commit c76c3ad493685bc3f6593ce23f00da5f1ea1cae3
parent 79e0ebcdf3c6f14cb2967dadb3c6f4888b786248
Author: noone <vazkats@gmail.com>
Date: Tue, 18 Mar 2025 00:13:32 +0200
Long time no see.
- I managed to fix the drawing algorithm and now evertything renders pretty much good
- Something is wrong though with the upper text of the logo. It's not shown. I have to figure out why..
Diffstat:
| M | .gitignore | | | 1 | + |
| M | makefile | | | 3 | ++- |
| M | src/defs.h | | | 4 | ++-- |
| M | src/gpu.c | | | 126 | +++++++++++++++++++++++++++++++++++-------------------------------------------- |
| M | src/main.c | | | 89 | +++++++++++++++++++++++++++++++++++++------------------------------------------ |
| M | src/sr.c | | | 280 | +++++++++++++++++++++++++++---------------------------------------------------- |
| M | src/sr.h | | | 3 | +++ |
| M | src/tags | | | 39 | +++++++++++++++++++++++++++++++++++++-- |
| M | src/util.c | | | 50 | ++++++++++++++++++++++++++++++-------------------- |
| M | src/util.h | | | 7 | +++++++ |
10 files changed, 273 insertions(+), 329 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -2,3 +2,4 @@
bin/
a.out
test.c
+compile_flags.txt
diff --git a/makefile b/makefile
@@ -1,5 +1,6 @@
+mac:
+ cc -g src/*.c -o bin/ultimecia -I/opt/homebrew/include/ -L/opt/homebrew/lib/ -lSDL2
bsd:
cc -O0 -g src/*.c -o bin/ultimecia -I/usr/local/include -L/usr/local/lib -lSDL2
-
win:
cc -O3 -g src/*.c -o bin/ultimecia -I/mingw64/include/SDL2 -L/mingw64/lib -lmingw32 -lSDL2main -lSDL2
diff --git a/src/defs.h b/src/defs.h
@@ -7,7 +7,7 @@ static const int debug = 0; // Set to 0 to disable debug prints
/* #define PANIC(...) do { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); } while(0) */
/* We should get rid of this */
-#define DEBUG 1;
+#define DEBUG 0;
#define LOG_NONE 0
#define LOG_DEBUG 1
@@ -16,7 +16,7 @@ static const int debug = 0; // Set to 0 to disable debug prints
#define LOG_ERROR 4
// Set the current log level
-#define CURRENT_LOG_LEVEL LOG_DEBUG
+#define CURRENT_LOG_LEVEL LOG_ERROR
#define LOG(level, fmt, ...) \
do { if (level >= CURRENT_LOG_LEVEL) fprintf(stderr, fmt, __VA_ARGS__); } while (0)
diff --git a/src/gpu.c b/src/gpu.c
@@ -49,6 +49,9 @@ GPU_status(GPU* gpu)
/* Bit 14 not supported */
r |= ((u32)gpu->texture_disable) << 15;
r |= HOR_RES_into_status(gpu->hres);
+ /* If we don't emulate bit 31 correctly setting vres to 1
+ locks the BIOS. 4.17 on the guide.
+ */
//r |= ((u32)gpu->vres) << 19;
r |= ((u32)gpu->vmode) << 20;
r |= ((u32)gpu->display_depth) << 21;
@@ -57,14 +60,14 @@ GPU_status(GPU* gpu)
r |= ((u32)gpu->interrupt) << 24;
/* Always GPU is ready */
- r |= 1 << 26;
+ r |= 1 << 26;
r |= 1 << 27;
r |= 1 << 28;
r |= ((u32) gpu->dma_direction) << 29;
/* Ignore odd lines for now */
- r |= 0 << 31;
+ r |= 0 << 31;
switch(gpu->dma_direction)
{
@@ -80,7 +83,7 @@ GPU_status(GPU* gpu)
return r;
}
-void
+void
GPU_gp1(GPU* gpu, u32 val)
{
@@ -104,7 +107,7 @@ GPU_gp1(GPU* gpu, u32 val)
}
-void
+void
GPU_gp1_reset(GPU* gpu, u32 val)
{
REN* tmp = gpu->ren;
@@ -162,7 +165,7 @@ GPU_gp1_display_vram_start(GPU* gpu, u32 val)
gpu->display_vram_y_start = (u16)((val >> 10) & 0x1ff);
}
-void
+void
GPU_gp1_dma_direction(GPU* gpu, u32 val)
{
switch (val & 3) {
@@ -174,7 +177,7 @@ GPU_gp1_dma_direction(GPU* gpu, u32 val)
}
}
-void
+void
GPU_gp1_display_mode(GPU* gpu, u32 val)
{
u8 hr1, hr2;
@@ -192,13 +195,13 @@ GPU_gp1_display_mode(GPU* gpu, u32 val)
fprintf(stderr, "Unsupported display mode %08X\n", val), exit(EXIT_FAILURE);
}
-void
+void
GPU_gp0(GPU* gpu, u32 val)
{
if (gpu->gp0_words_remaining == 0) {
u32 opcode, len;
void (*method)(GPU*);
-
+
opcode = (val >> 24) & 0xff;
switch (opcode) {
@@ -227,12 +230,12 @@ GPU_gp0(GPU* gpu, u32 val)
gpu->gp0_words_remaining -= 1;
switch (gpu->gp0_mode) {
- case GP0_MODE_COMMAND:
+ case GP0_MODE_COMMAND:
GPU_CMD_BUFFER_push_word(&gpu->gp0_command, val);
if (gpu->gp0_words_remaining == 0)
gpu->gp0_command_method(gpu);
break;
- case GP0_MODE_IMAGE_LOAD:
+ case GP0_MODE_IMAGE_LOAD:
if (gpu->gp0_words_remaining == 0)
gpu->gp0_mode = GP0_MODE_COMMAND;
break;
@@ -243,8 +246,8 @@ void GPU_gp0_nop(GPU* gpu) {}
void GPU_gp0_clear_cache(GPU* gpu) { /* Not implemented */}
-void
-GPU_gp0_image_load(GPU* gpu)
+void
+GPU_gp0_image_load(GPU* gpu)
{
u32 res, width, height, imgsize;
@@ -267,9 +270,6 @@ GPU_gp0_draw_mode(GPU* gpu)
gpu->page_base_y = (u8)((val >> 4) & 1);
gpu->semi_transparency = (u8)((val >> 5) & 3);
- /* Thought i would try ternary but I am not sure if this actually works
- gpu->texture_depth = (val >> 7 & 3) ? 0 ? TD_T4BIT ? 1 ? TD_T8BIT ? 2 ? TD_T15BIT : 0 : 0 : 0 : 0 : 0 : 0;*/
-
switch ((val >> 7) & 3)
{
case 0: gpu->texture_depth = TD_T4BIT; break;
@@ -318,7 +318,7 @@ GPU_gp0_drawing_offset(GPU* gpu)
gpu->drawing_x_offset = ((i16)(x << 5)) >> 5;
gpu->drawing_y_offset = ((i16)(y << 5)) >> 5;
- /*
+ /*
This is a hack because I haven't implemented gpu timings yet.
But gp0_drawing_offset is called every frame apparently.
*/
@@ -347,32 +347,23 @@ GPU_gp0_mask_bit_setting(GPU* gpu)
gpu->preserve_masked_pixels = (val & 2) != 0;
}
-void
+void
GPU_gp0_quad_mono_opaque(GPU* gpu)
{
- // LOG(LOG_DEBUG, "Draw quad pls\n", NULL);
- // ivec2 positions[4];
- // C colors[4];
-
- // positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]);
- // positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[2]);
- // positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[3]);
- // positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[4]);
- // LOG(LOG_DEBUG, "Vertex 0, x: %d, y: %d\n", positions[0].x, positions[0].y);
- // LOG(LOG_DEBUG, "Vertex 1, x: %d, y: %d\n", positions[1].x, positions[1].y);
- // LOG(LOG_DEBUG, "Vertex 2, x: %d, y: %d\n", positions[2].x, positions[2].y);
- // LOG(LOG_DEBUG, "Vertex 3, x: %d, y: %d\n", positions[3].x, positions[3].y);
-
- // colors[0] = colors[1] = colors[2] = colors[3] = COLOR_from_gp0(gpu->gp0_command.buffer[0]);
- // LOG(LOG_DEBUG, "Color 0, r: %d, g: %d, b: %d\n", colors[0].r, colors[0].g, colors[0].b);
- // //LOG(LOG_DEBUG, "Color 1, x: %d, y: %d\n", positions[1].x, positions[1].y);
- // //LOG(LOG_DEBUG, "Color 2, x: %d, y: %d\n", positions[2].x, positions[2].y);
- // //LOG(LOG_DEBUG, "Color 3, x: %d, y: %d\n", positions[3].x, positions[3].y);
-
- // REN_push_quad(gpu->ren, positions, colors);
+ ivec2 positions[4];
+ C colors[4];
+
+ positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]);
+ positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[2]);
+ positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[3]);
+ positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[4]);
+
+ colors[0] = colors[1] = colors[2] = colors[3] = COLOR_from_gp0(gpu->gp0_command.buffer[0]);
+
+ REN_push_quad(gpu->ren, positions, colors);
}
-void
+void
GPU_gp0_triangle_shaded_opaque(GPU* gpu)
{
ivec2 positions[3];
@@ -391,49 +382,42 @@ GPU_gp0_triangle_shaded_opaque(GPU* gpu)
LOG(LOG_DEBUG, "Draw triangle shaded\n", NULL);
}
-void
+void
GPU_gp0_quad_texture_blend_opaque(GPU* gpu)
{
- //ivec2 positions[4];
- //C colors[4];
+ ivec2 positions[4];
+ C colors[4];
- //positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]);
- //positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]);
- //positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]);
- //positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[7]);
+ positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]);
+ positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]);
+ positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]);
+ positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[7]);
- //colors[0] =(C) {0x00, 0x00, 0x80};//COLOR_from_gp0(gpu->gp0_command.buffer[0]);
- //colors[1] =(C) {0x00, 0x00, 0x80};//COLOR_from_gp0(gpu->gp0_command.buffer[2]);
- //colors[2] =(C) {0x00, 0x00, 0x80};//COLOR_from_gp0(gpu->gp0_command.buffer[4]);
- //colors[3] =(C) {0x00, 0x00, 0x80};//COLOR_from_gp0(gpu->gp0_command.buffer[6]);
+ colors[0] = colors[1] = colors[2] = colors[3] = (C){0x00, 0x00, 0x80};
- //REN_push_quad(gpu->ren, positions, colors);
- //LOG(LOG_DEBUG, "Draw quad texture blending\n", NULL);
+ REN_push_quad(gpu->ren, positions, colors);
}
-void
+void
GPU_gp0_quad_shaded_opaque(GPU* gpu)
{
- //LOG(LOG_DEBUG, "Draw quad pls\n", NULL);
- //ivec2 positions[4];
- //C colors[4];
+ ivec2 positions[4];
+ C colors[4];
- //positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]);
- //positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]);
- //positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]);
- //positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[7]);
-
- //colors[0] = COLOR_from_gp0(gpu->gp0_command.buffer[0]);
- //colors[1] = COLOR_from_gp0(gpu->gp0_command.buffer[2]);
- //colors[2] = COLOR_from_gp0(gpu->gp0_command.buffer[4]);
- //colors[3] = COLOR_from_gp0(gpu->gp0_command.buffer[6]);
+ positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]);
+ positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]);
+ positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]);
+ positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[7]);
- //REN_push_quad(gpu->ren, positions, colors);
+ colors[0] = COLOR_from_gp0(gpu->gp0_command.buffer[0]);
+ colors[1] = COLOR_from_gp0(gpu->gp0_command.buffer[2]);
+ colors[2] = COLOR_from_gp0(gpu->gp0_command.buffer[4]);
+ colors[3] = COLOR_from_gp0(gpu->gp0_command.buffer[6]);
- //LOG(LOG_DEBUG, "Draw quad shaded\n", NULL);
+ REN_push_quad(gpu->ren, positions, colors);
}
-void
+void
GPU_gp0_image_store(GPU* gpu)
{
u32 res, width, height;
@@ -456,11 +440,11 @@ GPU_CMD_BUFFER_new(void)
return buffer;
}
-void
-GPU_CMD_BUFFER_clear(GPU_CMD_BUFFER* cmd_buffer)
-{
+void
+GPU_CMD_BUFFER_clear(GPU_CMD_BUFFER* cmd_buffer)
+{
cmd_buffer->len = 0;
- /*memset(cmd_buffer->buffer, 413, 12 * sizeof(u32));*/
+ memset(cmd_buffer->buffer, 413, 12 * sizeof(u32));
}
void
diff --git a/src/main.c b/src/main.c
@@ -1,14 +1,10 @@
-#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
#include <SDL2/SDL.h>
-#include "types.h"
#include "cpu.h"
#include "interconnect.h"
#include "bios.h"
#include "mem.h"
-#include "defs.h"
#include "gpu.h"
#include "sr.h"
@@ -17,51 +13,50 @@ SDL_Event ev;
int
main(int argc, char **argv)
{
- int c;
- REN *ren;
- CPU *cpu;
- Interconnect *inter;
-
- SDL_Init(SDL_INIT_VIDEO);
- inter = new_interconnect();
- cpu = new_cpu(inter);
- ren = inter->gpu->ren;
- SDL_SetRenderDrawColor(ren->renderer, 0xff, 0xff, 0xff, 0xff);
- SDL_RenderClear(ren->renderer);
- SDL_RenderPresent(ren->renderer);
-
- while(1) {
- /* Because it's too slow to run events every instr */
- for (c = 0; c < 1e5; c++)
- CPU_run_next_instruction(cpu);
-
- while(SDL_PollEvent(&ev) != 0) {
- switch(ev.type) {
- case SDL_QUIT:
- SDL_Quit();
- exit(1);
- case SDL_KEYDOWN:
- if (ev.key.keysym.sym == SDLK_q) {
- SDL_Quit();
- exit(1);
- } else if (ev.key.keysym.sym == SDLK_a) {
- SDL_Log("A pressed");
- break;
- }
- }
+ int c;
+ REN *ren;
+ CPU *cpu;
+ Interconnect *inter;
+
+ SDL_Init(SDL_INIT_VIDEO);
+ inter = new_interconnect();
+ cpu = new_cpu(inter);
+ ren = inter->gpu->ren;
+ SDL_SetRenderDrawColor(ren->renderer, 0xff, 0xff, 0xff, 0xff);
+ SDL_RenderClear(ren->renderer);
+ SDL_RenderPresent(ren->renderer);
+
+ while(1) {
+ /* Because it's too slow to run events every instr */
+ for (c = 0; c < 1e5; c++) CPU_run_next_instruction(cpu);
+
+ while(SDL_PollEvent(&ev) != 0) {
+ switch(ev.type) {
+ case SDL_QUIT:
+ SDL_Quit();
+ exit(1);
+ case SDL_KEYDOWN:
+ if (ev.key.keysym.sym == SDLK_q) {
+ SDL_Quit();
+ exit(1);
+ } else if (ev.key.keysym.sym == SDLK_a) {
+ SDL_Log("A pressed");
+ break;
+ }
+ }
+ }
}
- }
- free(inter->bios->data);
- free(inter->bios);
- free(inter->ram->data);
- free(inter->ram);
- free(inter->dma);
- free(inter->gpu);
- free(inter);
- free(cpu);
+ free(inter->bios->data);
+ free(inter->bios);
+ free(inter->ram->data);
+ free(inter->ram);
+ free(inter->dma);
+ free(inter->gpu);
+ free(inter);
+ free(cpu);
- SDL_Quit();
+ SDL_Quit();
- return 0;
+ return 0;
}
diff --git a/src/sr.c b/src/sr.c
@@ -1,17 +1,14 @@
/* Based software renderer in one file */
-#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <math.h>
#include <SDL2/SDL.h>
#include "types.h"
#include "sr.h"
#include "defs.h"
-#include "shaders.h"
-
+#include "util.h"
ivec2
POSITION_from_gp0(u32 val)
@@ -53,7 +50,7 @@ FB_flip_vert(u32 *data)
}
ivec2
-IVEC2_op(ivec2 a, ivec2 b, enum mop mop)
+IVEC2_op(ivec2 a, ivec2 b, enum mop mop)
{
ivec2 c;
switch(mop) {
@@ -76,7 +73,7 @@ IVEC2_op(ivec2 a, ivec2 b, enum mop mop)
}
ivec2
-IVEC2_ops(ivec2 a, i32 b, enum mop mop)
+IVEC2_ops(ivec2 a, i32 b, enum mop mop)
{
ivec2 c;
switch(mop) {
@@ -99,35 +96,35 @@ IVEC2_ops(ivec2 a, i32 b, enum mop mop)
}
-C
-C_new(u32 b)
-{
+C
+C_new(u32 b)
+{
C c;
- c.r = (u8)(b & 0xff);
- c.g = (u8)((b >> 8) & 0xff);
- c.b = (u8)((b >> 16) & 0xff);
+ c.r = (u8)(b & 0xff);
+ c.g = (u8)((b >> 8) & 0xff);
+ c.b = (u8)((b >> 16) & 0xff);
return c;
};
void REN_FB_set(REN* ren, i32 x, i32 y, C c) { (!ren->fb || x<0 || y<0 || x>=W || y>=H) ? 0 : memcpy(ren->fb + ((x + y * W)), &c, 3); }
-//C*
-//FB_get(i32 x, i32 y)
+//C*
+//FB_get(i32 x, i32 y)
//{
// void* c = (!fb.data || x<0 || y<0 || x>=W || y>=H) ? (void*)0 : (void*)(C_new(fb.data[(x+y*W)]));
// return (C*)c;
//}
REN*
-REN_new()
+REN_new()
{
REN* ren;
ren = (REN*)malloc(sizeof(REN));
- ren->window = SDL_CreateWindow("Ultimecia", 2560 / 2 , 1440 / 2, WIN_W, WIN_H, SDL_WINDOW_SHOWN);
+ ren->window = SDL_CreateWindow("Ultimecia", 400 , 300, WIN_W, WIN_H, SDL_WINDOW_SHOWN);
ren->renderer = SDL_CreateRenderer(ren->window, -1, 0);
ren->tex = SDL_CreateTexture(ren->renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, W, H);
- ren->verts = NULL;
- ren->colors = NULL;
+ ren->verts = (ivec2*)malloc(sizeof(ivec2) * VERTEX_BUFFER_LEN);
+ ren->colors = (C*)malloc(sizeof(C) * VERTEX_BUFFER_LEN);
ren->verts = (ivec2*)malloc(sizeof(ivec2) * 10000);
ren->colors = (C*)malloc(sizeof(C) * 10000);
ren->fb = (u32*)malloc(W*H*sizeof(u32));
@@ -136,173 +133,82 @@ REN_new()
return ren;
}
-void REN_triangle(REN* ren, ivec2 verts[3], C colors[3])
+// Draw a scanline with color interpolation
+void
+draw_scanline(REN* ren, int y, int x1, C c1, int x2, C c2)
{
- // Sort vertices by y-coordinate
- ivec2 t0, t1, t2;
- C c0, c1, c2;
-
- t0 = verts[0], t1 = verts[1], t2 = verts[2];
- c0 = colors[0], c1 = colors[1], c2 = colors[2];
-
- if (t0.y > t1.y) { VEC2I_SWAP(t0, t1); C_SWAP(c0, c1); }
- if (t0.y > t2.y) { VEC2I_SWAP(t0, t2); C_SWAP(c0, c2); }
- if (t1.y > t2.y) { VEC2I_SWAP(t1, t2); C_SWAP(c1, c2); }
-
- int total_height = t2.y - t0.y;
- if (total_height == 0) return; // Degenerate triangle
-
- for (int y = t0.y; y <= t2.y; y++) {
- int is_upper = (y < t1.y || t1.y == t0.y);
-
- // Alpha (long edge)
- float alpha = (float)(y - t0.y) / (float)(t2.y - t0.y);
- int Ax = t0.x + (int)((t2.x - t0.x) * alpha);
- C colorA = {
- (u8)(c0.r + (c2.r - c0.r) * alpha),
- (u8)(c0.g + (c2.g - c0.g) * alpha),
- (u8)(c0.b + (c2.b - c0.b) * alpha)
- };
-
- // Beta (short edge)
- float beta = is_upper
- ? (float)(y - t0.y) / (float)(t1.y - t0.y)
- : (float)(y - t1.y) / (float)(t2.y - t1.y);
- int Bx = is_upper
- ? t0.x + (int)((t1.x - t0.x) * beta)
- : t1.x + (int)((t2.x - t1.x) * beta);
-
- C colorB = is_upper
- ? (C){
- (u8)(c0.r + (c1.r - c0.r) * beta),
- (u8)(c0.g + (c1.g - c0.g) * beta),
- (u8)(c0.b + (c1.b - c0.b) * beta)
- }
- : (C){
- (u8)(c1.r + (c2.r - c1.r) * beta),
- (u8)(c1.g + (c2.g - c1.g) * beta),
- (u8)(c1.b + (c2.b - c1.b) * beta)
- };
-
- // Ensure left-to-right order
- if (Ax > Bx) {
- int temp_x = Ax; Ax = Bx; Bx = temp_x;
- C temp_c = colorA; colorA = colorB; colorB = temp_c;
- }
-
- // Draw scanline
- for (int x = Ax; x <= Bx; x++) {
- float t = (float)(x - Ax) / (float)(Bx - Ax + 1e-6f); // Avoid divide by zero
- C color = {
- (u8)(colorA.r + (colorB.r - colorA.r) * t),
- (u8)(colorA.g + (colorB.g - colorA.g) * t),
- (u8)(colorA.b + (colorB.b - colorA.b) * t)
- };
-
- REN_FB_set(ren, x, y, color);
- }
- }
+ if (x1 > x2) {
+ swap_int(&x1, &x2);
+ swap_color(&c1, &c2);
+ }
+
+ int dx = x2 - x1;
+ if (dx == 0) return;
+
+ float dr = (c2.r - c1.r) / (float)dx;
+ float dg = (c2.g - c1.g) / (float)dx;
+ float db = (c2.b - c1.b) / (float)dx;
+
+ float r = c1.r, g = c1.g, b = c1.b;
+ for (int x = x1; x <= x2; x++) {
+ REN_FB_set(ren, x, y, (C){r,g,b});
+ r += dr; g += dg; b += db;
+ }
}
-//void REN_triangle(REN* ren, ivec2 verts[3], C colors[3])
-//{
-// // Sort vertices by y-coordinate
-// ivec2 t0, t1, t2;
-// C c0, c1, c2;
-//
-// t0 = verts[0], t1 = verts[1], t2 = verts[2];
-// c0 = colors[0], c1 = colors[1], c2 = colors[2];
-//
-// if (t0.y > t1.y) { VEC2I_SWAP(t0, t1); C_SWAP(c0, c1); }
-// if (t0.y > t2.y) { VEC2I_SWAP(t0, t2); C_SWAP(c0, c2); }
-// if (t1.y > t2.y) { VEC2I_SWAP(t1, t2); C_SWAP(c1, c2); }
-//
-// int inv_total_height = t2.y - t0.y;
-// //if (inv_total_height == 0) return;
-//
-// for (int y = t0.y; y <= t2.y; y++) {
-// int is_upper = y < t1.y || t1.y == t0.y;
-//
-// int alpha = (y - t0.y) * inv_total_height;
-//
-// // Interpolate along the long edge (t0 → t2)
-// int Ax = t0.x + (t2.x - t0.x) * alpha;
-// C colorA = {
-// (u8)(c0.r + (c2.r - c0.r) * alpha),
-// (u8)(c0.g + (c2.g - c0.g) * alpha),
-// (u8)(c0.b + (c2.b - c0.b) * alpha)
-// };
-//
-//
-// // Interpolate along the short edge (t0 → t1 or t1 → t2)
-// int beta = is_upper
-// ? (y - t0.y) / (t1.y - t0.y)
-// : (y - t1.y) / (t2.y - t1.y);
-//
-// int Bx = is_upper
-// ? t0.x + (t1.x - t0.x) * beta
-// : t1.x + (t2.x - t1.x) * beta;
-//
-// //if (Bx < 0) Bx = 0; // Clamp to minimum screen boundary
-// //if (Bx > W) Bx = W; // Clamp to maximum boundary
-//
-//
-// C colorB = is_upper
-// ? (C){
-// (u8)(c0.r + (c1.r - c0.r) * beta),
-// (u8)(c0.g + (c1.g - c0.g) * beta),
-// (u8)(c0.b + (c1.b - c0.b) * beta)
-// }
-// : (C){
-// (u8)(c1.r + (c2.r - c1.r) * beta),
-// (u8)(c1.g + (c2.g - c1.g) * beta),
-// (u8)(c1.b + (c2.b - c1.b) * beta)
-// };
-//
-// // C colorB = (C){ c0.r + (c1.r - c0.r) * beta, c0.g + (c1.g - c0.g) * beta, c0.b + (c1.b - c0.b) * beta };
-//
-// // Ensure left-to-right order
-// if (Ax > Bx) {
-// int temp_x = Ax; Ax = Bx; Bx = temp_x;
-// C temp_c = colorA; colorA = colorB; colorB = temp_c;
-// LOG(LOG_DEBUG, "IM IN %d \n", Ax);
-// }
-//
-// // Draw the scanline
-// for (int x = Ax; x <= Bx; x++) {
-// int t = (x - Ax) / (Bx - Ax + 1e-6f); // Prevent divide-by-zero
-// C color = {
-// (u8)(colorA.r + (colorB.r - colorA.r) * t),
-// (u8)(colorA.g + (colorB.g - colorA.g) * t),
-// (u8)(colorA.b + (colorB.b - colorA.b) * t)
-// };
-//
-// REN_FB_set(ren, x, y, color);
-// }
-// }
-//}
+// Rasterize triangle with color interpolation
+void
+REN_triangle(REN* ren, ivec2 verts[3], C colors[3])
+{
+ float dx01, dx02, dx12, dr01, dg01, db01, dr02, dg02, db02, dr12, dg12, db12, xL, xR, rL, rR, gL, gR, bL, bR;
+
+ /* Sort vertices by y-coordinate to ensure we process from top to bottom */
+ if (verts[0].y > verts[1].y) { swap_vec2(&verts[0], &verts[1]); swap_color(&colors[0], &colors[1]); }
+ if (verts[0].y > verts[2].y) { swap_vec2(&verts[0], &verts[2]); swap_color(&colors[0], &colors[2]); }
+ if (verts[1].y > verts[2].y) { swap_vec2(&verts[1], &verts[2]); swap_color(&colors[1], &colors[2]); }
+
+ // Calculate edge slopes
+ dx01 = (verts[1].x - verts[0].x) / (float)(verts[1].y - verts[0].y + 1);
+ dx02 = (verts[2].x - verts[0].x) / (float)(verts[2].y - verts[0].y + 1);
+ dx12 = (verts[2].x - verts[1].x) / (float)(verts[2].y - verts[1].y + 1);
+
+ dr01 = (colors[1].r - colors[0].r) / (float)(verts[1].y - verts[0].y + 1);
+ dg01 = (colors[1].g - colors[0].g) / (float)(verts[1].y - verts[0].y + 1);
+ db01 = (colors[1].b - colors[0].b) / (float)(verts[1].y - verts[0].y + 1);
+
+ dr02 = (colors[2].r - colors[0].r) / (float)(verts[2].y - verts[0].y + 1);
+ dg02 = (colors[2].g - colors[0].g) / (float)(verts[2].y - verts[0].y + 1);
+ db02 = (colors[2].b - colors[0].b) / (float)(verts[2].y - verts[0].y + 1);
+
+ dr12 = (colors[2].r - colors[1].r) / (float)(verts[2].y - verts[1].y + 1);
+ dg12 = (colors[2].g - colors[1].g) / (float)(verts[2].y - verts[1].y + 1);
+ db12 = (colors[2].b - colors[1].b) / (float)(verts[2].y - verts[1].y + 1);
+
+ // Rasterize top part
+ xL = verts[0].x, rL = colors[0].r, gL = colors[0].g, bL = colors[0].b;
+ xR = verts[0].x, rR = colors[0].r, gR = colors[0].g, bR = colors[0].b;
+
+ for (int y = verts[0].y; y < verts[1].y; y++) {
+ draw_scanline(ren, y, (int)xL, (C){rL, gL, bL}, (int)xR, (C){rR, gR, bR});
+ xL += dx01; rL += dr01; gL += dg01; bL += db01;
+ xR += dx02; rR += dr02; gR += dg02; bR += db02;
+ }
+
+ // Rasterize bottom part
+ xL = verts[1].x, rL = colors[1].r, gL = colors[1].g, bL = colors[1].b;
+ for (int y = verts[1].y; y < verts[2].y; y++) {
+ draw_scanline(ren, y, (int)xL, (C){rL, gL, bL}, (int)xR, (C){rR, gR, bR});
+ xL += dx12; rL += dr12; gL += dg12; bL += db12;
+ xR += dx02; rR += dr02; gR += dg02; bR += db02;
+ }
+}
void
REN_push_triangle(REN* ren, ivec2 verts[3], C colors[3])
{
u8 i;
-
- if (ren->nvertices > 9)
- {
- LOG(LOG_DEBUG, "Vertex attribute buffer full push_triangle, forcing draw... and NVERTICES IS %d\n", ren->nvertices);
- for(int i = 0; i < ren->nvertices-3; i+=3)
- REN_triangle(ren, ren->verts+i, ren->colors+i);
- ren->nvertices=0;
- }
-
- //if (ren->nvertices + 3 >= ren->capacity) {
- // ren->capacity *= 2; // Double the capacity
- // ren->verts = (ivec2*)realloc(ren->verts, sizeof(ivec2) * ren->capacity);
- // ren->colors = (C*)realloc(ren->colors, sizeof(C) * ren->capacity);
- //}
- //ren->verts = (ivec2*)realloc(ren->verts, sizeof(ivec2) * (ren->nvertices + 3));
- //ren->colors = (C*)realloc(ren->colors, sizeof(C) * (ren->nvertices + 3));
+ REN_flush(ren);
for (i = 0; i < 3; i++) {
ren->verts[ren->nvertices] = verts[i];
@@ -315,17 +221,8 @@ void
REN_push_quad(REN* ren, ivec2 verts[4], C colors[4])
{
u8 i;
-
- if (ren->nvertices > 9)
- {
- LOG(LOG_DEBUG, "Vertex attribute buffer full push_squad, forcing draw... and NVERTICES IS %d\n", ren->nvertices);
- for(int i = 0; i < ren->nvertices-3;i+=3)
- REN_triangle(ren, ren->verts+i, ren->colors+i);
- ren->nvertices=0;
- }
- //ren->verts = (ivec2*)realloc(ren->verts, sizeof(ivec2) * (ren->nvertices + 4));
- //ren->colors = (C*)realloc(ren->colors, sizeof(C) * (ren->nvertices + 4));
+ REN_flush(ren);
for (i = 0; i < 3; i++) {
ren->verts[ren->nvertices] = verts[i];
@@ -338,6 +235,17 @@ REN_push_quad(REN* ren, ivec2 verts[4], C colors[4])
ren->colors[ren->nvertices] = colors[i];
ren->nvertices++;
}
+ int a;
+}
+
+void
+REN_flush(REN* ren) {
+ u32 i;
+ if (ren->nvertices > 0) { // Always draw whatever is in the buffer
+ for (i = 0; i < ren->nvertices; i += 3)
+ REN_triangle(ren, ren->verts + i, ren->colors + i);
+ ren->nvertices = 0; // Reset buffer for next frame
+ }
}
void
diff --git a/src/sr.h b/src/sr.h
@@ -1,6 +1,7 @@
#pragma once
#include <SDL2/SDL.h>
+#include "types.h"
#define W 640
#define H 480
@@ -42,3 +43,5 @@ void REN_push_triangle(REN*, ivec2[3], C[3]);
void REN_push_quad(REN*, ivec2[4], C[4]);
void REN_draw(REN* ren);
void REN_display(REN* ren);
+void REN_flush(REN* ren);
+void draw_scanline(REN*, int, int, C, int, C);
diff --git a/src/tags b/src/tags
@@ -2,7 +2,8 @@ BIOS bios.h /^struct BIOS {$/
BIOS_load32 bios.c /^BIOS_load32(BIOS* b, u32 offset)$/
BIOS_load8 bios.c /^u8 BIOS_load8(BIOS* b, u32 offset) { return b->dat/
BIOS_new bios.c /^BIOS_new(const char* path)$/
-Bool types.h /^typedef uint8_t Bool;$/
+Bool tags /^Bool types.h \/^typedef uint8_t Bool;$\/$/
+C sr.h /^typedef struct {u8 b;u8 g;u8 r;} C;$/
CHANNEL_active mem.c /^CHANNEL_active(Channel* ch)$/
CHANNEL_base mem.c /^CHANNEL_base(Channel* ch)$/
CHANNEL_block_control mem.c /^CHANNEL_block_control(Channel* ch)$/
@@ -13,6 +14,7 @@ CHANNEL_set_base mem.c /^CHANNEL_set_base(Channel* ch, u32 val)$/
CHANNEL_set_block_control mem.c /^CHANNEL_set_block_control(Channel* ch, u32 val)$/
CHANNEL_set_control mem.c /^CHANNEL_set_control(Channel* ch, u32 val)$/
CHANNEL_transfer_size mem.c /^CHANNEL_transfer_size(Channel* ch, u32 *res)$/
+COLOR_from_gp0 sr.c /^COLOR_from_gp0(u32 val)$/
CPU cpu.h /^} CPU;$/
CPU_decode_and_execute cpu.c /^CPU_decode_and_execute(CPU* cpu, instruction* i)$/
CPU_load16 cpu.c /^u16 CPU_load16(CPU* cpu, u32 addr) { return INTER_/
@@ -22,6 +24,8 @@ CPU_run_next_instruction cpu.c /^CPU_run_next_instruction(CPU* cpu)$/
CPU_store16 cpu.c /^void CPU_store16(CPU* cpu, u32 addr, u16 val) { IN/
CPU_store32 cpu.c /^void CPU_store32(CPU* cpu, u32 addr, u32 val) { IN/
CPU_store8 cpu.c /^void CPU_store8(CPU* cpu, u32 addr, u8 val) { IN/
+C_SWAP sr.h /^#define C_SWAP(x, y) { C temp = x; x = y; y = temp/
+C_new sr.c /^C_new(u32 b)$/
Channel mem.h /^} Channel;$/
DISPLAY_DEPTH gpu.h /^} DISPLAY_DEPTH;$/
DMA mem.h /^} DMA;$/
@@ -34,27 +38,39 @@ DMA_set_control mem.c /^DMA_set_control(DMA* dma, u32 val)$/
DMA_set_interrupt mem.c /^DMA_set_interrupt(DMA* dma, u32 val)$/
Direction mem.h /^} Direction;$/
EXCEPTION cpu.h /^} EXCEPTION;$/
+FB_flip_vert sr.c /^FB_flip_vert(u32 *data)$/
FIELD gpu.h /^} FIELD;$/
+GP0_MODE gpu.h /^} GP0_MODE;$/
GPU gpu.h /^} GPU;$/
GPU_CMD_BUFFER gpu.h /^} GPU_CMD_BUFFER;$/
-GPU_CMD_BUFFER_clear gpu.c /^void GPU_CMD_BUFFER_clear(GPU_CMD_BUFFER* cmd_buff/
+GPU_CMD_BUFFER_clear gpu.c /^GPU_CMD_BUFFER_clear(GPU_CMD_BUFFER* cmd_buffer) $/
GPU_CMD_BUFFER_new gpu.c /^GPU_CMD_BUFFER_new(void)$/
GPU_CMD_BUFFER_push_word gpu.c /^GPU_CMD_BUFFER_push_word(GPU_CMD_BUFFER* cmd_buffe/
GPU_gp0 gpu.c /^GPU_gp0(GPU* gpu, u32 val)$/
+GPU_gp0_clear_cache gpu.c /^void GPU_gp0_clear_cache(GPU* gpu) { \/* Not imple/
GPU_gp0_draw_mode gpu.c /^GPU_gp0_draw_mode(GPU* gpu)$/
GPU_gp0_drawing_area_bottom_right gpu.c /^GPU_gp0_drawing_area_bottom_right(GPU* gpu)$/
GPU_gp0_drawing_area_top_left gpu.c /^GPU_gp0_drawing_area_top_left(GPU* gpu)$/
GPU_gp0_drawing_offset gpu.c /^GPU_gp0_drawing_offset(GPU* gpu)$/
+GPU_gp0_image_load gpu.c /^GPU_gp0_image_load(GPU* gpu) $/
+GPU_gp0_image_store gpu.c /^GPU_gp0_image_store(GPU* gpu)$/
GPU_gp0_mask_bit_setting gpu.c /^GPU_gp0_mask_bit_setting(GPU* gpu)$/
GPU_gp0_nop gpu.c /^void GPU_gp0_nop(GPU* gpu) {}$/
+GPU_gp0_quad_mono_opaque gpu.c /^GPU_gp0_quad_mono_opaque(GPU* gpu)$/
+GPU_gp0_quad_shaded_opaque gpu.c /^GPU_gp0_quad_shaded_opaque(GPU* gpu)$/
+GPU_gp0_quad_texture_blend_opaque gpu.c /^GPU_gp0_quad_texture_blend_opaque(GPU* gpu)$/
GPU_gp0_texture_window gpu.c /^GPU_gp0_texture_window(GPU* gpu)$/
+GPU_gp0_triangle_shaded_opaque gpu.c /^GPU_gp0_triangle_shaded_opaque(GPU* gpu)$/
GPU_gp1 gpu.c /^GPU_gp1(GPU* gpu, u32 val)$/
+GPU_gp1_acknowledge_irq gpu.c /^GPU_gp1_acknowledge_irq(GPU* gpu, u32 val)$/
+GPU_gp1_display_enable gpu.c /^GPU_gp1_display_enable(GPU* gpu, u32 val)$/
GPU_gp1_display_horizontal_range gpu.c /^GPU_gp1_display_horizontal_range(GPU* gpu, u32 val/
GPU_gp1_display_mode gpu.c /^GPU_gp1_display_mode(GPU* gpu, u32 val)$/
GPU_gp1_display_vertical_range gpu.c /^GPU_gp1_display_vertical_range(GPU* gpu, u32 val)$/
GPU_gp1_display_vram_start gpu.c /^GPU_gp1_display_vram_start(GPU* gpu, u32 val)$/
GPU_gp1_dma_direction gpu.c /^GPU_gp1_dma_direction(GPU* gpu, u32 val)$/
GPU_gp1_reset gpu.c /^GPU_gp1_reset(GPU* gpu, u32 val)$/
+GPU_gp1_reset_command_buffer gpu.c /^GPU_gp1_reset_command_buffer(GPU* gpu, u32 val)$/
GPU_new gpu.c /^GPU_new(void)$/
GPU_read gpu.c /^GPU_read(GPU* gpu)$/
GPU_status gpu.c /^GPU_status(GPU* gpu)$/
@@ -71,10 +87,15 @@ INTER_set_dma_reg interconnect.c /^INTER_set_dma_reg(Interconnect* inter, u32 of
INTER_store16 interconnect.c /^INTER_store16(Interconnect* inter, u32 addr, u16 v/
INTER_store32 interconnect.c /^INTER_store32(Interconnect* inter, u32 addr, u32 v/
INTER_store8 interconnect.c /^INTER_store8(Interconnect* inter, u32 addr, u8 val/
+IVEC2_op sr.c /^IVEC2_op(ivec2 a, ivec2 b, enum mop mop)$/
+IVEC2_ops sr.c /^IVEC2_ops(ivec2 a, i32 b, enum mop mop)$/
+I_SWAP sr.h /^#define I_SWAP(x, y) { int temp = x; x = y; y = te/
Interconnect interconnect.h /^struct Interconnect {$/
+LOG defs.h /^#define LOG(level, fmt, ...) \\$/
LOG_ERR defs.h /^#define LOG_ERR(x) fprintf(stderr, (x))$/
Load cpu.h /^} Load;$/
Mmain main.c /^main(int argc, char **argv)$/
+POSITION_from_gp0 sr.c /^POSITION_from_gp0(u32 val)$/
Port mem.h /^} Port;$/
RAM mem.h /^} RAM;$/
RAM_load16 mem.c /^RAM_load16(RAM* r, u32 offset)$/
@@ -84,10 +105,20 @@ RAM_new mem.c /^RAM_new(void) $/
RAM_store16 mem.c /^RAM_store16(RAM* r, u32 offset, u16 val)$/
RAM_store32 mem.c /^RAM_store32(RAM* r, u32 offset, u32 val)$/
RAM_store8 mem.c /^RAM_store8(RAM* r, u32 offset, u8 val)$/
+REN sr.h /^} REN;$/
+REN_FB_set sr.c /^void REN_FB_set(REN* ren, i32 x, i32 y, C c) { (!r/
+REN_display sr.c /^REN_display(REN* ren)$/
+REN_draw sr.c /^REN_draw(REN* ren)$/
+REN_new sr.c /^REN_new()$/
+REN_push_quad sr.c /^REN_push_quad(REN* ren, ivec2 verts[4], C colors[4/
+REN_push_triangle sr.c /^REN_push_triangle(REN* ren, ivec2 verts[3], C colo/
+REN_triangle sr.c /^void REN_triangle(REN* ren, ivec2 verts[3], C colo/
+SHADERS_gradient_shader shaders.c /^SHADERS_gradient_shader(float alpha, float beta, f/
Step mem.h /^} Step;$/
Sync mem.h /^} Sync;$/
TEXTURE_DEPTH gpu.h /^} TEXTURE_DEPTH;$/
UTIL_contains util.c /^UTIL_contains(u32 start, u32 length, u32 addr, u32/
+VEC2I_SWAP sr.h /^#define VEC2I_SWAP(x, y) { ivec2 temp = x; x = y; /
VMODE gpu.h /^} VMODE;$/
branch cpu.c /^branch(CPU* cpu, u32 offset)$/
checked_addi32 util.c /^checked_addi32(i32 a, i32 b, i32* res)$/
@@ -98,7 +129,9 @@ i32 types.h /^typedef int32_t i32;$/
i64 types.h /^typedef int64_t i64;$/
i8 types.h /^typedef int8_t i8;$/
instruction cpu.h /^} instruction;$/
+ivec2 sr.h /^typedef struct { int x, y; } ivec2;$/
mask_region util.c /^u32 mask_region(u32 addr) { return addr & REGION_M/
+mop sr.h /^enum mop {ADD, SUB, MUL, DIV};$/
new_cpu cpu.c /^new_cpu(Interconnect* inter) {$/
new_instr cpu.c /^new_instr(u32 i)$/
new_interconnect interconnect.c /^new_interconnect(void) {$/
@@ -173,9 +206,11 @@ op_swr cpu.c /^op_swr(CPU* cpu, instruction* i)$/
op_syscall cpu.c /^void op_syscall(CPU* cpu, instruction* i)$/
op_xor cpu.c /^op_xor(CPU* cpu, instruction* i)$/
op_xori cpu.c /^op_xori(CPU* cpu, instruction* i)$/
+point sr.h /^typedef struct { double x, y, z; } point;$/
reg cpu.c /^u32 reg(CPU* cpu, u32 reg) { return cpu->out_regs[/
set_reg cpu.c /^void set_reg(CPU* cpu, u32 reg, u32 val) { cpu->ou/
u16 types.h /^typedef uint16_t u16;$/
u32 types.h /^typedef uint32_t u32;$/
u64 types.h /^typedef uint64_t u64;$/
u8 types.h /^typedef uint8_t u8;$/
+vec3f sr.h /^typedef struct { double x, y, z; } vec3f;$/
diff --git a/src/util.c b/src/util.c
@@ -3,42 +3,52 @@
#include <limits.h>
const u32 REGION_MASK[8] = {
- /* KUSEG: 2048MB */
- 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
- /* KSEG0: 512MB */
- 0x7fffffff,
- /* KSEG1: 512MB */
- 0x1fffffff,
- /* KSEG2: 1024MB */
- 0xffffffff, 0xffffffff
+ /* KUSEG: 2048MB */
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ /* KSEG0: 512MB */
+ 0x7fffffff,
+ /* KSEG1: 512MB */
+ 0x1fffffff,
+ /* KSEG2: 1024MB */
+ 0xffffffff, 0xffffffff
};
u32
UTIL_contains(u32 start, u32 length, u32 addr, u32 *res)
{
- *res = addr-start;
- return (addr >= start && addr < start + length) ? 1 : 0;
+ *res = addr-start;
+ return (addr >= start && addr < start + length) ? 1 : 0;
}
u8
checked_addi32(i32 a, i32 b, i32* res)
{
- if ((b > 0 && a > INT_MAX - b) || (b < 0 && a < INT_MIN - b)) {
- return 0;
- }
- *res = a + b;
- return 1;
+ if ((b > 0 && a > INT_MAX - b) || (b < 0 && a < INT_MIN - b)) {
+ return 0;
+ }
+ *res = a + b;
+ return 1;
}
u8
checked_subi32(i32 a, i32 b, i32* res)
{
- if ((b > 0 && a > INT_MAX - b) || (b < 0 && a < INT_MIN - b) || (b == 0 && a == INT_MIN)) {
- return 0; /* Overflow occurred */
- }
+ if ((b > 0 && a > INT_MAX - b) || (b < 0 && a < INT_MIN - b) || (b == 0 && a == INT_MIN)) {
+ return 0; /* Overflow occurred */
+ }
- *res = a - b;
- return 1;
+ *res = a - b;
+ return 1;
}
u32 mask_region(u32 addr) { return addr & REGION_MASK[addr >> 29]; }
+
+void
+swap_int(int *a, int *b) { int temp = *a; *a = *b; *b = temp; }
+
+void
+swap_color(C *a, C *b) { C temp = *a; *a = *b; *b = temp; }
+
+void
+swap_vec2(ivec2 *a, ivec2 *b) { ivec2 temp = *a; *a = *b; *b = temp; }
+
diff --git a/src/util.h b/src/util.h
@@ -1,6 +1,7 @@
#pragma once
#include "types.h"
+#include "sr.h"
#define BIOS_SIZE 512 * 1024
#define BIOS_START 0x1FC00000
@@ -42,3 +43,9 @@ u32 UTIL_contains(u32, u32, u32, u32*);
u8 checked_addi32(i32, i32, i32*);
u8 checked_subi32(i32, i32, i32*);
u32 mask_region(u32);
+
+/* Misc */
+void swap_int(int*, int*);
+void swap_color(C*, C*);
+void swap_vec2(ivec2*, ivec2*);
+