o
odin.langpkg.dev
packages / library / cm_if_fast

cm_if_fast

f7fedf5library

A small recreation of Cell Machine used to test out optimizations. These optimizations may be replicated in TSC.

MIT · updated 2 weeks ago

Cell Machine if it was fast

This remake is quite fast

This initially started as an experiment to both learn Odin and see how fast I could make a CM engine if modding was never a priority. This is about an order of magnitude faster than TSC Turbo, which is TSC with all of the modding compiled out. This is due to some minor implementation details in TSC that are not properly compiled out.

The things I've learned from this project will eventually be put into TSC Turbo as well.

Controls

You can move around with the standard WASD controls and zoom with the scroll wheel (it zooms from where your cursor is).

Currently, you cannot place cells. You can load a level by pressing L, but you can't reset to the initial state. You can press the spacebar to run or pause the simulation, press F to tick it once, or hold down G to tick it every frame while you're pressing it. The simulation always runs at maximum speed.

You can press T to switch between single-threaded and multi-threaded mode. Multi-threaded isn't always better, especially for small grids, so make sure to try either one.

This remake is not intended to be used for anything more than simply running stuff super fast, for timelapsing or other reasons.

Compiling

The engine is pure Odin, so you can compile it with odin build cmfast -build-mode:shared to get a shared library.

For the remake, it depends on raylib. Install raylib, then run odin build ..

The C API

The C API of the engine is entirely defined in cmfast.h. As a basic example of a basic simulation checking the cell at the top-left corner after 100 ticks:

#include "cmfast.h"

// info this example needs
const char *level = "V3;...";

const char *namesLUT[CMF_CELLCOUNT] = {...}; // LUT mapping the values of cmf_CellType to string names
const char *dirs[CMF_DIRCOUNT] = {...}; // LUT mapping the values of cmf_Direction to string names

// actual usage of API
int main() {
    // create a pre-defined grid
    cmf_Grid *g = cmf_createGrid(1, 1);

    cmf_LoadResult res = cmf_load(g, level);
    if(res != CMF_LOADED) {
        return res;
    }

    for(int i = 0; i < 100; i++) cmf_tick(g);

    cmf_Cell c = cmf_getCell(g, 0, 0);
    cmf_destroyGrid(g); // the grid is not needed anymore, the cells are 8-bit independent values.

    cmf_CellType type = cmf_getCellType(c);
    cmf_Direction direction = cmf_getCellDirection(c);

    printf("ID: %s, DIR: %s\n", names[type], dirs[direction]);
    return 0;
}

An example of using multi-threaded ticking:

// in the setup
// 0 means use one thread for each logical core available. If a number other than 0 is used, it will try to use that amount of threads.
cmf_ThreadedDispatcher *dispatcher = cmf_createThreadpool(0);

// in the update code
cmf_threadedTick(grid, dispatcher);

// cleanup
cmf_destroyThreadpool(dispatcher);