Changing palettes

Hello!
In my program I need to draw an image, which is only 128x128, to the screen often but I also need to occasionally change the palette. For example, I may need to make all of the white pixels black. I’m not sure how to do this though. I do not understand meshes, would I need a vertex for each pixel? Any help is greatly appreciated!

@SaladFingers If that’s an image you’re creating by assigning colors before you draw, the you can assign colors to a variable. For instance you can say White=color(255,255,255). Then when you want to change to black you can assign White=color(0,0,0). I’d need to see some of your code to better understand how you’re drawing your image.

@dave1707 I forgot to mention that I manipulate the image frequently by using setContext(), and I draw the image to the screen using sprite()
Edit: I see what you are saying but I would not be able to to that because the image that I am drawing to the screen, has sprites drawn to it. My only idea of how to do this would be to iterate over all the pixels in the image and change the colors that way but it would be slow

@SaladFingers - sounds like you are drawing a background and then superimposing sprites. Do you need to change the colours of the background or sprites?

If it’s sprites a shader is the best way. If it’s the background an array of palettes would do the job.

In the bad old days, on a defunct computer (a BBC micro) a simple VDU command would have cycled sprite colours very easily.

@Bri_G Yes, essentially I have a screen buffer that is an image, and I use various built-in functions to draw to it: rect, sprite, line, etc… and I need to change the colors of all the pixels in the screen buffer image. I hope that makes sense. I draw the buffer using the sprite function. And I am not sure I understand your question about the backgrounds.
Thanks so much for your help!

@SaladFingers I’m still not sure of everything you’re trying to do but here’s an example where I draw a 128x128 background and then draw a rect, ellipse, line, and a sprite. Then each time I tap the screen I alter the color. What do you need to do differently.

displayMode(FULLSCREEN)

function setup()
    img=image(128,128)
    setContext(img)
    background(0, 255, 0, 255)
    fill(255,0,0)
    rect(50,50,20,20)
    fill(0,0,255)
    ellipse(100,100,40,40)
    stroke(255)
    strokeWidth(5)
    line(0,0,128,128)
    sprite("Planet Cute:Character Princess Girl",50,100,50)
    setContext()
end

function draw()
    background(0)
    sprite(img,WIDTH/2,HEIGHT/2)   
    fill(255)
    text("tap screen to alter color",WIDTH/2,HEIGHT-100)
end

function touched(t)
    if t.state==BEGAN then
        for x=1,128 do
            for y=1,128 do
                r,g,b,a=img:get(x,y)
                r,b=b,r
                g,r=r,g
                img:set(x,y,r,g,b,a)
            end
        end
    end
end

@SaladFingers - all the pixels probably needs a shader. If it’s an effect like flashing explosion you could consider layering the background and coupling cycling images with transparency values you could fade one out and fade one in. Do it other multiple backgrounds could be quite effective.

In a similar way you could cycle round different coloured sprites in the foreground (just as you do with animations).

@dave1707 Although this accomplishes what I need, it would be incredibly slow and not practical.

To give more context (which I should have done to start with), is I am trying to reimplement PICO-8 in Codea. Most problematically, so far, is the PAL() function which modifies palettes. So I have a ‘screen’ variable, which is a 128x128 image that uses RGB for color. PICO-8 has 16 colors in its palette, which accepts as an index to the RGB representation of that color. But in PICO-8, you can change the color that is shown for a specific index. For example, the 7th color is white and the 1st color is black, by calling PAL(1,0), any color on the screen that has the index of 1 (black), becomes displayed as index 0 (white). So all black pixels become white. Hope I explained that well…

@SaladFingers Here’s something that might be close to what you’re after, I think. Slide the from and to parameters then tap PAL to switch colors. Press reset to get back to the original image. This only has 8 colors, but that can be expanded to as many as you want.

displayMode(STANDARD)

function setup()
    tabs1()
    parameter.integer("fromCol",1,8,1)
    parameter.integer("toCol",1,8,1)
    parameter.action("PAL",pal)
    parameter.action("reset",reset)
    create()
end

function draw()
    background(0)
    sprite(img,WIDTH/2,HEIGHT/2)  
    stroke(255)
    strokeWidth(2)
    for z=1,8 do
        fill(tab1[z])
        rect(z*60,HEIGHT-100,50,50)
    end
    fill(255)
    text("from",fromCol*60+25,HEIGHT-120)
    text("to",toCol*60+25,HEIGHT-140)
    
    text(string.format("PAL(%d,%d)",fromCol,toCol),WIDTH/2,HEIGHT-180)
end

function pal()
    for z=1,#col do
        if col[z]==fromCol then
            col[z]=toCol
        end
    end
    tabs2()
    create() 
end

function reset()
    tabs1()
    create()
end

function tabs1()
    tab1={  color(0,0,0),
            color(0,0,255),
            color(0,255,0),
            color(0,255,255),
            color(255,0,0),
            color(255,0,255),
            color(255,255,0),
            color(255,255,255)
        }
    col={1,2,3,4,5,6,7,8}
    tabs2()
end

function tabs2()
    black=tab1[col[1]]
    blue=tab1[col[2]]
    green=tab1[col[3]]
    cyan=tab1[col[4]]
    red=tab1[col[5]]
    magenta=tab1[col[6]] 
    yellow=tab1[col[7]] 
    white=tab1[col[8]]
end

function create()
    noStroke()    
    
    img=image(128,128)    
    setContext(img)

    background(green)   
     
    fill(red)
    rect(20,60,20,60)   
     
    fill(blue)
    ellipse(100,50,40,40)   
     
    stroke(magenta)
    strokeWidth(5)
    line(0,0,128,128) 
       
    setContext()
end

@SaladFingers - that’s precisely what one of the bbc micros VDU commands did. Could you post an image as an example of what you are trying to colour cycle.

I’m not hot on shaders but in principle you could build up a palette, pass it to the shader which could cycle through the palette exchanging pixel colours. It was used in lots of demos with moving text and line/colour scrolling often with sine waves for effect

@dave1707 That would work, and is currently what I’m doing, but the issue is that I would be also drawing images onto “img” and those sprites would need their colors changed too.

@Bri_G The first is what it currently looks like and the second is what it should look like. The difference is the colors underneath the “hello world.” The white colors are modified. Here is the PICO-8 program:

function _update()

 t+=1

end



function _draw()

 cls()
 i,j0 = 0,0
  

 for i=1,11 do

  for j0=0,7 do

  j = 7-j0

  col = 7+j

  t1 = t + i*4 - j*2

  x = cos(t0)*5

  y = 38 + j + cos(t1/50)*5

  pal(7,col)

  spr(16+i, 8+i*8 + x, y)

  end

 end

 

  print("this is pico-8",

    37, 70, 14) --8+(t/4)%8)



 print("nice to meet you",

    34, 80, 12) --8+(t/4)%8)



  spr(1, 64-4, 90)

end

@SaladFingers I’m totally confused about what you’re trying to do. At the start you said you want to draw something on a 128x128 image and to be able to change a color on the image. Then above you show 2 images and the second image is quite different than the first. You’re not just altering a color, but you’re adding a lot of other things. So if you’re doing that, then just alter the colors before redrawing on the 2nd image. If you want a color palette, then you can put a bunch of colors in a table and refer to them by number.

displayMode(FULLSCREEN)

function setup()
    str="Hello World "
    col={   color(0,0,0),
            color(0,0,255),
            color(0,255,0),
            color(0,255,255),
            color(255,0,0),
            color(255,0,255),
            color(255,255,0),
            color(255,255,255) }
    create()   
end

function draw()
    background(0, 0, 0, 255)
    sprite(img,WIDTH/2,HEIGHT/2)
end

function create()
    img=image(WIDTH,HEIGHT)
    setContext(img)
    background(0)
    fontSize(140)    
    c=1
    for a=-3,3 do
        c=c+1
        for i=1,#str do
            x=i*70
            v=string.sub(str,i,i)
            y=math.sin(math.rad(i*180/#str))*60*a+HEIGHT/1.8
            fill(col[c])
            text(v,x,y)
        end
    end
    fontSize(40)
    fill(col[2])
    text("this is pico-8",WIDTH/2,HEIGHT/4)
    fill(col[4])
    text("nice to meet you",WIDTH/2,HEIGHT/5)
    sprite("Planet Cute:Heart",WIDTH/2,HEIGHT/7,50)
    setContext()
end

@SaladFingers, @dave1707 - first stab at getting you intro sorted. Only thing I am missing is getting each layer ‘Hello World’ to be offset vertically with the sine wave. Also seems to stick occasionally. Maybe one of you could add the offset scrolling?


-- Pico-8-01
-- Bri_G first attempt

displayMode(OVERLAY)
function setup()
--
    cX,cY = WIDTH/2,HEIGHT/2
    hello = "HELLO WORLD"
    font("Copperplate-Bold")
    fontSize(64)
    textMode(LEFT)
    offset,y,pt = 0,0,1
    txt = {}
    piV = 2*math.pi/11
    for lp = 1,11 do
        txt[lp] = string.sub(hello,lp,lp)
    end
end

function draw()
--
    background(4, 4, 4, 255)
    for layer = 1,7 do
        for x = 1,11 do
            posx = x*56
          --  for y = 1,11 do      
            fill(colrs[layer])
            pos =  math.sin(os.clock())
            posy = cY + pos*piV/(0.02)*y+offset
            text(txt[x],posx,posy)
            offset = 32
        end
        y = y+1
        if y > 7 then y = 1 end
    end
end

colrs = {
        color(228, 210, 204, 255),
        color(216, 133, 216, 255),
        color(148, 223, 215, 255),
        color(143, 223, 149, 255),
        color(235, 234, 67, 255),
        color(250, 151, 11, 255),
        color(241, 44, 62, 255),
}

P.s. - thought the use of text letters would be easier than sprites - adding an eightH colour created havoc!!

@Bri_G @SaladFingers See my example above.

@dave1707 - very neat, I just thought it was an animated intro screen with more involved images(sprites). I tried to text and it worked but I became a little frustrated with trying to offset several scrolling strings - produced some interesting effects but not like those @SaladFingers was trying to imitate.

@Bri_G I’m not sure what it’s supposed to be. As I mentioned in my post above I don’t know what he wants to accomplish. I was just going by what he showed in the 2 images.

@dave1707 - same here, just looks like some of the early PC games with simple scrolling text. See what feedback comes back.

@Bri_G @dave1707
I sincerely apologize for my lack of clarity. The idea of my project is to take a PICO-8 program and alter it to the point that it will run in Codea. PICO-8 is a fantasy console that uses Lua and has many other features such as built in graphics and sound. The program I attached was a PICO-8 demo program. It does not run natively in Codea. Functions like “cls,” “pal,” and “spr” have been rewritten by me to allow the code to run. The problem I am experiencing is with PICO-8’s ability to change palette colors. Codea uses a standard RGBA format for all image types. In PICO-8, I can have the color index 4 show up as white or as green or blue: it can be whatever color. In Codea, color(255,255,255,255) is always white. @dave1707 you suggested using tables which would work except for PICO-8’s “spr” function which draws a sprite to the screen. It would be very slow to copy each pixel one by one to my screen buffer rather than using Codea’s sprite function which copies all the pixels at once but doesn’t allow me to modify what those pixels look like.

I hope I’ve explained this better, and I really appreciate your guys’ help!

@SaladFingers Thanks, that explains a lot. You can change the sprite color somewhat by using the tint command. Or you can create your own simple sprites and redraw them changing the color. It’s always hard to take a program from one system and convert it to another.