From 326f6a894c47470dd5b4ef7d6521db35aa338dd4 Mon Sep 17 00:00:00 2001 From: violette Date: Mon, 1 Sep 2025 03:09:45 -0400 Subject: [PATCH 1/4] fix: semi works but fundamentally flawed reasoning --- source/main.c | 57 +++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/source/main.c b/source/main.c index 5d58d7a..5198290 100644 --- a/source/main.c +++ b/source/main.c @@ -47,7 +47,6 @@ RGB15(uint16_t r, uint16_t g, uint16_t b) /////////////////////////////////////////////////////////// -#include #include #include #include @@ -91,13 +90,13 @@ volatile FIXED_POINT K2 = (2 * CUBE_WIDTH) + 20; #define COORD2INDEX(x, y) (y * VWIDTH + x) #define COUPLE2INDEX(x) (COORD2INDEX(x[0], x[1])) -#define GET_ROTATE_X_Q(a) ({ float _a = (FIXED2FLOAT(a)) ; \ +#define GET_ROTATE_X_Q(a) ({ float _a = (a) ; \ struct Quaternions q = {}; q.w = FLOAT2FIXED(cos(_a * .5)); \ q.x = FLOAT2FIXED(sin(_a * .5)); q; }) -#define GET_ROTATE_Y_Q(a) ({ float _a = (FIXED2FLOAT(a)) ; \ +#define GET_ROTATE_Y_Q(a) ({ float _a = (a) ; \ struct Quaternions q = {}; q.w = FLOAT2FIXED(cos(_a * .5)); \ q.y = FLOAT2FIXED(sin(_a * .5)); q; }) -#define GET_ROTATE_Z_Q(a) ({ float _a = (FIXED2FLOAT(a)) ; \ +#define GET_ROTATE_Z_Q(a) ({ float _a = (a) ; \ struct Quaternions q = {}; q.w = FLOAT2FIXED(cos(_a * .5)); \ q.z = FLOAT2FIXED(sin(_a * .5)); q; }) @@ -279,30 +278,26 @@ void fill_quads(char current_face, char top[2], char left[2], char right[2], char bot[2]) { - if (current_face != 0) return; - output[COUPLE2INDEX(top)] = RGB15(0, 0, 15); - output[COUPLE2INDEX(left)] = RGB15(0, 0, 15); - output[COUPLE2INDEX(right)] = RGB15(0, 0, 15); - for (int y = top[1] ; y < bot[1] ; ++y) { for (int x = left[0] ; x < right[0] ; ++x) { char curr[2] = {x, y}; if (isInQuad(curr, top, left, right, bot)) //zbuffer issue - {} - //output[COORD2INDEX(x, y)] = current_face; + output[COORD2INDEX(x, y)] = current_face; } } } +float +dist(char a[2], char b[2]) { + return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]); +} + + void detect_and_fill_quads() { for (int current_face = 0 ; current_face < NUM_FACES ; ++current_face) { - char last_top [2] = {VWIDTH, VHEIGHT}; - char last_left[2] = {VWIDTH, 0}; - char last_right [2] = {0, 0}; - char last_bot[2] = {0, 0}; char top [2] = {VWIDTH, VHEIGHT}; char left[2] = {VWIDTH, 0}; char right [2] = {0, 0}; @@ -311,21 +306,21 @@ detect_and_fill_quads() for (char x = 0; x < VWIDTH; ++x) { if (output[COORD2INDEX(x, y)] != current_face) continue; - if (x <= left[0]) { - left[0] = x; - left[1] = y; - } - if (y <= top[1]) { + if (y < top[1]) { top[0] = x; top[1] = y; } - if (x >= right[0]) { + if (x > right[0] && (x != top[0] || y != top [1])) { right[0] = x; right[1] = y; } - if (y >= bot[1]) { - bot[0] = x; - bot[1] = y; + if (x <= left[0] && (x != top[0] || y != top [1])) { // <= to force it bot + left[0] = x; + left[1] = y; + } + if (y >= bot[1] && (x != right[0] || y != right [1]) && (x != left[0] || y != left[1])) { + bot[0] = x; + bot[1] = y; } } } @@ -442,27 +437,27 @@ handleAngle(char input) switch (input) { case 'w': case 'W': - Target = multQ(GET_ROTATE_X_Q(FLOAT2FIXED(M_PI_2)), Current); + Target = multQ(GET_ROTATE_X_Q(M_PI_2), Current); break; case 'a': case 'A': - Target = multQ(GET_ROTATE_Y_Q(-FLOAT2FIXED(M_PI_2)), Current); + Target = multQ(GET_ROTATE_Y_Q(-M_PI_2), Current); break; case 's': case 'S': - Target = multQ(GET_ROTATE_X_Q(-FLOAT2FIXED(M_PI_2)), Current); + Target = multQ(GET_ROTATE_X_Q(-M_PI_2), Current); break; case 'd': case 'D': - Target = multQ(GET_ROTATE_Y_Q(FLOAT2FIXED(M_PI_2)), Current); + Target = multQ(GET_ROTATE_Y_Q(M_PI_2), Current); break; case 'q': case 'Q': - Target = multQ(GET_ROTATE_Z_Q(-FLOAT2FIXED(M_PI_2)), Current); + Target = multQ(GET_ROTATE_Z_Q(-M_PI_2), Current); break; case 'e': case 'E': - Target = multQ(GET_ROTATE_Z_Q(FLOAT2FIXED(M_PI_2)), Current); + Target = multQ(GET_ROTATE_Z_Q(M_PI_2), Current); break; default: currentlyMoving = 0; @@ -507,7 +502,7 @@ main() cubeX <= CUBE_WIDTH_FP - STEP_FP; cubeX += STEP_FP) { for (FIXED_POINT cubeY = -CUBE_WIDTH_FP + STEP_FP; cubeY <= CUBE_WIDTH_FP - STEP_FP; cubeY += STEP_FP) { - switch (FACE_FRONT) { + switch (frontFacingFace) { case FACE_FRONT: rotateCube(cubeX, cubeY, -CUBE_WIDTH_FP, FACE_FRONT); break; From 28295eb8d69c5a8cedb34576b315ce02302165fb Mon Sep 17 00:00:00 2001 From: violette Date: Thu, 4 Sep 2025 07:09:17 -0400 Subject: [PATCH 2/4] feat: Scaling + qol stuff + some opti --- gbafix/Makefile | 2 +- source/main.c | 445 +++++++++++++++++++++++++++--------------------- 2 files changed, 251 insertions(+), 196 deletions(-) diff --git a/gbafix/Makefile b/gbafix/Makefile index c6bbdf8..9668bee 100644 --- a/gbafix/Makefile +++ b/gbafix/Makefile @@ -4,7 +4,7 @@ NAME := gbafix -CC := gcc +# CC := gcc RM := rm -rf # `make V=` builds the binary in verbose build mode diff --git a/source/main.c b/source/main.c index 5198290..75f71d7 100644 --- a/source/main.c +++ b/source/main.c @@ -3,6 +3,7 @@ // SPDX-FileContributor: Antonio Niño Díaz, 2022 #include +#include #define GBA_SCREEN_W 240 #define GBA_SCREEN_H 160 @@ -29,15 +30,24 @@ #define DISPCNT_BG2_ENABLE (1 << 10) -#define MEM_VRAM_MODE3_FB ((uint16_t *)0x06000000) +#define MEM_VRAM_MODE4 ((uint8_t *)buffer) + +#define SHOW_BACK 0x10; +#define FRONT_BUFFER (0x6000000) +#define BACK_BUFFER (0x600A000) + +#define PALETTE ((uint16_t *)0x5000000) +static volatile uint8_t lastPaletteIndex = 0; #define FIXED_POINT int32_t -#define fp 12 +#define FP 12 #define SHIFT_THRESHOLD 0.05 -#define SHIFT_THRESHOLD_FP ((1 << fp) * SHIFT_THRESHOLD) +#define SHIFT_THRESHOLD_FP ((1 << FP) * SHIFT_THRESHOLD) -#define FLOAT2FIXED(value) (int)((value) * (1 << fp)) -#define FIXED2FLOAT(value) ((value) / (float)(1 << fp)) +#define FLOAT2FIXED(value) (int)((value) * (1 << FP)) +#define FIXED2FLOAT(value) ((value) / (float)(1 << FP)) + +static uint8_t *buffer = (uint8_t *)FRONT_BUFFER; static inline uint16_t RGB15(uint16_t r, uint16_t g, uint16_t b) @@ -45,6 +55,30 @@ RGB15(uint16_t r, uint16_t g, uint16_t b) return (r & 0x1F) | ((g & 0x1F) << 5) | ((b & 0x1F) << 10); } +void +flipBuffers() +{ + if(buffer == (uint8_t *)FRONT_BUFFER) { + REG_DISPCNT &= ~SHOW_BACK; + buffer = (uint8_t *)BACK_BUFFER; + } else { + REG_DISPCNT |= SHOW_BACK; + buffer = (uint8_t *)FRONT_BUFFER; + } +} + +void +putPx(uint8_t x, uint8_t y, uint16_t c) +{ + uint16_t pos = (GBA_SCREEN_W * y + x) >> 1; + uint8_t px = buffer[pos]; + if (y & 1) { + buffer[pos] = c << 8; + buffer[pos] = (c << 8) | (px & 0x00ff); + } else { + buffer[pos] = (px & 0xff00) | c; + } +} /////////////////////////////////////////////////////////// #include @@ -53,10 +87,10 @@ RGB15(uint16_t r, uint16_t g, uint16_t b) #include #include -#define VWIDTH 50 -#define VHEIGHT 50 +#define VWIDTH 25 +#define VHEIGHT 25 #define CUBE_WIDTH 10 -#define CUBE_WIDTH_FP ((1 << fp) * CUBE_WIDTH) +#define CUBE_WIDTH_FP ((1 << FP) * CUBE_WIDTH) enum faces { FACE_FRONT = 0, @@ -68,27 +102,28 @@ enum faces { NUM_FACES, }; -#define STEP 5 -#define STEP_FP ((1 << fp) * STEP) +#define STEP 20 +#define STEP_FP ((1 << FP) * STEP) #define ACTION_STEP 0.1 -#define ACTION_STEP_FP ((1 << fp) * ACTION_STEP) +#define ACTION_STEP_FP ((1 << FP) * ACTION_STEP) -#define PITCH_STEP 0.05 -#define ROLL_STEP 0.05 -#define YAW_STEP 0.05 +#define SCALE 10 // how much is our initial render scaled -volatile FIXED_POINT K1 = 60; -volatile FIXED_POINT K2 = (2 * CUBE_WIDTH) + 20; +volatile FIXED_POINT K1 = 20; +volatile FIXED_POINT K2 = (2 * CUBE_WIDTH) + 10; - -#define MULT_FP(a,b) ((a * b) >> fp) +#define MULT_FP(a,b) ((a * b) >> FP) #define SQ(n) (n * n) #define SQ_FP(n) (MULT_FP(n, n)) #define COORD2INDEX(x, y) (y * VWIDTH + x) #define COUPLE2INDEX(x) (COORD2INDEX(x[0], x[1])) +#define PLOT_COORD(x, y, c) \ + for (uint8_t i = 0 ; i < SCALE ; ++i) \ + for (uint8_t j = 0 ; j < SCALE ; ++j) \ + putPx(x * SCALE + i, j + (SCALE * y), chooseColor(c)); #define GET_ROTATE_X_Q(a) ({ float _a = (a) ; \ struct Quaternions q = {}; q.w = FLOAT2FIXED(cos(_a * .5)); \ @@ -104,10 +139,28 @@ volatile FIXED_POINT K2 = (2 * CUBE_WIDTH) + 20; #define IS_IDLE (Idle.x || Idle.y || Idle.z) #define RESET_IDLE {Idle.x = 0; Idle.y = 0; Idle.z = 0;} +void +init_colors() +{ + const uint16_t color_order[NUM_FACES + 1] = { + RGB15(0, 0, 0), + RGB15(31, 0, 0), + RGB15(0, 31, 0), + RGB15(0, 0, 31), + RGB15(0, 31, 31), + RGB15(31, 31, 0), + RGB15(31, 0, 31), + }; + + for ( ; lastPaletteIndex <= NUM_FACES ; ++lastPaletteIndex) { + PALETTE[lastPaletteIndex] = color_order[lastPaletteIndex]; + } +} + struct { - char x; - char y; - char z; + uint8_t x; + uint8_t y; + uint8_t z; } Idle; @@ -118,22 +171,24 @@ struct Quaternions { FIXED_POINT z; } Target, Current; -FIXED_POINT interpolationStep = 0; -FIXED_POINT zBuffer[VHEIGHT * VWIDTH]; -char output[VHEIGHT * VWIDTH]; +static FIXED_POINT interpolationStep = 0; +static FIXED_POINT zBuffer[VHEIGHT * VWIDTH]; +static FIXED_POINT maxZbufByColor[NUM_FACES * 2]; +static uint8_t output[VHEIGHT * VWIDTH]; -static volatile char shouldBreak = 1; -static volatile char currentlyMoving = 0; -static volatile char currentCountR = 0; -static volatile char frontFacingFace = FACE_FRONT; +static volatile uint8_t shouldBreak = 1; +static volatile uint8_t currentlyMoving = 0; +static volatile uint8_t currentCountR = 0; +static volatile uint8_t frontFacingFace = FACE_FRONT; void normalize(struct Quaternions *q) { float n = sqrt(FIXED2FLOAT(SQ_FP(q->w) + SQ_FP(q->x) + SQ_FP(q->y) + SQ_FP(q->z))); - if (n == 0) + if (n == 0 || n == 1) return; + q->w = FLOAT2FIXED(FIXED2FLOAT(q->w) / n); q->x = FLOAT2FIXED(FIXED2FLOAT(q->x) / n); q->y = FLOAT2FIXED(FIXED2FLOAT(q->y) / n); @@ -141,77 +196,68 @@ normalize(struct Quaternions *q) } struct Quaternions -mult(struct Quaternions q, FIXED_POINT x, FIXED_POINT y, FIXED_POINT z) +mult(struct Quaternions *q, FIXED_POINT x, FIXED_POINT y, FIXED_POINT z) { //p = q * p * qbar struct Quaternions res; res.w = 0; - res.x = MULT_FP(x, (SQ_FP(q.w) + SQ_FP(q.x) - SQ_FP(q.y) - SQ_FP(q.z))) - + (MULT_FP(y, (MULT_FP(q.x, q.y) - MULT_FP(q.w, q.z))) * 2) - + (MULT_FP(z, (MULT_FP(q.x, q.z) + MULT_FP(q.w, q.y))) * 2); + res.x = MULT_FP(x, (SQ_FP(q->w) + SQ_FP(q->x) - SQ_FP(q->y) - SQ_FP(q->z))) + + (MULT_FP(y, (MULT_FP(q->x, q->y) - MULT_FP(q->w, q->z))) * 2) + + (MULT_FP(z, (MULT_FP(q->x, q->z) + MULT_FP(q->w, q->y))) * 2); - res.y = (MULT_FP(x, (MULT_FP(q.x, q.y) + MULT_FP(q.w,q.z))) * 2) - + (MULT_FP(y, (SQ_FP(q.w) - SQ_FP(q.x) + SQ_FP(q.y) - SQ_FP(q.z)))) - + (MULT_FP(z, (MULT_FP(q.y, q.z) - MULT_FP(q.w, q.x))) << 2); + res.y = (MULT_FP(x, (MULT_FP(q->x, q->y) + MULT_FP(q->w,q->z))) * 2) + + (MULT_FP(y, (SQ_FP(q->w) - SQ_FP(q->x) + SQ_FP(q->y) - SQ_FP(q->z)))) + + (MULT_FP(z, (MULT_FP(q->y, q->z) - MULT_FP(q->w, q->x))) << 2); - res.z = (MULT_FP(x, (MULT_FP(q.x, q.z) - MULT_FP(q.w, q.y)))* 2) - + (MULT_FP(y, (MULT_FP(q.y, q.z) + MULT_FP(q.w, q.x))) * 2) - + MULT_FP(z, (SQ_FP(q.w) - SQ_FP(q.x) - SQ_FP(q.y) + SQ_FP(q.z))); + res.z = (MULT_FP(x, (MULT_FP(q->x, q->z) - MULT_FP(q->w, q->y)))* 2) + + (MULT_FP(y, (MULT_FP(q->y, q->z) + MULT_FP(q->w, q->x))) * 2) + + MULT_FP(z, (SQ_FP(q->w) - SQ_FP(q->x) - SQ_FP(q->y) + SQ_FP(q->z))); return res; } -struct Quaternions -multQ(struct Quaternions p, struct Quaternions q) +// res in quat p +void +multQ(struct Quaternions *p, struct Quaternions *q) { - if (p.x <= SHIFT_THRESHOLD_FP && p.x >= -SHIFT_THRESHOLD_FP - && p.y <= SHIFT_THRESHOLD_FP && p.y >= -SHIFT_THRESHOLD_FP - && p.z <= SHIFT_THRESHOLD_FP && p.z >= -SHIFT_THRESHOLD_FP) - return q; + if (p->x <= SHIFT_THRESHOLD_FP && p->x >= -SHIFT_THRESHOLD_FP + && p->y <= SHIFT_THRESHOLD_FP && p->y >= -SHIFT_THRESHOLD_FP + && p->z <= SHIFT_THRESHOLD_FP && p->z >= -SHIFT_THRESHOLD_FP) { + p = q; + return; + } - if (q.x <= SHIFT_THRESHOLD_FP && q.x >= -SHIFT_THRESHOLD_FP - && q.y <= SHIFT_THRESHOLD_FP && q.y >= -SHIFT_THRESHOLD_FP - && q.z <= SHIFT_THRESHOLD_FP && q.z >= -SHIFT_THRESHOLD_FP) - return p; + if (q->x <= SHIFT_THRESHOLD_FP && q->x >= -SHIFT_THRESHOLD_FP + && q->y <= SHIFT_THRESHOLD_FP && q->y >= -SHIFT_THRESHOLD_FP + && q->z <= SHIFT_THRESHOLD_FP && q->z >= -SHIFT_THRESHOLD_FP) + return; - struct Quaternions res = { - .w = MULT_FP(p.w, q.w) - MULT_FP(p.x, q.x) - - MULT_FP(p.y, q.y) - MULT_FP(p.z, q.z), - .x = MULT_FP(p.w, q.x) + MULT_FP(p.x, q.w) + - MULT_FP(p.y, q.z) - MULT_FP(p.z, q.y), - .y = MULT_FP(p.w, q.y) - MULT_FP(p.x, q.z) + - MULT_FP(p.y, q.w) + MULT_FP(p.z, q.x), - .z = MULT_FP(p.w, q.z) + MULT_FP(p.x, q.y) - - MULT_FP(p.y, q.x) + MULT_FP(p.z, q.w), - }; - - return res; + FIXED_POINT w = MULT_FP(p->w, q->w) - MULT_FP(p->x, q->x) - + MULT_FP(p->y, q->y) - MULT_FP(p->z, q->z); + FIXED_POINT x = MULT_FP(p->w, q->x) + MULT_FP(p->x, q->w) + + MULT_FP(p->y, q->z) - MULT_FP(p->z, q->y); + FIXED_POINT y = MULT_FP(p->w, q->y) - MULT_FP(p->x, q->z) + + MULT_FP(p->y, q->w) + MULT_FP(p->z, q->x); + FIXED_POINT z = MULT_FP(p->w, q->z) + MULT_FP(p->x, q->y) - + MULT_FP(p->y, q->x) + MULT_FP(p->z, q->w); + p->w = w; + p->x = x; + p->y = y; + p->z = z; } + uint16_t -chooseColor(char c) +chooseColor(uint8_t c) { - switch (c) { - case FACE_FRONT: - return RGB15(31, 0, 0); - case FACE_BACK: - return RGB15(31, 15, 31); - case FACE_BOTTOM: - return RGB15(31, 0, 31); - case FACE_LEFT: - return RGB15(0, 0, 31); - case FACE_RIGHT: - return RGB15(0, 31, 31); - case FACE_TOP: - return RGB15(0, 31, 0); - default: - // BG - return RGB15(31, 31, 31); - } + if (c >= 1 && c <= NUM_FACES) + return c; + else + return 0; } -char +uint8_t chooseMainFace() { int total = 0; @@ -234,30 +280,27 @@ chooseMainFace() return frontFacingFace; } -char -isInQuad(char curr[2], char top[2], char left[2], - char right[2], char bot[2]) +uint8_t +isInQuad(uint8_t curr[2], uint8_t points[8]) { - char *points[4] = {top, left, bot, right}; - - char pos = 0, neg = 0; - char x = curr[0]; - char y = curr[1];; + uint8_t pos = 0, neg = 0; + uint8_t x = curr[0]; + uint8_t y = curr[1];; int d; - for (char i = 0; i < 4; ++i) { - if (points[i][0] == curr[0] && points[i][1] == curr[1]) + for (uint8_t i = 0; i < 4; ++i) { + if (points[2 * i] == curr[0] && points[2 * i + 1] == curr[1]) return 1; //Form a segment between the i'th point - char x1 = points[i][0]; - char y1 = points[i][1]; + uint8_t x1 = points[2 * i]; + uint8_t y1 = points[2 * i + 1]; //And the i+1'th, or if i is the last, with the first point - char i2 = (i + 1) % 4; + uint8_t i2 = (i + 1) % 4; - char x2 = points[i2][0]; - char y2 = points[i2][1]; + uint8_t x2 = points[2 * i2]; + uint8_t y2 = points[2 * i2 + 1]; //Compute the cross product @@ -275,90 +318,97 @@ isInQuad(char curr[2], char top[2], char left[2], } void -fill_quads(char current_face, char top[2], char left[2], - char right[2], char bot[2]) +fill_quads(uint8_t *points, uint8_t current_face) { - for (int y = top[1] ; y < bot[1] ; ++y) { - for (int x = left[0] ; x < right[0] ; ++x) { - char curr[2] = {x, y}; - if (isInQuad(curr, top, left, right, bot)) - //zbuffer issue - output[COORD2INDEX(x, y)] = current_face; + uint8_t top = 0, bot = 0, left = 0, right = 0; + for (uint8_t x = 0 ; x < 8 ; ++x) { + if (x % 2 == 0) { + if (points[x] > right) + right = points[x]; + if (points[x] < left) + left = points[x]; + } else { + if (points[x] > bot) + bot = points[x]; + if (points[x] < top) + top = points[x]; + } + } + for (int y = top ; y < bot ; ++y) { + for (int x = left ; x < right ; ++x) { + uint8_t curr[2] = {x, y}; + if (isInQuad(curr, points)) + PLOT_COORD(x, y, current_face + 1); } } } -float -dist(char a[2], char b[2]) { - return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]); +uint8_t +detect(uint8_t *points, uint8_t current_face) { + uint8_t i = 0; + for (uint8_t y = 0; y < VHEIGHT; ++y) { + for (uint8_t x = 0; x < VWIDTH; ++x) { + if (output[COORD2INDEX(x, y)] != current_face) + continue; + // only 4 points are ploted + points[i] = x; + points[i + 1] = y; + i += 2; + } + } + + for (uint8_t x = 0 ; x < 8 ; ++x) + if (points[x] == 0) + return 0; + return 1; } +int +comp(const void *p1, const void *p2) { + FIXED_POINT left = *(const FIXED_POINT *)p1; + FIXED_POINT right = *(const FIXED_POINT *)p2; + + return ((left > right) - (left < right)); +} void detect_and_fill_quads() { - for (int current_face = 0 ; current_face < NUM_FACES ; ++current_face) { - char top [2] = {VWIDTH, VHEIGHT}; - char left[2] = {VWIDTH, 0}; - char right [2] = {0, 0}; - char bot[2] = {0, 0}; - for (char y = 0; y < VHEIGHT; ++y) { - for (char x = 0; x < VWIDTH; ++x) { - if (output[COORD2INDEX(x, y)] != current_face) - continue; - if (y < top[1]) { - top[0] = x; - top[1] = y; - } - if (x > right[0] && (x != top[0] || y != top [1])) { - right[0] = x; - right[1] = y; - } - if (x <= left[0] && (x != top[0] || y != top [1])) { // <= to force it bot - left[0] = x; - left[1] = y; - } - if (y >= bot[1] && (x != right[0] || y != right [1]) && (x != left[0] || y != left[1])) { - bot[0] = x; - bot[1] = y; - } - } - } - fill_quads(current_face, top, left, right, bot); + qsort(maxZbufByColor, NUM_FACES, 2 * sizeof(FIXED_POINT), comp); + for (uint8_t idx = 0 ; idx < NUM_FACES ; ++idx) { + uint8_t current_face = maxZbufByColor[2 * idx + 1]; + uint8_t points[8] = { 0 }; + if (detect(points, current_face)) + fill_quads(points, current_face); } - } void printAscii() { - // TODO scale up - MEM_VRAM_MODE3_FB[120 + 80 * GBA_SCREEN_W] = RGB15(currentCountR, 31 - currentCountR, 0); - MEM_VRAM_MODE3_FB[136 + 80 * GBA_SCREEN_W] = RGB15(currentCountR, 31 - currentCountR, 0); - MEM_VRAM_MODE3_FB[120 + 96 * GBA_SCREEN_W] = RGB15(currentCountR, 31 - currentCountR, 0); - currentCountR = currentCountR == 31 ? 0 : 31; - detect_and_fill_quads(); + flipBuffers(); - for (int i = 0; i < VHEIGHT; ++i) { - for (int j = 0; j < VWIDTH; ++j) { - char prevc = 0; - char *c = output + (i * VWIDTH + j); - MEM_VRAM_MODE3_FB[(i + 50) * GBA_SCREEN_W + j + 50] = chooseColor(*c); - } - } + // DISPLAY POINTS + //for (int i = 0; i < VHEIGHT; ++i) { + // for (int j = 0; j < VWIDTH; ++j) { + // uint8_t prevc = 0; + // uint8_t c = output[i * VWIDTH + j]; + // MEM_VRAM_MODE4[i * GBA_SCREEN_W + j] = chooseColor(c); + // } + //} } void -rotateCube(FIXED_POINT cubeX, FIXED_POINT cubeY, FIXED_POINT cubeZ, char ch) +rotateCube(FIXED_POINT cubeX, FIXED_POINT cubeY, FIXED_POINT cubeZ, uint8_t ch) { - struct Quaternions q = mult(Current, cubeX, cubeY, cubeZ); + struct Quaternions q = mult(&Current, cubeX, cubeY, cubeZ); - int x = q.x >> fp; - int y = q.y >> fp; + int x = q.x >> FP; + int y = q.y >> FP; // not fixed point yet!! - float invZ = (1 << fp) / (float)(q.z + K2 * (1 << fp)); + float invZ = (1 << FP) / (float)(q.z + K2 * (1 << FP)); int screenX = (int)(VWIDTH * 0.5) + (int)((x) * K1) * invZ; int screenY = (int)(VHEIGHT * 0.5) + (int)((y) * K1) * invZ; @@ -372,33 +422,32 @@ rotateCube(FIXED_POINT cubeX, FIXED_POINT cubeY, FIXED_POINT cubeZ, char ch) if (zBuffer[idx] < invZ) { zBuffer[idx] = invZ; output[idx] = ch; + if (invZ > maxZbufByColor[ch]) { + maxZbufByColor[2 * ch] = invZ; + maxZbufByColor[2 * ch + 1] = ch; //palette[0] is bg + } } } } -struct Quaternions -interpolate(struct Quaternions qa, struct Quaternions qb) +void +interpolate(struct Quaternions *qa, struct Quaternions *qb) { frontFacingFace = -1; - struct Quaternions res; float cosHalfTheta = - FIXED2FLOAT(MULT_FP(qa.w, qb.w) + - MULT_FP(qa.x, qb.x) + - MULT_FP(qa.y, qb.y) + - MULT_FP(qa.z, qb.z)); + FIXED2FLOAT(MULT_FP(qa->w, qb->w) + + MULT_FP(qa->x, qb->x) + + MULT_FP(qa->y, qb->y) + + MULT_FP(qa->z, qb->z)); //if qa = qb or qa = -qb then theta = 0 and we can return qa if (cosHalfTheta >= 1.0 || cosHalfTheta <= -1.0) { - res.w = qa.w; - res.x = qa.x; - res.y = qa.y; - res.z = qa.z; goto exit; } if (cosHalfTheta < 0) { - qb.w = -qb.w; - qb.x = -qb.x; - qb.y = -qb.y; - qb.z = qb.z; + qb->w = -qb->w; + qb->x = -qb->x; + qb->y = -qb->y; + qb->z = qb->z; cosHalfTheta = -cosHalfTheta; } @@ -406,11 +455,11 @@ interpolate(struct Quaternions qa, struct Quaternions qb) float sinHalfTheta = sqrt(1.0 - cosHalfTheta * cosHalfTheta); //if theta = 180 degrees then result is not fully defined // we could rotate around any axis normal to qa or qb - if (sinHalfTheta < 0.001 && sinHalfTheta > -0.001) { - res.w = ((qa.w >> 1) + (qb.w >> 1)); - res.x = ((qa.x >> 1) + (qb.x >> 1)); - res.y = ((qa.y >> 1) + (qb.y >> 1)); - res.z = ((qa.z >> 1) + (qb.z >> 1)); + if (sinHalfTheta < 0.01 && sinHalfTheta > -0.01) { + qa->w = ((qa->w >> 1) + (qb->w >> 1)); + qa->x = ((qa->x >> 1) + (qb->x >> 1)); + qa->y = ((qa->y >> 1) + (qb->y >> 1)); + qa->z = ((qa->z >> 1) + (qb->z >> 1)); goto exit; } @@ -418,55 +467,58 @@ interpolate(struct Quaternions qa, struct Quaternions qb) FIXED_POINT ratioA = FLOAT2FIXED(sin((1 - FIXED2FLOAT(interpolationStep)) * halfTheta) / sinHalfTheta); FIXED_POINT ratioB = FLOAT2FIXED(sin(FIXED2FLOAT(interpolationStep) * halfTheta) / sinHalfTheta); - res.w = (MULT_FP(qa.w, ratioA) + MULT_FP(qb.w, ratioB)); - res.x = (MULT_FP(qa.x, ratioA) + MULT_FP(qb.x, ratioB)); - res.y = (MULT_FP(qa.y, ratioA) + MULT_FP(qb.y, ratioB)); - res.z = (MULT_FP(qa.z, ratioA) + MULT_FP(qb.z, ratioB)); + qa->w = (MULT_FP(qa->w, ratioA) + MULT_FP(qb->w, ratioB)); + qa->x = (MULT_FP(qa->x, ratioA) + MULT_FP(qb->x, ratioB)); + qa->y = (MULT_FP(qa->y, ratioA) + MULT_FP(qb->y, ratioB)); + qa->z = (MULT_FP(qa->z, ratioA) + MULT_FP(qb->z, ratioB)); exit: interpolationStep += ACTION_STEP_FP; - return res; } void -handleAngle(char input) +handleAngle(uint8_t input) { // TODO if (currentlyMoving == 0) { currentlyMoving = input; + struct Quaternions tmp; switch (input) { case 'w': case 'W': - Target = multQ(GET_ROTATE_X_Q(M_PI_2), Current); + tmp = GET_ROTATE_X_Q(M_PI_2); break; case 'a': case 'A': - Target = multQ(GET_ROTATE_Y_Q(-M_PI_2), Current); + tmp = GET_ROTATE_Y_Q(-M_PI_2); break; case 's': case 'S': - Target = multQ(GET_ROTATE_X_Q(-M_PI_2), Current); + tmp = GET_ROTATE_X_Q(-M_PI_2); break; case 'd': case 'D': - Target = multQ(GET_ROTATE_Y_Q(M_PI_2), Current); + tmp = GET_ROTATE_Y_Q(M_PI_2); break; case 'q': case 'Q': - Target = multQ(GET_ROTATE_Z_Q(-M_PI_2), Current); + tmp = GET_ROTATE_Z_Q(-M_PI_2); break; case 'e': case 'E': - Target = multQ(GET_ROTATE_Z_Q(M_PI_2), Current); + tmp = GET_ROTATE_Z_Q(M_PI_2); break; default: currentlyMoving = 0; + return; //TODO idle movement } + multQ(&tmp, &Target); + Target = tmp; normalize(&Target); } else { - if (interpolationStep < (1 << fp) - ACTION_STEP_FP * 2) { - Current = interpolate(Current, Target); + if (interpolationStep < (1 << FP) ) { + interpolate(&Current, &Target); normalize(&Current); } else { @@ -477,31 +529,34 @@ handleAngle(char input) } } -char +uint8_t getInput() { // TODO - char c = 'd'; + uint8_t c = 'd'; handleAngle(c); return c; } - int main() { - REG_DISPCNT = DISPCNT_BG_MODE(3) | DISPCNT_BG2_ENABLE; + REG_DISPCNT = DISPCNT_BG_MODE(4) | DISPCNT_BG2_ENABLE; Current = GET_ROTATE_Z_Q(0); + init_colors(); + while (1) { + memset(MEM_VRAM_MODE4, 0, GBA_SCREEN_H * GBA_SCREEN_W); memset(output, NUM_FACES, VWIDTH * VHEIGHT); + memset(maxZbufByColor, 0, 2 * sizeof(FIXED_POINT) * NUM_FACES); memset(zBuffer, 0xffffffff, VWIDTH * VHEIGHT * sizeof(FIXED_POINT)); - for (FIXED_POINT cubeX = -CUBE_WIDTH_FP + STEP_FP ; - cubeX <= CUBE_WIDTH_FP - STEP_FP; cubeX += STEP_FP) { - for (FIXED_POINT cubeY = -CUBE_WIDTH_FP + STEP_FP; - cubeY <= CUBE_WIDTH_FP - STEP_FP; cubeY += STEP_FP) { + for (FIXED_POINT cubeX = -CUBE_WIDTH_FP + 2 * (1 << FP); + cubeX <= CUBE_WIDTH_FP - 2 * (1 << FP); cubeX += STEP_FP - 4 * (1 << FP)) { + for (FIXED_POINT cubeY = -CUBE_WIDTH_FP + 2 * (1 << FP); + cubeY <= CUBE_WIDTH_FP - 2 * (1 << FP); cubeY += STEP_FP - 4 * (1 << FP)) { switch (frontFacingFace) { case FACE_FRONT: rotateCube(cubeX, cubeY, -CUBE_WIDTH_FP, FACE_FRONT); From f2bb638c0bded862ae1dcbddcfe7e3be1579e54a Mon Sep 17 00:00:00 2001 From: violette Date: Fri, 5 Sep 2025 08:25:22 -0400 Subject: [PATCH 3/4] fix: [WIP] IT "WORKS" --- source/main.c | 614 ++++++++++++++++++++++++-------------------------- 1 file changed, 298 insertions(+), 316 deletions(-) diff --git a/source/main.c b/source/main.c index 75f71d7..76472d9 100644 --- a/source/main.c +++ b/source/main.c @@ -10,20 +10,20 @@ #define REG_DISPCNT *((volatile uint16_t *)0x04000000) -#define REG_KEYINPUT *((volatile uint16_t *)0x04000130) -#define DEFAULT_REG_KEYINPUT *((volatile uint16_t *)0x04000130) +#define REG_KEYINPUT *((volatile uint16_t *)0x04000130) +#define DEFAULT_REG_KEYINPUT *((volatile uint16_t *)0x04000130) #define KEY_DOWN_NOW(key) (~(REG_KEYINPUT) & key) -#define KEY_A 1 -#define KEY_B 2 -#define KEY_SELECT 3 -#define KEY_START 4 -#define KEY_DPAD_RIGHT 5 -#define KEY_DPAD_LEFT 6 -#define KEY_DPAD_UP 7 -#define KEY_DPAD_DOWN 8 -#define KEY_TRIGGER_LEFT 9 -#define KEY_TRIGGER_RIGHT 10 +#define KEY_A 1 +#define KEY_B 2 +#define KEY_SELECT 3 +#define KEY_START 4 +#define KEY_DPAD_RIGHT 5 +#define KEY_DPAD_LEFT 6 +#define KEY_DPAD_UP 7 +#define KEY_DPAD_DOWN 8 +#define KEY_TRIGGER_LEFT 9 +#define KEY_TRIGGER_RIGHT 10 #define DISPCNT_BG_MODE_MASK (0x7) #define DISPCNT_BG_MODE(n) ((n) & DISPCNT_BG_MODE_MASK) // 0 to 5 @@ -52,7 +52,7 @@ static uint8_t *buffer = (uint8_t *)FRONT_BUFFER; static inline uint16_t RGB15(uint16_t r, uint16_t g, uint16_t b) { - return (r & 0x1F) | ((g & 0x1F) << 5) | ((b & 0x1F) << 10); + return (r & 0x1F) | ((g & 0x1F) << 5) | ((b & 0x1F) << 10); } void @@ -68,17 +68,12 @@ flipBuffers() } void -putPx(uint8_t x, uint8_t y, uint16_t c) +putPx(uint16_t x, uint16_t y, uint8_t c) { - uint16_t pos = (GBA_SCREEN_W * y + x) >> 1; - uint8_t px = buffer[pos]; - if (y & 1) { - buffer[pos] = c << 8; - buffer[pos] = (c << 8) | (px & 0x00ff); - } else { - buffer[pos] = (px & 0xff00) | c; - } + uint16_t pos = (GBA_SCREEN_W * y + x); + buffer[pos] = c; } + /////////////////////////////////////////////////////////// #include @@ -93,13 +88,13 @@ putPx(uint8_t x, uint8_t y, uint16_t c) #define CUBE_WIDTH_FP ((1 << FP) * CUBE_WIDTH) enum faces { - FACE_FRONT = 0, - FACE_LEFT, - FACE_RIGHT, - FACE_BOTTOM, - FACE_TOP, - FACE_BACK, - NUM_FACES, + FACE_FRONT = 0, + FACE_LEFT, + FACE_RIGHT, + FACE_BOTTOM, + FACE_TOP, + FACE_BACK, + NUM_FACES, }; #define STEP 20 @@ -108,7 +103,7 @@ enum faces { #define ACTION_STEP 0.1 #define ACTION_STEP_FP ((1 << FP) * ACTION_STEP) -#define SCALE 10 // how much is our initial render scaled +#define SCALE 3 // how much is our initial render scaled volatile FIXED_POINT K1 = 20; volatile FIXED_POINT K2 = (2 * CUBE_WIDTH) + 10; @@ -118,22 +113,20 @@ volatile FIXED_POINT K2 = (2 * CUBE_WIDTH) + 10; #define SQ(n) (n * n) #define SQ_FP(n) (MULT_FP(n, n)) -#define COORD2INDEX(x, y) (y * VWIDTH + x) -#define COUPLE2INDEX(x) (COORD2INDEX(x[0], x[1])) #define PLOT_COORD(x, y, c) \ for (uint8_t i = 0 ; i < SCALE ; ++i) \ for (uint8_t j = 0 ; j < SCALE ; ++j) \ putPx(x * SCALE + i, j + (SCALE * y), chooseColor(c)); #define GET_ROTATE_X_Q(a) ({ float _a = (a) ; \ - struct Quaternions q = {}; q.w = FLOAT2FIXED(cos(_a * .5)); \ - q.x = FLOAT2FIXED(sin(_a * .5)); q; }) + struct Quaternions q = {}; q.w = FLOAT2FIXED(cos(_a * .5)); \ + q.x = FLOAT2FIXED(sin(_a * .5)); q; }) #define GET_ROTATE_Y_Q(a) ({ float _a = (a) ; \ - struct Quaternions q = {}; q.w = FLOAT2FIXED(cos(_a * .5)); \ - q.y = FLOAT2FIXED(sin(_a * .5)); q; }) + struct Quaternions q = {}; q.w = FLOAT2FIXED(cos(_a * .5)); \ + q.y = FLOAT2FIXED(sin(_a * .5)); q; }) #define GET_ROTATE_Z_Q(a) ({ float _a = (a) ; \ - struct Quaternions q = {}; q.w = FLOAT2FIXED(cos(_a * .5)); \ - q.z = FLOAT2FIXED(sin(_a * .5)); q; }) + struct Quaternions q = {}; q.w = FLOAT2FIXED(cos(_a * .5)); \ + q.z = FLOAT2FIXED(sin(_a * .5)); q; }) //TODO Idle animations #define IS_IDLE (Idle.x || Idle.y || Idle.z) @@ -152,29 +145,27 @@ init_colors() RGB15(31, 0, 31), }; - for ( ; lastPaletteIndex <= NUM_FACES ; ++lastPaletteIndex) { + for ( ; lastPaletteIndex <= NUM_FACES ; ++lastPaletteIndex) PALETTE[lastPaletteIndex] = color_order[lastPaletteIndex]; - } } struct { - uint8_t x; - uint8_t y; - uint8_t z; + uint8_t x; + uint8_t y; + uint8_t z; } Idle; struct Quaternions { - FIXED_POINT w; - FIXED_POINT x; - FIXED_POINT y; - FIXED_POINT z; + FIXED_POINT w; + FIXED_POINT x; + FIXED_POINT y; + FIXED_POINT z; } Target, Current; -static FIXED_POINT interpolationStep = 0; -static FIXED_POINT zBuffer[VHEIGHT * VWIDTH]; -static FIXED_POINT maxZbufByColor[NUM_FACES * 2]; -static uint8_t output[VHEIGHT * VWIDTH]; +static FIXED_POINT interpolationStep = 0; +static volatile uint16_t vertices[NUM_FACES * 2 * 4]; +static volatile FIXED_POINT zBuffer[NUM_FACES * 2]; static volatile uint8_t shouldBreak = 1; static volatile uint8_t currentlyMoving = 0; @@ -184,54 +175,54 @@ static volatile uint8_t frontFacingFace = FACE_FRONT; void normalize(struct Quaternions *q) { - float n = sqrt(FIXED2FLOAT(SQ_FP(q->w) + SQ_FP(q->x) + - SQ_FP(q->y) + SQ_FP(q->z))); - if (n == 0 || n == 1) - return; + float n = sqrt(FIXED2FLOAT(SQ_FP(q->w) + SQ_FP(q->x) + + SQ_FP(q->y) + SQ_FP(q->z))); + if (n == 0 || n == 1) + return; - q->w = FLOAT2FIXED(FIXED2FLOAT(q->w) / n); - q->x = FLOAT2FIXED(FIXED2FLOAT(q->x) / n); - q->y = FLOAT2FIXED(FIXED2FLOAT(q->y) / n); - q->z = FLOAT2FIXED(FIXED2FLOAT(q->z) / n); + q->w = FLOAT2FIXED(FIXED2FLOAT(q->w) / n); + q->x = FLOAT2FIXED(FIXED2FLOAT(q->x) / n); + q->y = FLOAT2FIXED(FIXED2FLOAT(q->y) / n); + q->z = FLOAT2FIXED(FIXED2FLOAT(q->z) / n); } struct Quaternions mult(struct Quaternions *q, FIXED_POINT x, FIXED_POINT y, FIXED_POINT z) { - //p = q * p * qbar - struct Quaternions res; + //p = q * p * qbar + struct Quaternions res; - res.w = 0; - res.x = MULT_FP(x, (SQ_FP(q->w) + SQ_FP(q->x) - SQ_FP(q->y) - SQ_FP(q->z))) - + (MULT_FP(y, (MULT_FP(q->x, q->y) - MULT_FP(q->w, q->z))) * 2) - + (MULT_FP(z, (MULT_FP(q->x, q->z) + MULT_FP(q->w, q->y))) * 2); + res.w = 0; + res.x = MULT_FP(x, (SQ_FP(q->w) + SQ_FP(q->x) - SQ_FP(q->y) - SQ_FP(q->z))) + + (MULT_FP(y, (MULT_FP(q->x, q->y) - MULT_FP(q->w, q->z))) * 2) + + (MULT_FP(z, (MULT_FP(q->x, q->z) + MULT_FP(q->w, q->y))) * 2); - res.y = (MULT_FP(x, (MULT_FP(q->x, q->y) + MULT_FP(q->w,q->z))) * 2) - + (MULT_FP(y, (SQ_FP(q->w) - SQ_FP(q->x) + SQ_FP(q->y) - SQ_FP(q->z)))) - + (MULT_FP(z, (MULT_FP(q->y, q->z) - MULT_FP(q->w, q->x))) << 2); + res.y = (MULT_FP(x, (MULT_FP(q->x, q->y) + MULT_FP(q->w,q->z))) * 2) + + (MULT_FP(y, (SQ_FP(q->w) - SQ_FP(q->x) + SQ_FP(q->y) - SQ_FP(q->z)))) + + (MULT_FP(z, (MULT_FP(q->y, q->z) - MULT_FP(q->w, q->x))) << 2); - res.z = (MULT_FP(x, (MULT_FP(q->x, q->z) - MULT_FP(q->w, q->y)))* 2) - + (MULT_FP(y, (MULT_FP(q->y, q->z) + MULT_FP(q->w, q->x))) * 2) - + MULT_FP(z, (SQ_FP(q->w) - SQ_FP(q->x) - SQ_FP(q->y) + SQ_FP(q->z))); + res.z = (MULT_FP(x, (MULT_FP(q->x, q->z) - MULT_FP(q->w, q->y)))* 2) + + (MULT_FP(y, (MULT_FP(q->y, q->z) + MULT_FP(q->w, q->x))) * 2) + + MULT_FP(z, (SQ_FP(q->w) - SQ_FP(q->x) - SQ_FP(q->y) + SQ_FP(q->z))); - return res; + return res; } // res in quat p void multQ(struct Quaternions *p, struct Quaternions *q) { - if (p->x <= SHIFT_THRESHOLD_FP && p->x >= -SHIFT_THRESHOLD_FP + if (p->x <= SHIFT_THRESHOLD_FP && p->x >= -SHIFT_THRESHOLD_FP && p->y <= SHIFT_THRESHOLD_FP && p->y >= -SHIFT_THRESHOLD_FP && p->z <= SHIFT_THRESHOLD_FP && p->z >= -SHIFT_THRESHOLD_FP) { p = q; return; } - if (q->x <= SHIFT_THRESHOLD_FP && q->x >= -SHIFT_THRESHOLD_FP + if (q->x <= SHIFT_THRESHOLD_FP && q->x >= -SHIFT_THRESHOLD_FP && q->y <= SHIFT_THRESHOLD_FP && q->y >= -SHIFT_THRESHOLD_FP && q->z <= SHIFT_THRESHOLD_FP && q->z >= -SHIFT_THRESHOLD_FP) - return; + return; FIXED_POINT w = MULT_FP(p->w, q->w) - MULT_FP(p->x, q->x) - MULT_FP(p->y, q->y) - MULT_FP(p->z, q->z); @@ -251,8 +242,8 @@ multQ(struct Quaternions *p, struct Quaternions *q) uint16_t chooseColor(uint8_t c) { - if (c >= 1 && c <= NUM_FACES) - return c; + if (c >= 0 && c < NUM_FACES) + return c + 1; // palette 0 is bg else return 0; } @@ -260,106 +251,108 @@ chooseColor(uint8_t c) uint8_t chooseMainFace() { - int total = 0; - int faces[NUM_FACES] = {0}; + int total = 0; + int faces[NUM_FACES] = {0}; - for (int k = 0; k < VWIDTH * VHEIGHT; ++k) - if (output[k] >= 0 && output[k] < NUM_FACES) { - faces[output[k]]++; - ++total; - } + for (int k = 0; k < VWIDTH * VHEIGHT; ++k) + if (vertices[k] >= 0 && vertices[k] < NUM_FACES) { + faces[vertices[k]]++; + ++total; + } - int max = 0, idx = 0; - for (int k = 0; k < NUM_FACES; ++k) - if (faces[k] > max) { - max = faces[k]; - idx = k; - } + int max = 0, idx = 0; + for (int k = 0; k < NUM_FACES; ++k) + if (faces[k] > max) { + max = faces[k]; + idx = k; + } - frontFacingFace = max > total * 0.9 ? idx : -1; - return frontFacingFace; + frontFacingFace = max > total * 0.9 ? idx : -1; + return frontFacingFace; } +// ISSUE the 4 vertices rendered do not make a convex quad +// we have to switch 2 vertices for that +#pragma GCC uint8_t -isInQuad(uint8_t curr[2], uint8_t points[8]) +isInQuad(const uint16_t x, const uint16_t y, uint8_t current_face) { - uint8_t pos = 0, neg = 0; - uint8_t x = curr[0]; - uint8_t y = curr[1];; - int d; + uint16_t *points = (uint16_t *)&vertices[current_face * 8]; + // little hack - for (uint8_t i = 0; i < 4; ++i) { - if (points[2 * i] == curr[0] && points[2 * i + 1] == curr[1]) - return 1; + uint16_t tmpX = points[6], tmpY = points[7]; + points[6] = points[4]; + points[7] = points[5]; + points[4] = tmpX; + points[5] = tmpY; - //Form a segment between the i'th point - uint8_t x1 = points[2 * i]; - uint8_t y1 = points[2 * i + 1]; + uint8_t pos = 0, neg = 0; + int32_t d; - //And the i+1'th, or if i is the last, with the first point - uint8_t i2 = (i + 1) % 4; + for (uint8_t i = 0; i < 4; ++i) { + if (points[2 * i] == x && points[2 * i + 1] == y) + return 1; - uint8_t x2 = points[2 * i2]; - uint8_t y2 = points[2 * i2 + 1]; + //Form a segment between the i'th point + int32_t x1 = points[2 * i]; + int32_t y1 = points[2 * i + 1]; + + //And the i+1'th, or if i is the last, with the first point + uint8_t i2 = (i + 1) % 4; + + int32_t x2 = points[2 * i2]; + int32_t y2 = points[2 * i2 + 1]; - //Compute the cross product - d = (x - x1) * (y2 - y1) - (y - y1) * (x2 - x1); + //Compute the cross product + d = (x - x1) * (y2 - y1) - (y - y1) * (x2 - x1); - if (d > 0) ++pos; - if (d < 0) ++neg; + if (d > 0) ++pos; + if (d < 0) ++neg; - //If the sign changes, then point is outside - if (pos > 0 && neg > 0) - return 0; - } + //If the sign changes, then point is outside + if (pos > 0 && neg > 0) + return 0; + } - return 1; + return 1; } void -fill_quads(uint8_t *points, uint8_t current_face) +fillQuads(uint8_t current_face) { - uint8_t top = 0, bot = 0, left = 0, right = 0; - for (uint8_t x = 0 ; x < 8 ; ++x) { - if (x % 2 == 0) { - if (points[x] > right) - right = points[x]; - if (points[x] < left) - left = points[x]; + uint16_t top = UINT16_MAX, bot = 0, left = UINT16_MAX, right = 0; + for (uint8_t k = 0 ; k < 8 ; ++k) { + const uint16_t item = vertices[current_face * 8 + k]; + + if (k & 1) { + if (item > bot) + bot = item; + if (item < top) + top = item; } else { - if (points[x] > bot) - bot = points[x]; - if (points[x] < top) - top = points[x]; + if (item > right) + right = item; + if (item < left) + left = item; + } + } + + for (uint16_t y = top ; y <= bot ; ++y) { + for (uint16_t x = left ; x <= right ; ++x) { + if (isInQuad(x, y, current_face)) + PLOT_COORD(x, y, current_face); } } - for (int y = top ; y < bot ; ++y) { - for (int x = left ; x < right ; ++x) { - uint8_t curr[2] = {x, y}; - if (isInQuad(curr, points)) - PLOT_COORD(x, y, current_face + 1); - } - } } uint8_t -detect(uint8_t *points, uint8_t current_face) { - uint8_t i = 0; - for (uint8_t y = 0; y < VHEIGHT; ++y) { - for (uint8_t x = 0; x < VWIDTH; ++x) { - if (output[COORD2INDEX(x, y)] != current_face) - continue; - // only 4 points are ploted - points[i] = x; - points[i + 1] = y; - i += 2; - } - } - - for (uint8_t x = 0 ; x < 8 ; ++x) - if (points[x] == 0) +detect(uint8_t current_face) +{ + for (uint8_t k = current_face * 8; k < current_face * 8 + 8; ++k) + if (vertices[k] == UINT16_MAX) return 0; + return 1; } @@ -372,222 +365,211 @@ comp(const void *p1, const void *p2) { } void -detect_and_fill_quads() +detectAndFillQuads() { - qsort(maxZbufByColor, NUM_FACES, 2 * sizeof(FIXED_POINT), comp); - for (uint8_t idx = 0 ; idx < NUM_FACES ; ++idx) { - uint8_t current_face = maxZbufByColor[2 * idx + 1]; - uint8_t points[8] = { 0 }; - if (detect(points, current_face)) - fill_quads(points, current_face); - } + qsort((FIXED_POINT *)zBuffer, NUM_FACES, 2 * sizeof(FIXED_POINT), comp); + for (uint8_t idx = 0 ; idx < NUM_FACES ; ++idx) { + char ch = zBuffer[2 * idx + 1]; + if (detect(ch)) + fillQuads(ch); + } } void printAscii() { - detect_and_fill_quads(); + detectAndFillQuads(); flipBuffers(); - - // DISPLAY POINTS - //for (int i = 0; i < VHEIGHT; ++i) { - // for (int j = 0; j < VWIDTH; ++j) { - // uint8_t prevc = 0; - // uint8_t c = output[i * VWIDTH + j]; - // MEM_VRAM_MODE4[i * GBA_SCREEN_W + j] = chooseColor(c); - // } - //} } void rotateCube(FIXED_POINT cubeX, FIXED_POINT cubeY, FIXED_POINT cubeZ, uint8_t ch) { - struct Quaternions q = mult(&Current, cubeX, cubeY, cubeZ); + struct Quaternions q = mult(&Current, cubeX, cubeY, cubeZ); - int x = q.x >> FP; - int y = q.y >> FP; + uint32_t x = q.x >> FP; + uint32_t y = q.y >> FP; - // not fixed point yet!! - float invZ = (1 << FP) / (float)(q.z + K2 * (1 << FP)); + // not fixed point yet!! + float invZ = (1 << FP) / (float)(q.z + K2 * (1 << FP)); - int screenX = (int)(VWIDTH * 0.5) + (int)((x) * K1) * invZ; - int screenY = (int)(VHEIGHT * 0.5) + (int)((y) * K1) * invZ; - //TODO luminescence + int32_t screenX = CUBE_WIDTH * 2 + (int32_t)((x) * K1) * invZ; + int32_t screenY = CUBE_WIDTH * 2 + (int32_t)((y) * K1) * invZ; + //TODO luminescence - if (screenX > VWIDTH || screenX < 0) return; + if (screenX > GBA_SCREEN_W || screenX < 0 + || screenY > GBA_SCREEN_H || screenY < 0) return; - int idx = screenY * VWIDTH + screenX; - if (idx >= 0 && idx < VWIDTH * VHEIGHT) { - invZ = FLOAT2FIXED(invZ); - if (zBuffer[idx] < invZ) { - zBuffer[idx] = invZ; - output[idx] = ch; - if (invZ > maxZbufByColor[ch]) { - maxZbufByColor[2 * ch] = invZ; - maxZbufByColor[2 * ch + 1] = ch; //palette[0] is bg - } - } - } + FIXED_POINT invZFixed = FLOAT2FIXED(invZ); + uint8_t firstEmptyVertex = ch * 8; + for ( ; vertices[firstEmptyVertex] != UINT16_MAX + && firstEmptyVertex - ch * 8 < 8 ; firstEmptyVertex+=2); + + vertices[firstEmptyVertex] = screenX; + vertices[firstEmptyVertex + 1] = screenY; + + if (zBuffer[2 * ch] < invZFixed) { + zBuffer[2 * ch] = invZFixed; + zBuffer[2 * ch + 1] = ch; + } } void interpolate(struct Quaternions *qa, struct Quaternions *qb) { - frontFacingFace = -1; - float cosHalfTheta = - FIXED2FLOAT(MULT_FP(qa->w, qb->w) + - MULT_FP(qa->x, qb->x) + - MULT_FP(qa->y, qb->y) + - MULT_FP(qa->z, qb->z)); - //if qa = qb or qa = -qb then theta = 0 and we can return qa - if (cosHalfTheta >= 1.0 || cosHalfTheta <= -1.0) { - goto exit; - } - if (cosHalfTheta < 0) { - qb->w = -qb->w; - qb->x = -qb->x; - qb->y = -qb->y; - qb->z = qb->z; - cosHalfTheta = -cosHalfTheta; - } + frontFacingFace = -1; + float cosHalfTheta = + FIXED2FLOAT(MULT_FP(qa->w, qb->w) + + MULT_FP(qa->x, qb->x) + + MULT_FP(qa->y, qb->y) + + MULT_FP(qa->z, qb->z)); + //if qa = qb or qa = -qb then theta = 0 and we can return qa + if (cosHalfTheta >= 1.0 || cosHalfTheta <= -1.0) { + goto exit; + } + if (cosHalfTheta < 0) { + qb->w = -qb->w; + qb->x = -qb->x; + qb->y = -qb->y; + qb->z = qb->z; + cosHalfTheta = -cosHalfTheta; + } - float halfTheta = acos(cosHalfTheta); - float sinHalfTheta = sqrt(1.0 - cosHalfTheta * cosHalfTheta); - //if theta = 180 degrees then result is not fully defined - // we could rotate around any axis normal to qa or qb - if (sinHalfTheta < 0.01 && sinHalfTheta > -0.01) { - qa->w = ((qa->w >> 1) + (qb->w >> 1)); - qa->x = ((qa->x >> 1) + (qb->x >> 1)); - qa->y = ((qa->y >> 1) + (qb->y >> 1)); - qa->z = ((qa->z >> 1) + (qb->z >> 1)); - goto exit; - } + float halfTheta = acos(cosHalfTheta); + float sinHalfTheta = sqrt(1.0 - cosHalfTheta * cosHalfTheta); + //if theta = 180 degrees then result is not fully defined + // we could rotate around any axis normal to qa or qb + if (sinHalfTheta < 0.01 && sinHalfTheta > -0.01) { + qa->w = ((qa->w >> 1) + (qb->w >> 1)); + qa->x = ((qa->x >> 1) + (qb->x >> 1)); + qa->y = ((qa->y >> 1) + (qb->y >> 1)); + qa->z = ((qa->z >> 1) + (qb->z >> 1)); + goto exit; + } - FIXED_POINT ratioA = FLOAT2FIXED(sin((1 - FIXED2FLOAT(interpolationStep)) * halfTheta) / sinHalfTheta); - FIXED_POINT ratioB = FLOAT2FIXED(sin(FIXED2FLOAT(interpolationStep) * halfTheta) / sinHalfTheta); + FIXED_POINT ratioA = FLOAT2FIXED(sin((1 - FIXED2FLOAT(interpolationStep)) * halfTheta) / sinHalfTheta); + FIXED_POINT ratioB = FLOAT2FIXED(sin(FIXED2FLOAT(interpolationStep) * halfTheta) / sinHalfTheta); - qa->w = (MULT_FP(qa->w, ratioA) + MULT_FP(qb->w, ratioB)); - qa->x = (MULT_FP(qa->x, ratioA) + MULT_FP(qb->x, ratioB)); - qa->y = (MULT_FP(qa->y, ratioA) + MULT_FP(qb->y, ratioB)); - qa->z = (MULT_FP(qa->z, ratioA) + MULT_FP(qb->z, ratioB)); + qa->w = (MULT_FP(qa->w, ratioA) + MULT_FP(qb->w, ratioB)); + qa->x = (MULT_FP(qa->x, ratioA) + MULT_FP(qb->x, ratioB)); + qa->y = (MULT_FP(qa->y, ratioA) + MULT_FP(qb->y, ratioB)); + qa->z = (MULT_FP(qa->z, ratioA) + MULT_FP(qb->z, ratioB)); exit: - interpolationStep += ACTION_STEP_FP; + interpolationStep += ACTION_STEP_FP; } void handleAngle(uint8_t input) { - // TODO - if (currentlyMoving == 0) { - currentlyMoving = input; + // TODO + if (currentlyMoving == 0) { + currentlyMoving = input; struct Quaternions tmp; - switch (input) { - case 'w': - case 'W': + switch (input) { + case 'w': + case 'W': tmp = GET_ROTATE_X_Q(M_PI_2); - break; - case 'a': - case 'A': - tmp = GET_ROTATE_Y_Q(-M_PI_2); - break; - case 's': - case 'S': - tmp = GET_ROTATE_X_Q(-M_PI_2); - break; - case 'd': - case 'D': - tmp = GET_ROTATE_Y_Q(M_PI_2); - break; - case 'q': - case 'Q': - tmp = GET_ROTATE_Z_Q(-M_PI_2); - break; - case 'e': - case 'E': - tmp = GET_ROTATE_Z_Q(M_PI_2); - break; - default: - currentlyMoving = 0; + break; + case 'a': + case 'A': + tmp = GET_ROTATE_Y_Q(-M_PI_2); + break; + case 's': + case 'S': + tmp = GET_ROTATE_X_Q(-M_PI_2); + break; + case 'd': + case 'D': + tmp = GET_ROTATE_Y_Q(M_PI_2); + break; + case 'q': + case 'Q': + tmp = GET_ROTATE_Z_Q(-M_PI_2); + break; + case 'e': + case 'E': + tmp = GET_ROTATE_Z_Q(M_PI_2); + break; + default: + currentlyMoving = 0; return; - //TODO idle movement - } + //TODO idle movement + } multQ(&tmp, &Target); Target = tmp; - normalize(&Target); - } else { - if (interpolationStep < (1 << FP) ) { - interpolate(&Current, &Target); - normalize(&Current); - } - else { - Current = Target; - interpolationStep = 0; - currentlyMoving = 0; - } - } + normalize(&Target); + } else { + if (interpolationStep < (1 << FP) ) { + interpolate(&Current, &Target); + normalize(&Current); + } + else { + Current = Target; + interpolationStep = 0; + currentlyMoving = 0; + } + } } uint8_t getInput() { - // TODO - uint8_t c = 'd'; - handleAngle(c); - return c; + // TODO + uint8_t c = 'd'; + handleAngle(c); + return c; } int main() { - REG_DISPCNT = DISPCNT_BG_MODE(4) | DISPCNT_BG2_ENABLE; - - Current = GET_ROTATE_Z_Q(0); - + REG_DISPCNT = DISPCNT_BG_MODE(4) | DISPCNT_BG2_ENABLE; + Current = GET_ROTATE_Z_Q(0); init_colors(); - while (1) { - memset(MEM_VRAM_MODE4, 0, GBA_SCREEN_H * GBA_SCREEN_W); - memset(output, NUM_FACES, VWIDTH * VHEIGHT); - memset(maxZbufByColor, 0, 2 * sizeof(FIXED_POINT) * NUM_FACES); - memset(zBuffer, 0xffffffff, VWIDTH * VHEIGHT * sizeof(FIXED_POINT)); + while (1) { + memset(MEM_VRAM_MODE4, 0, GBA_SCREEN_H * GBA_SCREEN_W); + memset((uint16_t *)vertices, UINT16_MAX, sizeof(uint16_t) * NUM_FACES * 4 * 2); + //zBuff is not correct data struct, need a map or smth + memset((uint16_t *)zBuffer, 0, NUM_FACES * 2 * sizeof(FIXED_POINT)); - for (FIXED_POINT cubeX = -CUBE_WIDTH_FP + 2 * (1 << FP); - cubeX <= CUBE_WIDTH_FP - 2 * (1 << FP); cubeX += STEP_FP - 4 * (1 << FP)) { - for (FIXED_POINT cubeY = -CUBE_WIDTH_FP + 2 * (1 << FP); - cubeY <= CUBE_WIDTH_FP - 2 * (1 << FP); cubeY += STEP_FP - 4 * (1 << FP)) { - switch (frontFacingFace) { - case FACE_FRONT: - rotateCube(cubeX, cubeY, -CUBE_WIDTH_FP, FACE_FRONT); - break; - case FACE_LEFT: - rotateCube(-CUBE_WIDTH_FP, cubeX, cubeY, FACE_LEFT); - break; - case FACE_RIGHT: - rotateCube(CUBE_WIDTH_FP, cubeX, cubeY, FACE_RIGHT); - break; - case FACE_BOTTOM: - rotateCube(cubeX, -CUBE_WIDTH_FP, cubeY, FACE_BOTTOM); - break; - case FACE_TOP: - rotateCube(cubeX, CUBE_WIDTH_FP, cubeY, FACE_TOP); - break; - case FACE_BACK: - rotateCube(cubeX, cubeY, CUBE_WIDTH_FP, FACE_BACK); - break; - default: // idk render all - rotateCube(cubeX, cubeY, -CUBE_WIDTH_FP, FACE_FRONT); - rotateCube(-CUBE_WIDTH_FP, cubeX, cubeY, FACE_LEFT); - rotateCube(CUBE_WIDTH_FP, cubeX, cubeY, FACE_RIGHT); - rotateCube(cubeX, -CUBE_WIDTH_FP, cubeY, FACE_TOP); - rotateCube(cubeX, CUBE_WIDTH_FP, cubeY, FACE_BOTTOM); - rotateCube(cubeX, cubeY, CUBE_WIDTH_FP, FACE_BACK); - } - } - } + for (FIXED_POINT cubeX = -CUBE_WIDTH_FP + 1 * (1 << FP); + cubeX <= CUBE_WIDTH_FP - 1 * (1 << FP); cubeX += STEP_FP - 2 * (1 << FP)) { + for (FIXED_POINT cubeY = -CUBE_WIDTH_FP + 1 * (1 << FP); + cubeY <= CUBE_WIDTH_FP - 1 * (1 << FP); cubeY += STEP_FP - 2 * (1 << FP)) { + switch (frontFacingFace) { + case FACE_FRONT: + rotateCube(cubeX, cubeY, -CUBE_WIDTH_FP, FACE_FRONT); + break; + case FACE_LEFT: + rotateCube(-CUBE_WIDTH_FP, cubeX, cubeY, FACE_LEFT); + break; + case FACE_RIGHT: + rotateCube(CUBE_WIDTH_FP, cubeX, cubeY, FACE_RIGHT); + break; + case FACE_BOTTOM: + rotateCube(cubeX, -CUBE_WIDTH_FP, cubeY, FACE_BOTTOM); + break; + case FACE_TOP: + rotateCube(cubeX, CUBE_WIDTH_FP, cubeY, FACE_TOP); + break; + case FACE_BACK: + rotateCube(cubeX, cubeY, CUBE_WIDTH_FP, FACE_BACK); + break; + default: // idk render all + rotateCube(cubeX, cubeY, -CUBE_WIDTH_FP, FACE_FRONT); + rotateCube(-CUBE_WIDTH_FP, cubeX, cubeY, FACE_LEFT); + rotateCube(CUBE_WIDTH_FP, cubeX, cubeY, FACE_RIGHT); + rotateCube(cubeX, -CUBE_WIDTH_FP, cubeY, FACE_TOP); + rotateCube(cubeX, CUBE_WIDTH_FP, cubeY, FACE_BOTTOM); + rotateCube(cubeX, cubeY, CUBE_WIDTH_FP, FACE_BACK); + } + } + } - printAscii(); - getInput(); - } + printAscii(); + getInput(); + } } From a1cd49180b300980840c95ed88000d468b792380 Mon Sep 17 00:00:00 2001 From: violette Date: Sat, 4 Oct 2025 18:40:15 -0400 Subject: [PATCH 4/4] fix: now rotating just fine --- source/main.c | 130 +++++++++++++++++++++++--------------------------- 1 file changed, 59 insertions(+), 71 deletions(-) diff --git a/source/main.c b/source/main.c index 76472d9..c561d8b 100644 --- a/source/main.c +++ b/source/main.c @@ -67,13 +67,6 @@ flipBuffers() } } -void -putPx(uint16_t x, uint16_t y, uint8_t c) -{ - uint16_t pos = (GBA_SCREEN_W * y + x); - buffer[pos] = c; -} - /////////////////////////////////////////////////////////// #include @@ -82,8 +75,6 @@ putPx(uint16_t x, uint16_t y, uint8_t c) #include #include -#define VWIDTH 25 -#define VHEIGHT 25 #define CUBE_WIDTH 10 #define CUBE_WIDTH_FP ((1 << FP) * CUBE_WIDTH) @@ -103,21 +94,16 @@ enum faces { #define ACTION_STEP 0.1 #define ACTION_STEP_FP ((1 << FP) * ACTION_STEP) -#define SCALE 3 // how much is our initial render scaled +#define SCALE 5 // how much is our initial render scaled -volatile FIXED_POINT K1 = 20; -volatile FIXED_POINT K2 = (2 * CUBE_WIDTH) + 10; +#define K1 (20) +#define K2 (2 * CUBE_WIDTH + 10) -#define MULT_FP(a,b) ((a * b) >> FP) +#define MULT_FP(a, b) ((a * b) >> FP) #define SQ(n) (n * n) #define SQ_FP(n) (MULT_FP(n, n)) -#define PLOT_COORD(x, y, c) \ - for (uint8_t i = 0 ; i < SCALE ; ++i) \ - for (uint8_t j = 0 ; j < SCALE ; ++j) \ - putPx(x * SCALE + i, j + (SCALE * y), chooseColor(c)); - #define GET_ROTATE_X_Q(a) ({ float _a = (a) ; \ struct Quaternions q = {}; q.w = FLOAT2FIXED(cos(_a * .5)); \ q.x = FLOAT2FIXED(sin(_a * .5)); q; }) @@ -149,6 +135,25 @@ init_colors() PALETTE[lastPaletteIndex] = color_order[lastPaletteIndex]; } +uint8_t +chooseColor(uint8_t c) +{ + if (c >= 0 && c < NUM_FACES) + return c + 1; // palette 0 is bg + else + return 0; +} + +void +putPx(uint16_t x, uint16_t y, uint8_t c) +{ + for (uint8_t i = 0 ; i < SCALE ; ++i) + for (uint8_t j = 0 ; j < SCALE ; ++j) { + uint16_t pos = GBA_SCREEN_W * (y * SCALE + j) + x * SCALE + i; + buffer[pos] = chooseColor(c); + } +} + struct { uint8_t x; uint8_t y; @@ -177,7 +182,7 @@ normalize(struct Quaternions *q) { float n = sqrt(FIXED2FLOAT(SQ_FP(q->w) + SQ_FP(q->x) + SQ_FP(q->y) + SQ_FP(q->z))); - if (n == 0 || n == 1) + if (n == 0.|| n == 1.) return; q->w = FLOAT2FIXED(FIXED2FLOAT(q->w) / n); @@ -192,17 +197,18 @@ mult(struct Quaternions *q, FIXED_POINT x, FIXED_POINT y, FIXED_POINT z) //p = q * p * qbar struct Quaternions res; + // << 1 <=> * 2 res.w = 0; res.x = MULT_FP(x, (SQ_FP(q->w) + SQ_FP(q->x) - SQ_FP(q->y) - SQ_FP(q->z))) - + (MULT_FP(y, (MULT_FP(q->x, q->y) - MULT_FP(q->w, q->z))) * 2) - + (MULT_FP(z, (MULT_FP(q->x, q->z) + MULT_FP(q->w, q->y))) * 2); + + (MULT_FP(y, (MULT_FP(q->x, q->y) - MULT_FP(q->w, q->z))) << 1) + + (MULT_FP(z, (MULT_FP(q->x, q->z) + MULT_FP(q->w, q->y))) << 1); - res.y = (MULT_FP(x, (MULT_FP(q->x, q->y) + MULT_FP(q->w,q->z))) * 2) + res.y = (MULT_FP(x, (MULT_FP(q->x, q->y) + MULT_FP(q->w,q->z))) << 1) + (MULT_FP(y, (SQ_FP(q->w) - SQ_FP(q->x) + SQ_FP(q->y) - SQ_FP(q->z)))) - + (MULT_FP(z, (MULT_FP(q->y, q->z) - MULT_FP(q->w, q->x))) << 2); + + (MULT_FP(z, (MULT_FP(q->y, q->z) - MULT_FP(q->w, q->x))) << 1); - res.z = (MULT_FP(x, (MULT_FP(q->x, q->z) - MULT_FP(q->w, q->y)))* 2) - + (MULT_FP(y, (MULT_FP(q->y, q->z) + MULT_FP(q->w, q->x))) * 2) + res.z = (MULT_FP(x, (MULT_FP(q->x, q->z) - MULT_FP(q->w, q->y))) << 1) + + (MULT_FP(y, (MULT_FP(q->y, q->z) + MULT_FP(q->w, q->x))) << 1) + MULT_FP(z, (SQ_FP(q->w) - SQ_FP(q->x) - SQ_FP(q->y) + SQ_FP(q->z))); return res; @@ -239,52 +245,17 @@ multQ(struct Quaternions *p, struct Quaternions *q) } -uint16_t -chooseColor(uint8_t c) -{ - if (c >= 0 && c < NUM_FACES) - return c + 1; // palette 0 is bg - else - return 0; -} - uint8_t chooseMainFace() { - int total = 0; - int faces[NUM_FACES] = {0}; - - for (int k = 0; k < VWIDTH * VHEIGHT; ++k) - if (vertices[k] >= 0 && vertices[k] < NUM_FACES) { - faces[vertices[k]]++; - ++total; - } - - int max = 0, idx = 0; - for (int k = 0; k < NUM_FACES; ++k) - if (faces[k] > max) { - max = faces[k]; - idx = k; - } - - frontFacingFace = max > total * 0.9 ? idx : -1; - return frontFacingFace; + // TODO + return 0; } -// ISSUE the 4 vertices rendered do not make a convex quad -// we have to switch 2 vertices for that -#pragma GCC uint8_t isInQuad(const uint16_t x, const uint16_t y, uint8_t current_face) { uint16_t *points = (uint16_t *)&vertices[current_face * 8]; - // little hack - - uint16_t tmpX = points[6], tmpY = points[7]; - points[6] = points[4]; - points[7] = points[5]; - points[4] = tmpX; - points[5] = tmpY; uint8_t pos = 0, neg = 0; int32_t d; @@ -294,15 +265,14 @@ isInQuad(const uint16_t x, const uint16_t y, uint8_t current_face) return 1; //Form a segment between the i'th point - int32_t x1 = points[2 * i]; - int32_t y1 = points[2 * i + 1]; + uint16_t x1 = points[2 * i]; + uint16_t y1 = points[2 * i + 1]; //And the i+1'th, or if i is the last, with the first point uint8_t i2 = (i + 1) % 4; - int32_t x2 = points[2 * i2]; - int32_t y2 = points[2 * i2 + 1]; - + uint16_t x2 = points[2 * i2]; + uint16_t y2 = points[2 * i2 + 1]; //Compute the cross product d = (x - x1) * (y2 - y1) - (y - y1) * (x2 - x1); @@ -318,9 +288,27 @@ isInQuad(const uint16_t x, const uint16_t y, uint8_t current_face) return 1; } +// the 4 vertices rendered do not make a convex quad +// we have to switch 2 vertices for that +// only works because we render 4 points left to right +void +makeConvex(uint16_t *points) +{ + // little hack + + uint16_t tmpX = points[6], tmpY = points[7]; + points[6] = points[4]; + points[7] = points[5]; + points[4] = tmpX; + points[5] = tmpY; + +} + void fillQuads(uint8_t current_face) { + makeConvex((uint16_t *)&vertices[current_face * 8]); + uint16_t top = UINT16_MAX, bot = 0, left = UINT16_MAX, right = 0; for (uint8_t k = 0 ; k < 8 ; ++k) { const uint16_t item = vertices[current_face * 8 + k]; @@ -338,10 +326,10 @@ fillQuads(uint8_t current_face) } } - for (uint16_t y = top ; y <= bot ; ++y) { + for (uint16_t y = top ; y <= bot; ++y) { for (uint16_t x = left ; x <= right ; ++x) { if (isInQuad(x, y, current_face)) - PLOT_COORD(x, y, current_face); + putPx(x, y, current_face); } } } @@ -517,7 +505,7 @@ uint8_t getInput() { // TODO - uint8_t c = 'd'; + uint8_t c = 's'; handleAngle(c); return c; } @@ -533,7 +521,7 @@ main() memset(MEM_VRAM_MODE4, 0, GBA_SCREEN_H * GBA_SCREEN_W); memset((uint16_t *)vertices, UINT16_MAX, sizeof(uint16_t) * NUM_FACES * 4 * 2); //zBuff is not correct data struct, need a map or smth - memset((uint16_t *)zBuffer, 0, NUM_FACES * 2 * sizeof(FIXED_POINT)); + memset((FIXED_POINT *)zBuffer, 0, NUM_FACES * 2 * sizeof(FIXED_POINT)); for (FIXED_POINT cubeX = -CUBE_WIDTH_FP + 1 * (1 << FP); cubeX <= CUBE_WIDTH_FP - 1 * (1 << FP); cubeX += STEP_FP - 2 * (1 << FP)) {