Skip to content

Commit

Permalink
V2 Update
Browse files Browse the repository at this point in the history
* Moved presets to src/configs.h
* Created common.h
* Added color palettes
* Fixed with up/down scrolling in menus ( wrapping around from the top would not work properly )
* Changed force refresh rate to every 128 frames ( previously 16 )
* Fixed custom config default fill rate to 50% ( previously 30% )
* Modified README.md
* Changed optimization level to 2 (previously size)
  • Loading branch information
ChickChicky committed May 5, 2024
1 parent d0ff451 commit b48376d
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 122 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ src = $(addprefix src/,\

CFLAGS = -std=c99
CFLAGS += $(shell $(NWLINK) eadk-cflags)
CFLAGS += -Os -Wall
CFLAGS += -O2 -Wall
CFLAGS += -ggdb
LDFLAGS = -Wl,--relocatable
LDFLAGS += -nostartfiles
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Just a small little project that adds a Game Of Life application to a Numworks c
This is to ensure that the project builds in the first place, and then to get the binary.
###### *([taken from here](https://github.com/numworks/epsilon-sample-app-c/?tab=readme-ov-file#build-the-app))*

To build this sample app, you will need to install the [embedded ARM toolchain](https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain) and [Node.js](https://nodejs.org/en/). The C SDK for Epsilon apps is shipped as an npm module called [nwlink](https://www.npmjs.com/package/nwlink) that will automatically be installed at compile time.
To build this app, you will need to install the [embedded ARM toolchain](https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain) and [Node.js](https://nodejs.org/en/). The C SDK for Epsilon apps is shipped as an npm module called [nwlink](https://www.npmjs.com/package/nwlink) that will automatically be installed at compile time.

```shell
brew install numworks/tap/arm-none-eabi-gcc node # Or equivalent on your OS
Expand All @@ -23,4 +23,8 @@ You should now have a `output/app.nwa` file that you can distribute! Anyone can
```shell
# Now connect your NumWorks calculator to your computer using the USB cable
make run
```
```

## License

This sample app is distributed under the terms of the BSD License. See LICENSE for details.
12 changes: 12 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef COMMON_H
#define COMMON_H

#include <eadk.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// Modulus so that (-1)%7 = 5
#define MOD(a,b) ((((a)%(b))+(b))%(b))

#endif
75 changes: 75 additions & 0 deletions src/configs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#ifndef CONFIGS_H
#define CONFIGS_H

#include "common.h"
#include "palettes.h"

typedef struct config {
float F; // How much should the grid be filled when initializing
uint16_t B; // Birth rule
uint16_t S; // Survival rule
uint8_t s; // (WIP) State count
const char* name; // The name of the rule / configuration
pal_t* palette; // The color palette of the rule
} config_t;

static const char* const menu_custom_name = "[Custom]";
static const char* const menu_config_name = "[Configure]";

#define NCONFIGS ((sizeof(configs)/sizeof(config_t))-1)

config_t configs[] = { // All of the preset configurations
{ .F = .50f,
.B = 0b000001000,
.S = 0b000001100,
.s = 2,
.name = menu_custom_name,
.palette = &pal_custom,
},
{ .name = menu_config_name, },
{ .F = .50f,
.B = 0b000001000,
.S = 0b000001100,
.s = 2,
.name = "GOL",
.palette = &pal_default,
},
{ .F = .75f,
.B = 0b000001000,
.S = 0b000111110,
.s = 2,
.name = "Maze",
.palette = &pal_default,
},
{ .F = .75f,
.B = 0b110001000,
.S = 0b111101100,
.s = 2,
.name = "Coagulation",
.palette = &pal_default,
},
{ .F = .50f,
.B = 0b010001000,
.S = 0b100111000,
.s = 3,
.name = "Cool",
.palette = &pal_cool,
},
{ .F = .10f,
.B = 0b000000100,
.S = 0b000010100,
.s = 8,
.name = "Crystal",
.palette = &pal_crystal,
},
{ .F = .10f,
.B = 0b000101010,
.S = 0b110111100,
.s = 2,
.name = "Land Rush",
.palette = &pal_default,
},
{ 0 }
};

#endif
147 changes: 28 additions & 119 deletions src/main.c
Original file line number Diff line number Diff line change
@@ -1,122 +1,13 @@
#include <eadk.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "common.h"
#include "configs.h"
#include "palettes.h"

const char eadk_app_name[] __attribute__((section(".rodata.eadk_app_name"))) = "GOL+";
const uint32_t eadk_api_level __attribute__((section(".rodata.eadk_api_level"))) = 0;

typedef struct config {
float F; // How much should the grid be filled when initializing
uint16_t B; // Birth rule
uint16_t S; // Survival rule
uint8_t s; // (WIP) State count
const char* name; // The name of the rule / configuration
} config_t;

static const char* const menu_custom_name = "[Custom]";
static const char* const menu_config_name = "[Configure]";

config_t configs[] = { // All of the preset configurations
{ .F = .30f,
.B = 0b000001000,
.S = 0b000001100,
.s = 2,
.name = menu_custom_name,
},
{
.name = menu_config_name,
},
{ .F = .50f,
.B = 0b000001000,
.S = 0b000001100,
.s = 2,
.name = "GOL",
},
{ .F = .75f,
.B = 0b000001000,
.S = 0b000111110,
.s = 2,
.name = "Maze",
},
{ .F = .75f,
.B = 0b110001000,
.S = 0b111101100,
.s = 2,
.name = "Coagulation",
},
{ .F = .50f,
.B = 0b010001000,
.S = 0b100111000,
.s = 3,
.name = "Cool",
},
{ .F = .10f,
.B = 0b000000100,
.S = 0b000010100,
.s = 8,
.name = "Crystal",
},
{ 0 }
};

eadk_color_t palette[] = {
0x0000,
0x0841,
0x1082,
0x18c3,
0x2104,
0x2945,
0x3186,
0x39c7,
0x4208,
0x4a49,
0x528a,
0x5acb,
0x630c,
0x6b4d,
0x738e,
0x7bcf,
0x8410,
0x8c51,
0x9492,
0x9cd3,
0xa514,
0xad55,
0xb596,
0xbdd7,
0xc618,
0xce59,
0xd69a,
0xdedb,
0xe71c,
0xef5d,
0xf79e,
0xffff,
};

static inline eadk_color_t palette_get(uint8_t s, uint8_t t) {
return palette[((uint32_t)t)*(sizeof(palette)/sizeof(eadk_color_t)-1)/(((uint32_t)s)-1ull)];
}

#define NCONFIGS ((sizeof(configs)/sizeof(config_t))-1)

// Waits for the specified key to be released (eadk_key_*)
#define WAIT_RELEASE(k){while((eadk_keyboard_key_down(eadk_keyboard_scan(),k)))eadk_timing_msleep(10);}

// Modulus so that (-1)%7 = 5
#define MOD(a,b) ((((a)%(b))+(b))%(b))

static inline float clampf(float v, float n, float m) {
v = (v<n)?n:v;
return (v>m)?m:v;
}

static inline int clampi(int v, int n, int m) {
v = (v<n)?n:v;
return (v>m)?m:v;
}

#define FLAG_PAUSED 0b00000000000000000000000000000001
#define FLAG_STEP 0b00000000000000000000000000000010

Expand All @@ -128,6 +19,8 @@ static inline int clampi(int v, int n, int m) {
// The amount of time between scrolls while holding keys
#define HOLD_PAUSE 150

pal_t* palette;

uint8_t board[240*240] = {0}; // Board
uint8_t bboard[240*240] = {0}; // Backboard

Expand Down Expand Up @@ -155,7 +48,22 @@ uint32_t w;
uint32_t h;
uint32_t sz;

char tmp[16] = {0};
char tmp[64] = {0};

static inline float clampf(float v, float n, float m) {
v = (v<n)?n:v;
return (v>m)?m:v;
}

static inline int clampi(int v, int n, int m) {
v = (v<n)?n:v;
return (v>m)?m:v;
}

static inline eadk_color_t palette_get(uint8_t s, uint8_t t) {
if (!palette) return 0xF81F | (((uint32_t)s)*31/255);
return palette->colors[((uint32_t)t)*(palette->size-1)/(((uint32_t)s)-1ull)];
}

static inline void init_menu(bool first) { state = STATE_MENU;
if (!first) return;
Expand All @@ -171,6 +79,7 @@ static inline void init_sim(bool first) { state = STATE_SIM;
S = conf.S;
s = conf.s;
F = conf.F;
palette = conf.palette;
const uint32_t fillrate = UINT32_MAX*F;
for (size_t i = 0; i < sz; i++)
board[i] = (eadk_random() < fillrate)*(eadk_random()%s);
Expand Down Expand Up @@ -214,7 +123,7 @@ int main(int argc, char* argv[]) {
if (state == STATE_MENU) {
if (eadk_keyboard_key_down(kbd,eadk_key_up)) {
if (t-lt > HOLD_PAUSE) {
selected = MOD(selected-1,NCONFIGS);
selected = MOD(((int16_t)selected)-1,NCONFIGS);
lt = t;
}
}
Expand Down Expand Up @@ -256,7 +165,7 @@ int main(int argc, char* argv[]) {
else if (state == STATE_CUSTOM) {
if (eadk_keyboard_key_down(kbd,eadk_key_up)) {
if (t-lt > HOLD_PAUSE) {
ctm_locr = MOD(ctm_locr-1,5);
ctm_locr = MOD(((int16_t)ctm_locr)-1,5);
lt = t;
}
}
Expand All @@ -271,7 +180,7 @@ int main(int argc, char* argv[]) {
if (ctm_locr == 0 || ctm_locr == 1) {
ctm_locc = MOD(ctm_locc-1,9);
} else if (ctm_locr == 2) {
configs[selected].s = clampi(configs[selected].s-1,2,sizeof(palette)/sizeof(eadk_color_t));
configs[selected].s = clampi(configs[selected].s-1,2,pal_custom.size-1);
} else if (ctm_locr == 3) {
configs[selected].F = ((float)((int)(clampf(configs[selected].F-.1f,0.f,1.f)*100.f)))/100.f;
} else if (ctm_locr == 4) {
Expand All @@ -285,7 +194,7 @@ int main(int argc, char* argv[]) {
if (ctm_locr == 0 || ctm_locr == 1) {
ctm_locc = MOD(ctm_locc+1,9);
} else if (ctm_locr == 2) {
configs[selected].s = clampi(configs[selected].s+1,2,sizeof(palette)/sizeof(eadk_color_t));
configs[selected].s = clampi(configs[selected].s+1,2,pal_custom.size-1);
} else if (ctm_locr == 3) {
configs[selected].F = ((float)((int)(clampf(configs[selected].F+.1f,0.f,1.f)*100.f)))/100.f;
} else if (ctm_locr == 4) {
Expand Down Expand Up @@ -351,7 +260,7 @@ int main(int argc, char* argv[]) {
else if (state == STATE_CONFIG) {
if (eadk_keyboard_key_down(kbd,eadk_key_up)) {
if (t-lt > HOLD_PAUSE) {
cfg_locr = MOD(cfg_locr-1,2);
cfg_locr = MOD(((int16_t)cfg_locr)-1,2);
lt = t;
}
}
Expand Down Expand Up @@ -457,7 +366,7 @@ int main(int argc, char* argv[]) {
bboard[i] = v = k ? (s-1) : (u==0 ? 0 : s-2);
}

if (!(frame%16) || u != v)
if (!(frame%128) || u != v) // Full screen refresh every 128 frames
eadk_display_push_rect_uniform((eadk_rect_t){x,y,1,1},palette_get(s,v));
}
}
Expand Down
Loading

0 comments on commit b48376d

Please sign in to comment.