Dave1707 from the Codea forum shows a much better approach to converting the bitmaps.

Yesterday on the Codea forum, Dave1707 posted this code:

displayMode(STANDARD)

function setup()
    parameter.integer("sc",1,15,5)

    hex1={0x00,0x00,0x39,0x79,0x7A,0x6E,0xEC,0xFA,0xFA,0xEC,0x6E,0x7A,0x79,0x39}
    hex2={0x00,0x00,0x00,0x78,0x1D,0xBE,0x6C,0x3C,0x3C,0x3C,0x6C,0xBE,0x1D,0x78}
    hex3={0x00,0x00,0x00,0x00,0x19,0x3A,0x6D,0xFA,0xFA,0x6D,0x3A,0x19,0x00,0x00}
    hex4={0x00,0x0F,0x1F,0x1F,0x1F,0x1F,0x7F,0xFF,0x7F,0x1F,0x1F,0x1F,0x1F,0x0F}

    map1=image(16,8)
    map2=image(16,8)
    map3=image(16,8)
    map4=image(16,8)

    bitMap(hex1,map1)
    bitMap(hex2,map2)
    bitMap(hex3,map3)
    bitMap(hex4,map4)
end

function bitMap(hexString,img)
    for a=1,#hexString do
        for z=0,7 do
            if (hexString[a]>>z)&1==1 then
                img:set(a,z+1,255,255,255,255)
            end
        end 
    end   
end

function draw()
    background(0)
    noSmooth()
    fontSize(30)
    fill(255)
    text("Scale  "..sc,WIDTH/2,HEIGHT-100)
    scale(sc,sc)
    sprite(map1,WIDTH/2/sc,HEIGHT*.7/sc)
    sprite(map2,WIDTH/2/sc,HEIGHT*.5/sc)
    sprite(map3,WIDTH/2/sc,HEIGHT*.3/sc)
    sprite(map4,WIDTH/2/sc,HEIGHT*.1/sc)
end

The code displays this:

three invaders and a cannon

So there’s me told. Dave just converted the bytes in the Space Invaders source to bytes: I was going to pack them into words. My thinking, if there was any, was space efficiency, which is hardly laudable at the scale we have here, especially since we’ll almost certainly not include this code in the real program, instead saving all these images as sprite files. I’m pretty sure there must be a way to do that.

Dave just iterated over each supposed object byte, shifting the bits and putting them into an image. I’d have iterated over my words the same way. But I have 47 lines of tests for a three line function (counting “function” as one and “end” as another), and I was going to use that function today, while Dave has just gone ahead and converted the data.

It’s kind of the difference between writing a bash script to do something, and writing a Ruby program to do it. In many cases, including this one, the simple way is better. In my opinion, far better.

This morning I’ll build on this to bring in at least some of the remaining data, like the other invader pictures and we’ll see what else. Let’s do that now.

The Rest of the Invaders

The invaders each have two poses, which they alternate as they march. The source code provides this as the second form:

1C30: 00 00 38 7A 7F 6D EC FA FA EC 6D 7F 7A 38 00 00
1C40: 00 00 00 0E 18 BE 6D 3D 3C 3D 6D BE 18 0E 00 00
1C50: 00 00 00 00 1A 3D 68 FC FC 68 3D 1A 00 00 00 00

We’ll want that. Dave also brought in the healthy form of the player cannon thing, and it has two blowing up forms as well:

1C70: 00 04 01 13 03 07 B3 0F 2F 03 2F 49 04 03 00 01
1C80: 40 08 05 A3 0A 03 5B 0F 27 27 0B 4B 40 84 11 48

That’ll do for now. There are also sprites for the player’s shot, the shot exploding, and three animated invader shots. We’ll do those later.

My simple plan is to paste the lines above into Codea and covert them to legal hex tables. If there were more of them, I might regex them or doing them in a real editor, but this’ll be OK I think.

I’m inclined to give these better names before I go any further:

    inv1={0x00,0x00,0x39,0x79,0x7A,0x6E,0xEC,0xFA,0xFA,0xEC,0x6E,0x7A,0x79,0x39}
    inv2={0x00,0x00,0x00,0x78,0x1D,0xBE,0x6C,0x3C,0x3C,0x3C,0x6C,0xBE,0x1D,0x78}
    inv3={0x00,0x00,0x00,0x00,0x19,0x3A,0x6D,0xFA,0xFA,0x6D,0x3A,0x19,0x00,0x00}
    play={0x00,0x0F,0x1F,0x1F,0x1F,0x1F,0x7F,0xFF,0x7F,0x1F,0x1F,0x1F,0x1F,0x0F}
--[[
inv12: 00 00 38 7A 7F 6D EC FA FA EC 6D 7F 7A 38 00 00
inv22: 00 00 00 0E 18 BE 6D 3D 3C 3D 6D BE 18 0E 00 00
inv32: 00 00 00 00 1A 3D 68 FC FC 68 3D 1A 00 00 00 00

playx1: 00 04 01 13 03 07 B3 0F 2F 03 2F 49 04 03 00 01
playx2: 40 08 05 A3 0A 03 5B 0F 27 27 0B 4B 40 84 11 48
]]--

Even this may be overkill if I’m just going to export these sprites. But years of experience tells me that programs we plan to throw away have a tendency to be used again. Improving the names can’t hurt, takes little time, and might help. We’ll see.

A bit of editing gets me here:

    inv12={00 00 38 7A 7F 6D EC FA FA EC 6D 7F 7A 38 00 00}
    inv22={00 00 00 0E 18 BE 6D 3D 3C 3D 6D BE 18 0E 00 00}
    inv32={00 00 00 00 1A 3D 68 FC FC 68 3D 1A 00 00 00 00}

    playx1={00 04 01 13 03 07 B3 0F 2F 03 2F 49 04 03 00 01}
    playx2={40 08 05 A3 0A 03 5B 0F 27 27 0B 4B 40 84 11 48}

Darn it, I could do this in seconds in a real editor. Why don’t I have cross-machine copy/paste? Wait! I do!


inv12={0x00,0x00,0x38,0x7A,0x7F,0x6D,0xEC,0xFA,0xFA,0xEC,0x6D,0x7F,0x7A,0x38,0x00,0x00}
inv22={0x00,0x00,0x00,0x0E,0x18,0xBE,0x6D,0x3D,0x3C,0x3D,0x6D,0xBE,0x18,0x0E,0x00,0x00}
inv32={0x00,0x00,0x00,0x00,0x1A,0x3D,0x68,0xFC,0xFC,0x68,0x3D,0x1A,0x00,0x00,0x00,0x00}
playx1={0x00,0x04,0x01,0x13,0x03,0x07,0xB3,0x0F,0x2F,0x03,0x2F,0x49,0x04,0x03,0x00,0x01}
playx2={0x40,0x08,0x05,0xA3,0x0A,0x03,0x5B,0x0F,0x27,0x27,0x0B,0x4B,0x40,0x84,0x11,0x48}

Whee, I forgot I could do that! I’ll remember that next time I have a tedious edit to do. I cracked out that change in Sublime in 1/10 the time it would have taken in Codea.

Soon enough I have this program:

displayMode(STANDARD)

function setup()
    parameter.integer("sc",1,15,5)

    inv1={0x00,0x00,0x39,0x79,0x7A,0x6E,0xEC,0xFA,0xFA,0xEC,0x6E,0x7A,0x79,0x39}
    inv2={0x00,0x00,0x00,0x78,0x1D,0xBE,0x6C,0x3C,0x3C,0x3C,0x6C,0xBE,0x1D,0x78}
    inv3={0x00,0x00,0x00,0x00,0x19,0x3A,0x6D,0xFA,0xFA,0x6D,0x3A,0x19,0x00,0x00}
    play={0x00,0x0F,0x1F,0x1F,0x1F,0x1F,0x7F,0xFF,0x7F,0x1F,0x1F,0x1F,0x1F,0x0F}

    inv12={0x00,0x00,0x38,0x7A,0x7F,0x6D,0xEC,0xFA,0xFA,0xEC,0x6D,0x7F,0x7A,0x38,0x00,0x00}
    inv22={0x00,0x00,0x00,0x0E,0x18,0xBE,0x6D,0x3D,0x3C,0x3D,0x6D,0xBE,0x18,0x0E,0x00,0x00}
    inv32={0x00,0x00,0x00,0x00,0x1A,0x3D,0x68,0xFC,0xFC,0x68,0x3D,0x1A,0x00,0x00,0x00,0x00}
    playx1={0x00,0x04,0x01,0x13,0x03,0x07,0xB3,0x0F,0x2F,0x03,0x2F,0x49,0x04,0x03,0x00,0x01}
    playx2={0x40,0x08,0x05,0xA3,0x0A,0x03,0x5B,0x0F,0x27,0x27,0x0B,0x4B,0x40,0x84,0x11,0x48}

    inv1map=image(16,8)
    inv2map=image(16,8)
    inv3map=image(16,8)
    playmap=image(16,8)
    inv12map=image(16,8)
    inv22map=image(16,8)
    inv32map=image(16,8)
    playx1map=image(16,8)
    playx2map=image(16,8)

    bitMap(inv1,inv1map)
    bitMap(inv2,inv2map)
    bitMap(inv3,inv3map)
    bitMap(play,playmap)
    bitMap(inv12,inv12map)
    bitMap(inv22,inv22map)
    bitMap(inv32,inv32map)
    bitMap(playx1,playx1map)
    bitMap(playx2,playx2map)
end

function bitMap(hexString,img)
    for a=1,#hexString do
        for z=0,7 do
            if (hexString[a]>>z)&1==1 then
                img:set(a,z+1,255,255,255,255)
            end
        end 
    end   
end

function draw()
    background(0)
    noSmooth()
    fontSize(30)
    fill(255)
    text("Scale  "..sc,WIDTH/2,HEIGHT-100)
    scale(sc,sc)
    sprite(inv1map,WIDTH/2/sc,HEIGHT*.7/sc)
    sprite(inv12map, WIDTH/2/sc + 3*sc, HEIGHT*.7/sc)
    sprite(inv2map,WIDTH/2/sc,HEIGHT*.5/sc)
    sprite(inv22map, WIDTH/2/sc + 3*sc, HEIGHT*.5/sc)
    sprite(inv3map,WIDTH/2/sc,HEIGHT*.3/sc)
    sprite(inv32map, WIDTH/2/sc + 3*sc, HEIGHT*.3/sc)
    sprite(playmap,WIDTH/2/sc,HEIGHT*.1/sc)
    sprite(playx1map, WIDTH/2/sc + 3*sc, HEIGHT*.1/sc)
    sprite(playx2map, WIDTH/2/sc + 6*sc, HEIGHT*.1/sc)
end

Which displays this:

both versions of each invader plus player explosions

So that’s good, and a good time for a break. Next question will be how to get these guys exported.

Exporting My Images

I’ve not converted all the images I’ll need, but I’ve got a decent batch, and my next unsolved concern is how to export them. I’m hoping for something called saveImage to be in there.

I plan to save all the bitmap images in Codea’s “Dropbox” folder, which has little or nothing to do with the product of the same name, but is a common folder that all Codea projects can access. We’ll move the images into the actual product as soon as it makes sense. Right now we’re just saving them.

To save the first one, after a few tries at the syntax, this worked

    saveImage(asset.documents.Dropbox .. "inv11", inv1map)

The weird .. bit is there because Codea doesn’t know the name the first time through, so will not compile the more obvious form asset.documents.dropbox.inv11. No problem once you find the trick in the documents. And it is there.

dropbox first pic

Now I’ll save the rest of what we’ve got:

    saveImage(asset.documents.Dropbox .. "inv21", inv2map)
    saveImage(asset.documents.Dropbox .. "inv31", inv3map)
    saveImage(asset.documents.Dropbox .. "play", playmap)
    saveImage(asset.documents.Dropbox .. "inv12", inv12map)
    saveImage(asset.documents.Dropbox .. "inv22", inv22map)
    saveImage(asset.documents.Dropbox .. "inv32", inv32map)
    saveImage(asset.documents.Dropbox .. "playx1", playx1map)
    saveImage(asset.documents.Dropbox .. "playx2", playx2map)

And they’re all there:

dropbox all

They’re just very tiny and hard to see, but they’re there:

dropbox highlighted

It’s still quite early in the day, only 0936, but I think I’ll sum up here and take a break until later or even until tomorrow.

Summing Up

Pairing and feedback are good

Well first of all, it’s good to have a pair or at least feedback. No doubt my approach to these bitmaps would have worked, but it was very much over-engineered for the actual problem. I’m sure that had Dave been sitting with me, we could have skipped a lot of work.

That said, I did learn a bit about testing in Codea and so perhaps from a pedagogical viewpoint it was worth something. Frankly, though, Dave’s approach is better in my view. I do expect to be glad I’m changing the names a bit. We will be back to that program to convert some more objects, I’m sure.

Recognizing better is good

Were I not the learning-oriented easy-going delightfully charming and open individual that I am, I might easily have said “oh thanks dave” and moved on with what I was going. Because I am all those things, or at least play them here on the computer, I was able to recognize a better idea, accept it, and adopt it.

The lesson here is to hold on to our ideas loosely, so that when a new one comes along, we’ll be ready to latch on to it. That isn’t always easy when we’re trying to be the smartest person in the room. I am in fact the smartest person in the room right now, because the cat is out on the deck, but I’ve been fortunate enough to meet and work with people who could program me right into the ground, but have instead lifted me up by sharing what they knew.

I’m grateful for that and over the decades I fancy I’ve gotten a bit better at hearing better ideas.

Code management is good

I’m missing my ability to save code in Working Copy. It’s an excellent product and the author has already reproduced my problem and promises a fix in the next version. That will come along very soon, based on his history. I recommend that program highly, it changes one’s relationship with one’s code, because you can always get back to where you were.

Until that’s back, I’ll be treading a bit more carefully than I’d like to.

Bottom line

We’re on our way. We’ve got a handy little program for scarfing the bitmaps out of the ancient source code, and we know they’ll display. I’m sure we’re nearly done.

Well, we’re on our way, anyway. See you next time!


displayMode(STANDARD)

function setup()
    parameter.integer("sc",1,15,5)

    inv1={0x00,0x00,0x39,0x79,0x7A,0x6E,0xEC,0xFA,0xFA,0xEC,0x6E,0x7A,0x79,0x39}
    inv2={0x00,0x00,0x00,0x78,0x1D,0xBE,0x6C,0x3C,0x3C,0x3C,0x6C,0xBE,0x1D,0x78}
    inv3={0x00,0x00,0x00,0x00,0x19,0x3A,0x6D,0xFA,0xFA,0x6D,0x3A,0x19,0x00,0x00}
    play={0x00,0x0F,0x1F,0x1F,0x1F,0x1F,0x7F,0xFF,0x7F,0x1F,0x1F,0x1F,0x1F,0x0F}

    inv12={0x00,0x00,0x38,0x7A,0x7F,0x6D,0xEC,0xFA,0xFA,0xEC,0x6D,0x7F,0x7A,0x38,0x00,0x00}
    inv22={0x00,0x00,0x00,0x0E,0x18,0xBE,0x6D,0x3D,0x3C,0x3D,0x6D,0xBE,0x18,0x0E,0x00,0x00}
    inv32={0x00,0x00,0x00,0x00,0x1A,0x3D,0x68,0xFC,0xFC,0x68,0x3D,0x1A,0x00,0x00,0x00,0x00}
    playx1={0x00,0x04,0x01,0x13,0x03,0x07,0xB3,0x0F,0x2F,0x03,0x2F,0x49,0x04,0x03,0x00,0x01}
    playx2={0x40,0x08,0x05,0xA3,0x0A,0x03,0x5B,0x0F,0x27,0x27,0x0B,0x4B,0x40,0x84,0x11,0x48}

    inv1map=image(16,8)
    inv2map=image(16,8)
    inv3map=image(16,8)
    playmap=image(16,8)
    inv12map=image(16,8)
    inv22map=image(16,8)
    inv32map=image(16,8)
    playx1map=image(16,8)
    playx2map=image(16,8)

    bitMap(inv1,inv1map)
    bitMap(inv2,inv2map)
    bitMap(inv3,inv3map)
    bitMap(play,playmap)
    bitMap(inv12,inv12map)
    bitMap(inv22,inv22map)
    bitMap(inv32,inv32map)
    bitMap(playx1,playx1map)
    bitMap(playx2,playx2map)
    
    -- save the imagessprite(asset.documents.Dropbox.milkyway,20,20)
    
    saveImage(asset.documents.Dropbox .. "inv11", inv1map)
    saveImage(asset.documents.Dropbox .. "inv21", inv2map)
    saveImage(asset.documents.Dropbox .. "inv31", inv3map)
    saveImage(asset.documents.Dropbox .. "play", playmap)
    saveImage(asset.documents.Dropbox .. "inv12", inv12map)
    saveImage(asset.documents.Dropbox .. "inv22", inv22map)
    saveImage(asset.documents.Dropbox .. "inv32", inv32map)
    saveImage(asset.documents.Dropbox .. "playx1", playx1map)
    saveImage(asset.documents.Dropbox .. "playx2", playx2map)
end

function bitMap(hexString,img)
    for a=1,#hexString do
        for z=0,7 do
            if (hexString[a]>>z)&1==1 then
                img:set(a,z+1,255,255,255,255)
            end
        end 
    end   
end

function draw()
    background(0)
    noSmooth()
    fontSize(30)
    fill(255)
    text("Scale  "..sc,WIDTH/2,HEIGHT-100)
    scale(sc,sc)
    sprite(inv1map,WIDTH/2/sc,HEIGHT*.7/sc)
    sprite(inv12map, WIDTH/2/sc + 3*sc, HEIGHT*.7/sc)
    sprite(inv2map,WIDTH/2/sc,HEIGHT*.5/sc)
    sprite(inv22map, WIDTH/2/sc + 3*sc, HEIGHT*.5/sc)
    sprite(inv3map,WIDTH/2/sc,HEIGHT*.3/sc)
    sprite(inv32map, WIDTH/2/sc + 3*sc, HEIGHT*.3/sc)
    sprite(playmap,WIDTH/2/sc,HEIGHT*.1/sc)
    sprite(playx1map, WIDTH/2/sc + 3*sc, HEIGHT*.1/sc)
    sprite(playx2map, WIDTH/2/sc + 6*sc, HEIGHT*.1/sc)
end