diff --git a/device/device.c b/device/device.c index d3c3674..e87b8bc 100644 --- a/device/device.c +++ b/device/device.c @@ -1,5 +1,7 @@ #include #include "device.h" -uint32_t device_pixels[DEVICE_H][DEVICE_W]; +uint8_t device_pixels[DEVICE_H][DEVICE_W]; +uint32_t device_palette[256]; + bool device_buttons[DEVICE_BUTTON_N]; \ No newline at end of file diff --git a/device/device.h b/device/device.h index bf1cb85..c6a9389 100644 --- a/device/device.h +++ b/device/device.h @@ -22,7 +22,9 @@ typedef enum { DEVICE_BUTTON_N=8, } DeviceButton; -extern uint32_t device_pixels[DEVICE_H][DEVICE_W]; +extern uint8_t device_pixels[DEVICE_H][DEVICE_W]; +extern uint32_t device_palette[256]; + extern bool device_buttons[DEVICE_BUTTON_N]; #endif //CROCPARTY_DEVICE_H diff --git a/game/game.c b/game/game.c index 07c63eb..ad4c617 100644 --- a/game/game.c +++ b/game/game.c @@ -5,29 +5,42 @@ uint32_t game_frame; void game_init() { game_frame = 0; + + for (uint32_t x = 0; x < 8; x++) { + for (uint32_t y = 0; y < 8; y++) { + for (uint32_t z = 0; z < 4; z++) { + device_palette[ + (x << 5)|(y << 2)|(z) + ] = + ((x * 255)/7) << 24 | + ((y * 255)/7) << 16 | + ((z * 255)/3) << 8; + } + } + } } void game_update() { - game_frame += 1; + game_frame += 4; } void game_draw() { for (int x = 0; x < DEVICE_W; x++) { for (int y = 0; y < DEVICE_H; y++) { - uint32_t r = (x * 255)/DEVICE_W; - uint32_t g = (y * 255)/DEVICE_H; + uint32_t r = (x * 255)/(DEVICE_W - 1); + uint32_t g = (y * 255)/(DEVICE_H - 1); uint32_t b = game_frame & 0x100 ? 0xff - game_frame & 0xff : game_frame & 0xff; if (x % 4 == 2 && y % 4 == 2) { r = 255 - r; g = 255 - g; b = 255 - b; } - uint32_t color = r << 24 | g << 16 | b << 8; + uint8_t color = (r >> 5) << 5 | (g >> 5) << 2 | (b >> 6); device_pixels[y][x] = color; } } for (int i = 0; i < DEVICE_BUTTON_N; i++) { - device_pixels[0][i] = device_buttons[i] ? 0x000000ff : 0xffffffff; + device_pixels[0][i] = device_buttons[i] ? 0x00 : 0xff; } } diff --git a/sdl_host/main.c b/sdl_host/main.c index dc13113..2883ded 100644 --- a/sdl_host/main.c +++ b/sdl_host/main.c @@ -121,6 +121,7 @@ void sdl_host_suggest_dimensions(uint32_t* window_w, uint32_t* window_h) { void sdl_host_loop() { uint32_t ticks_per_frame = 1000/60; + uint32_t real_pixels[DEVICE_H][DEVICE_W]; game_init(); while (true) { @@ -139,7 +140,13 @@ void sdl_host_loop() { game_update(); game_draw(); - SDL_UpdateTexture(sdl_host_target, NULL, &device_pixels, sizeof(device_pixels[0])); + for (int x = 0; x < DEVICE_W; x++) { + for (int y = 0; y < DEVICE_H; y++) { + real_pixels[y][x] = device_palette[device_pixels[y][x]]; + } + } + + SDL_UpdateTexture(sdl_host_target, NULL, &real_pixels, sizeof(real_pixels[0])); SDL_RenderClear(sdl_host_renderer); SDL_RenderCopy(sdl_host_renderer, sdl_host_target, NULL, NULL); SDL_RenderPresent(sdl_host_renderer); diff --git a/sys/sys.h b/sys/sys.h new file mode 100644 index 0000000..ae85494 --- /dev/null +++ b/sys/sys.h @@ -0,0 +1,7 @@ +#ifndef CROCPARTY_SYS_H +#define CROCPARTY_SYS_H + +#include "sys_data.h" +#include "sys_graphics.h" + +#endif // CROCPARTY_SYS_H \ No newline at end of file diff --git a/sys/sys_data.h b/sys/sys_data.h new file mode 100644 index 0000000..7fce79b --- /dev/null +++ b/sys/sys_data.h @@ -0,0 +1,13 @@ +#ifndef CROCPARTY_SYS_DATA_H +#define CROCPARTY_SYS_DATA_H + +#include + +typedef int32_t sys_i32; +typedef uint8_t sys_color; +typedef uint32_t sys_screen_color; + + +sys_screen_color sys_make_screen_color(uint8_t r, uint8_t g, uint8_t b); + +#endif // CROCPARTY_SYS_DATA_H \ No newline at end of file diff --git a/sys/sys_graphics.c b/sys/sys_graphics.c new file mode 100644 index 0000000..e69de29 diff --git a/sys/sys_graphics.h b/sys/sys_graphics.h new file mode 100644 index 0000000..1c5e779 --- /dev/null +++ b/sys/sys_graphics.h @@ -0,0 +1,149 @@ +// Corresponds roughly to section 6.2 of the Pico 8 manual +// +// However, all ranges are now half-open. +// +// https://www.lexaloffle.com/dl/docs/pico-8_manual.html +// +#ifndef CROCPARTY_SYS_GRAPHICS_H +#define CROCPARTY_SYS_GRAPHICS_H + +#include +#include + +#include "sys_data.h" + +/** + * Set the clipping rectangle in pixels. + * + * All drawing operations will be clipped to this rectangle. + */ +void sys_clip_set(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1); + +/** + * Set the clipping rectangle in pixels. + * + * This is the same as `sys_clip_set`, but you can pass clip_previous in order + * to clip to the previous region. + */ +void sys_clip_set_ext( + sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, + bool clip_previous +); + +/** + * Set the color of the pixel `(x, y)`. + */ +void sys_pixel_set( + sys_i32 x, sys_i32 y, + sys_color c +); + +/** + * Get the color of the pixel `(x, y)`. + * + * Returns 0 if the pixel is out of bounds. + */ +sys_color sys_pixel_get( + sys_i32 x, sys_i32 y +); + +// TODO: SSET/SGET +// TODO: FGET/FSET +// TODO: PRINT +// TODO: CURSOR? COLOR? + +/** + * Fill the entire screen with color `c`. + */ +void sys_cls(sys_color c); + +/** + * Create a screen offset of `(-x, -y)` for all drawing operations. + */ +void sys_camera_set(sys_i32 x, sys_i32 y); + +/** + * Reset the camera's offset to `(0, 0)`. + */ +void sys_camera_reset(); + +/** + * Draw or fill a circle at `(x, y)` with radius `r`. + * + * The circle consists of a "stroke" region and a "fill" region which the user + * can decide individually on whether or not to fill. + * + * If r is negative, the circle is not drawn. + * + * This is a special case of sys_circ_oval_draw_ext. + */ +void sys_circ_draw_ext(sys_i32 x, sys_i32 y, sys_i32 r, sys_color c, bool stroke, bool fill); +void sys_circ_draw(sys_i32 x, sys_i32 y, sys_i32 r, sys_color c); +void sys_circ_fill(sys_i32 x, sys_i32 y, sys_i32 r); + +/** + * Draw or fill an oval in the rectangle from `(x0, y0)` to `(x1, y1)` + * + * The oval consists of a "stroke" region and a "fill" region which the user + * can decide individually on whether or not to fill. + */ +void sys_oval_draw_ext( + sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c, + bool stroke, bool fill +); +void sys_oval_draw(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c); +void sys_oval_fill(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c); + +/** + * Draw a line from x0 to y0. + */ +void sys_line_draw(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c); + +/** + * Draw or fill a rectangle `(x, y, w, h)` + */ +void sys_rect_draw_ext( + sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c, + bool stroke, bool fill +); +void sys_rect_draw(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c); +void sys_rect_fill(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c); + +/** + * Set screen palette. + * + * After calling this function, virtual color `c0` will be rendered as + * real color `rc1`. + */ +void sys_spal_set(uint8_t c0, uint32_t rc1); + +/** + * Reset screen palette. + * + * After calling this function, all screen colors are (0, 0, 0). + */ +void sys_spal_reset(); + +/** + * Set draw palette. + * + * After calling this function, draws using color `c0` will be performed + * using color `c1` instead. + * + * Any color mapped to `255` will not actually be drawn. + */ +void sys_dpal_set(uint8_t c0, uint8_t c1); + +/** + * Reset draw palette. + * + * All colors are mapped to themselves. Color 255 is transparent. + */ +void sys_dpal_reset(); + +// TODO: SPR +// TODO: SSPR +// TODO: FILLP? + + +#endif // CROCPARTY_SYS_GRAPHICS_H