Skip to content

Instantly share code, notes, and snippets.

@leiradel
Created September 26, 2018 21:29
Show Gist options
  • Save leiradel/3ac12ca432a0c9f86fb8433b208ab46e to your computer and use it in GitHub Desktop.
Save leiradel/3ac12ca432a0c9f86fb8433b208ab46e to your computer and use it in GitHub Desktop.
Generates code that fills the entire screen, with gray support
#include <stdio.h>
#include <stdint.h>
/*---------------------------------------------------------------------------*/
/* stb_image config and inclusion */
#define STBI_ASSERT( x )
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
/*---------------------------------------------------------------------------*/
struct state_t {
uint32_t code, last;
int x, y;
int last_x, last_y;
int count;
};
static void emit(state_t* state) {
if (state->code == state->last) {
state->count++;
return;
}
uint8_t white_mask = state->last >> 16;
uint8_t black_mask = (state->last >> 8) & 0xff;
uint8_t gray_mask = state->last & 0xff;
if (++state->count != 0) {
printf(" /* %2d, %2d */ ", state->last_x, state->last_y);
if (gray_mask == 0) {
// No gray, set the bits to white and black.
if (black_mask == 0) {
// Pure white, just advance (it seems GB will clear the LCD to white at every frame.)
printf("bg += %d;\n", state->count);
}
else {
if (state->count > 1) {
printf("memset(bg, 0x%02x, %d); bg += %d;\n", black_mask, state->count, state->count);
}
else {
printf("*bg++ = 0x%02x;\n", black_mask);
}
}
}
else {
// Has gray.
const char* even = (state->last_x & 1) == 0 ? "gray" : "~gray";
const char* odd = (state->last_x & 1) == 0 ? "~gray" : "gray";
uint8_t inv_white = white_mask ^ 0xff;
if (state->count > 2) {
if (inv_white != 0xff) {
if (black_mask != 0) {
printf("grayset(bg, (0x%02x & %s) | 0x%02x, (0x%02x & %s) | 0x%02x, %d); bg += %d;\n", inv_white, even, black_mask, inv_white, odd, black_mask, state->count, state->count);
}
else {
printf("grayset(bg, 0x%02x & %s, 0x%02x & %s, %d); bg += %d;\n", inv_white, even, inv_white, odd, state->count, state->count);
}
}
else {
if (black_mask != 0) {
printf("grayset(bg, %s | 0x%02x, %s | 0x%02x, %d); bg += %d;\n", even, black_mask, odd, black_mask, state->count, state->count);
}
else {
printf("grayset(bg, %s, %s, %d); bg += %d;\n", even, odd, state->count, state->count);
}
}
}
else if (state->count == 2) {
if (inv_white != 0xff) {
if (black_mask != 0) {
printf("*bg++ = (0x%02x & %s) | 0x%02x; *bg++ = (0x%02x & %s) | 0x%02x;\n", inv_white, even, black_mask, inv_white, odd, black_mask);
}
else {
printf("*bg++ = 0x%02x & %s; *bg++ = 0x%02x & %s;\n", inv_white, even, inv_white, odd);
}
}
else {
if (black_mask != 0) {
printf("*bg++ = %s | 0x%02x; *bg++ = %s | 0x%02x;\n", even, black_mask, odd, black_mask);
}
else {
printf("*bg++ = %s; *bg++ = %s;\n", even, odd);
}
}
}
else {
if (black_mask != 0) {
printf("*bg++ = (0x%02x & %s) | 0x%02x;\n", inv_white, even, black_mask);
}
else {
printf("*bg++ = 0x%02x & %s;\n", inv_white, even);
}
}
}
state->count = 0;
}
state->last = state->code;
state->last_x = state->x;
state->last_y = state->y;
}
int main(int argc, const char* argv[]) {
if (argc != 2) {
fprintf(stderr, "USAGE: roomenc inputfile\n");
return 1;
}
int width, height;
uint32_t* image = (uint32_t*)stbi_load(argv[1], &width, &height, NULL, STBI_rgb_alpha);
if (width != 84 || height != 48) {
fprintf(stderr, "Image must be 84x48\n");
free((void*)image);
return 1;
}
printf("static void grayset(uint8_t* db, uint8_t m1, uint8_t m2, uint8_t count) {\n");
printf(" for (uint8_t i = 0; i < count; i += 2) {\n");
printf(" *db++ = m1;\n");
printf(" *db++ = m2;\n");
printf(" }\n\n");
printf(" if (count & 1) {\n");
printf(" *db = m1;\n");
printf(" }\n");
printf("}\n\n");
printf("static void draw(bool even) const {\n");
printf(" uint8_t* bg = _displayBuffer;\n");
printf(" uint8_t gray = ((uint8_t)even - 1) ^ 0xaa;\n\n");
state_t state;
state.last = 0xffffffff;
state.last_x = state.last_y = 0;
state.count = -1;
for (state.y = 0; state.y < 48; state.y += 8) {
for (state.x = 0; state.x < 84; state.x++) {
uint8_t white_mask = 0, black_mask = 0, gray_mask = 0;
for (int i = 0; i < 8; i++) {
uint32_t color = image[(state.y + i) * 84 + state.x] & 0xffffff;
uint8_t b = (color >> 16) & 255;
uint8_t g = (color >> 8) & 255;
uint8_t r = color & 255;
if (r >= 0xa0 && g >= 0xa0 && b >= 0xa0) {
white_mask |= 1 << i;
}
else if (r <= 0x55 && g <= 0x55 && b <= 0x55) {
black_mask |= 1 << i;
}
else {
gray_mask |= 1 << i;
}
}
state.code = white_mask << 16 | black_mask << 8 | gray_mask;
emit(&state);
}
}
state.code = 0xffffffff;
emit(&state);
printf("}\n");
free((void*)image);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment