Log In  
[ :: Read More :: ]

Cart #57882 | 2018-10-13 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Working on a 3d engine to try to make a space game... This is the current iteration

P#57883 2018-10-12 21:53 ( Edited 2018-10-13 02:58)

[ :: Read More :: ]

Cart #57806 | 2018-10-10 | Code ▽ | Embed ▽ | No License

P#57807 2018-10-10 17:09 ( Edited 2018-10-10 21:09)

[ :: Read More :: ]

I was experimenting with generating three-color pattern dither (2x2 matricies), and this is what I came up with. It's obviously too slow to use without building a dithering table (you could fit 4:5:4 color in the cartridge ram with cstore/restore), but I wanted to throw this out in the world incase someone else wanted to play with it.

Cart #18124 | 2016-01-03 | Code ▽ | Embed ▽ | No License

P#18125 2016-01-02 23:24 ( Edited 2016-01-03 04:24)

[ :: Read More :: ]

I started translating a lot of the CV2 soundtrack to the Pico-8. This is one of the finished ones that I think turned out nice.

P#18034 2015-12-24 20:55 ( Edited 2015-12-25 01:55)

[ :: Read More :: ]

The more lua code I write in the pico-8, the more general purpose functions I wind up discovering. Here is my current utility library, I'll probably continue adding more as time progresses.

Quick sort

This one is pretty straight forward, you simply call it by providing a table and an optional comparator (for non-numeric lists), and it will in-place sort your table. It currently does not return anything, but it could me modified to return the table passed if you want to chain things.

-- Inplace quick sort
function qsort(tbl, cmp, first, last)
    first = first or 1
    last = last or #tbl
    cmp = cmp or function (x,y) return x - y end

    if (first >= last) then

    local pivot, pv, tail = first, tbl[pivot], last

    while pivot < tail do
        local tv = tbl[tail]

        -- Tail is smaller than the pivot
        -- Shuffle things around
        if ( cmp(pv, tv) > 0 ) then
            tbl[pivot], pivot = tv, pivot + 1
            tbl[tail] = tbl[pivot]

        tail = tail - 1

    tbl[pivot] = pv

    qsort(tbl, cmp, first, pivot - 1)
    qsort(tbl, cmp, pivot + 1, last)

Unpack is a useful function for converting a table into an argument list (similar to kargs in python), or assign a bunch of locals quickly:

IE: local x, y, z = unpack(vector) or print(join(",", unpack(numbers)))

-- Unpack table into spread values
function unpack(y, i)
    i = i or 1
    local g = y[i]
    if (g) return g, unpack(y, i + 1)

Enum does what you would expect, it's basically ipairs with an optional filter (in case you want to unpack the values, for example)

-- Enumerate and potentially filter a table
function enum(t, filter)
    local i = 0
    filter = filter or function (v) return v end
    return function()
        local o = t[i]
        i += 1
        if (o) return i, filter(o)

Join is my function for concatinating a list of arguments with a seperator. It's useful for displaying things like vectors.

-- Join arguments by a seperator
function join(a, b, ...)
    x = {...}

    for i = 1,#x do
        b = b .. a .. x[i]

    return b
P#17606 2015-12-08 15:05 ( Edited 2015-12-08 20:05)

[ :: Read More :: ]

So, one of my favorite effects from the olden days was the ability to do glinting / pseudo transparency. Sadly, there is no way to do this in the PICO-8 due to cycle timing and memory issues. I would love to see the PAL call replaced with something that accepts three colors rather than two.

something like: tpal c0 c1 c2, which would take all instances where c0 is drawn over c1 with c2. It would take 128 bytes of memory, but there is still plenty of headroom inside of the draw state structure to accommodate this.

P#13941 2015-09-09 17:33 ( Edited 2015-09-09 22:02)

[ :: Read More :: ]

I don't know if anyone else has done a write up on this, but there is actually a pretty solid way to get around most of the data limits on the system, and it's kinda gross, and doesn't with the webplayer. The nice thing is that it gives you a legit file system, and basically limitless binary data!

Here is a proof of concept, I created two files (this one is test.pb)

RELOAD (0x6000, 0x4300, 128)
RELOAD (0x6100, 0x4300, 128)


Test 2 contains nothing but garbage code that would crash the machine.

The rational behind this is that:
1) If LOAD trashes execution, it would crash when the new program runs
2) If LOAD aborts the current thread, it would simply return to the prompt with TEST2 loaded
3) If LOAD doesn't allow shared state, it would copy the same thing out of the code area of the cartridge

This test proves 3 things...

1) RUN performs LUA compilation, so LOADing garbage data doesn't harm execution state
2) The existing machine state is preserved after a LOAD call, while altering the loaded filename and data stored with in the cartridge
3) Storage space is essentially limitless.

Basic rundown of what happens with LOAD / RUN

LOAD: Sets the active filename for the cartridge, loads the 32k cartridge into the cartridge buffer, and loads the first 0x4300 bytes into memory (tiles, maps, sounds and patterns)
RUN: Disposes of existing Lua runtime state, discarding any global values, functions, etc, then parses and executes the code stored in the cartridge buffer.

This also means that whatever is in ram at 0x4300~0x7FFF is PRESERVED BETWEEN RUNS. The only downside here is that LOAD will print garbage to the screen, so write to this area after you LOAD, but before you RUN the LOADed cartridge.

So, if you want to get past the data storage limits, use a LOAD without running first.

If you want to get past the CODE limits, store persistent data at 0x4300~0x7FFF and then RUN.

P#13625 2015-09-03 14:14 ( Edited 2015-09-04 08:00)

[ :: Read More :: ]

So, I've been spending quite a bit of time these last few days trying to figure out the innerworkings of the PICO-8, especially the cartridge storage and I've basically got everything figured out at this point. One thing I thought might be helpful is letting everyone get a glimpse into the compression format that is used inside of the .PNG format, so you can avoid hitting that pesky 32kB code wall!

So, first I will start by breaking down the storage format for the current version of the .PNG. Note so far this has been a clean room RE, so if I'm duplicating anything that you already know, or has been described for you, just ignore me and move on.

Cartridge data is stored in the 2 lowest bits of a color channel, so each color is 8-bits worth of data (1 byte). The channels are ordered (MSB to LSB) ARGB (this is not raw uint8 data order from the image container, so keep that in mind). The images are 160*205, giving you a theoretical size of 32800, although only 32769 bytes are used, Everything past this is discarded.

0x0000~0x42FF:  Ram initalizer (simply copied to RAM on load, see manual memory map for details)
0x4300~0x7FFF:  Code (version 0 is ASCII encoded, version 1 is 
0x8000:       File version

This is all fairly straight forward and should not surprise anyone. If the version is 1, it means the code is likely compressed and will follow the following format:

0x0~0x3: the string ":c:\x00"
0x4~0x5: length of code (decomressed, big-endian)
0x6~0x7: always zero (could be used for compression scheme in the future?)
0x8+:    Compressed data

Compressed data is an LZ like format, supporting a minimized character set so some text takes less space. It takes 8-bit codes to generate a chain of characters, this loops until the output data matches the value located in the header.

The codes are as follows

0x00 xx: "Extended" code.  The following byte is copied to the output stream
0x01: Emit a new line
0x02~0x3B: Maps to: " 0123456789abcdefghijklmnopqrstuvwxyz!#%(){}[]<>+=/*:;.,~_"
0x3C~0xFF xx: Copy from buffer

The 'copy' call copies N bytes from -X bytes from the end of the current stream.

offset = (code - 0x3C) * 16 + (code2 & 0xF);
length = (code2 >> 4) + 2;

For a working example, this is what "Hello hello" would be encoded as.

// Header
"3a", "63", "3a", "0", "0", "b", "0", "0", 
// Encoded text
"0", "48",  // "H"
"11", "18",  "18",  "1b", // "ello"
"2", // [space]
"14", // "h"
"3c", "26" // "ello", 4 bytes copied from 6 bytes ago

Note: There are no capital letters in the short form encoding, so don't ever use them in your program. Also the maximum number of characters that can be copied from a previous point in the stream is 17 characters, so try to keep your variable names below this threshold. Interestingly enough, minus signs are also not supported by the base character set.

P#13539 2015-09-01 23:48 ( Edited 2016-10-19 05:37)

Follow Lexaloffle:          
Generated 2024-04-21 04:50:03 | 0.084s | Q:21