ultimecia

A ps1 emulator in c
Log | Files | Refs

commit 79e0ebcdf3c6f14cb2967dadb3c6f4888b786248
parent 1865c6d720ef2c79549253e1c76108ab749c4c9c
Author: Edea Kramer <edea@lunarcry.home>
Date:   Tue, 17 Dec 2024 18:54:30 +0200

Long time..

- Probably looks okay. Now I am stuck again with quads.
- I have to look at the rasterization algo again.

Diffstat:
Mmakefile | 2+-
Msrc/cpu.c | 4++--
Msrc/defs.h | 2+-
Msrc/gpu.c | 55++++++++++++++++++++++++++++++++++++++++++++++++++++---
Asrc/shaders.c | 10++++++++++
Asrc/shaders.h | 5+++++
Msrc/sr.c | 274+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/sr.h | 1+
8 files changed, 263 insertions(+), 90 deletions(-)

diff --git a/makefile b/makefile @@ -1,5 +1,5 @@ bsd: - cc -O3 -g src/*.c -o bin/ultimecia -I/usr/local/include -L/usr/local/lib -lprofiler -lSDL2 + 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/cpu.c b/src/cpu.c @@ -617,9 +617,9 @@ op_lh(CPU* cpu, instruction* i) void op_lhu(CPU* cpu, instruction* i) { - u32 v, addr; + u32 v, addr; - addr = reg(cpu, i->s) + i->imm_se; + addr = reg(cpu, i->s) + i->imm_se; if (addr % 2 == 0) { diff --git a/src/defs.h b/src/defs.h @@ -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_ERROR +#define CURRENT_LOG_LEVEL LOG_DEBUG #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 @@ -350,7 +350,26 @@ GPU_gp0_mask_bit_setting(GPU* gpu) void GPU_gp0_quad_mono_opaque(GPU* gpu) { - LOG(LOG_DEBUG, "Draw quad pls\n", NULL); + // 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); } void @@ -375,13 +394,43 @@ GPU_gp0_triangle_shaded_opaque(GPU* gpu) void GPU_gp0_quad_texture_blend_opaque(GPU* gpu) { - LOG(LOG_DEBUG, "Draw quad texture blending\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[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]); + + //REN_push_quad(gpu->ren, positions, colors); + //LOG(LOG_DEBUG, "Draw quad texture blending\n", NULL); } void GPU_gp0_quad_shaded_opaque(GPU* gpu) { - LOG(LOG_DEBUG, "Draw quad shaded\n", NULL); + //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[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]); + + //REN_push_quad(gpu->ren, positions, colors); + + //LOG(LOG_DEBUG, "Draw quad shaded\n", NULL); } void diff --git a/src/shaders.c b/src/shaders.c @@ -0,0 +1,10 @@ +#include "gpu.h" + +void +SHADERS_gradient_shader(float alpha, float beta, float gamma, C* out_color) { + // Example shader: simple gradient based on alpha and beta + out_color->r = (uint8_t)(alpha * 255); // Gradient in red + out_color->g = (uint8_t)(beta * 255); // Gradient in green + out_color->b = (uint8_t)(gamma * 255); // Gradient in blue +} + diff --git a/src/shaders.h b/src/shaders.h @@ -0,0 +1,5 @@ +#pragma once + +#include "gpu.h" + +void SHADERS_gradient_shader(float, float, float, C*); diff --git a/src/sr.c b/src/sr.c @@ -10,6 +10,7 @@ #include "types.h" #include "sr.h" #include "defs.h" +#include "shaders.h" ivec2 @@ -122,119 +123,226 @@ REN_new() { REN* ren; ren = (REN*)malloc(sizeof(REN)); - ren->window = SDL_CreateWindow("Ultimecia", 400, 750, WIN_W, WIN_H, SDL_WINDOW_SHOWN); + ren->window = SDL_CreateWindow("Ultimecia", 2560 / 2 , 1440 / 2, 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->fb = malloc(W*H*sizeof(u32)); + ren->verts = (ivec2*)malloc(sizeof(ivec2) * 10000); + ren->colors = (C*)malloc(sizeof(C) * 10000); + ren->fb = (u32*)malloc(W*H*sizeof(u32)); memset(ren->fb, 0, (u32)(W*H)*sizeof(u32)); ren->nvertices = 0; return ren; } - - -void -REN_triangle(REN* ren, ivec2 verts[3], C colors[3]) { - ivec2 temp, t0, t1, t2; - C c0 = colors[0], c1 = colors[1], c2 = colors[2]; - t0 = verts[0]; t1 = verts[1]; t2 = verts[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); } - - i32 total_height = t2.y - t0.y; - i32 height_first_half = t1.y - t0.y; - i32 height_second_half = t2.y - t1.y; - float alpha_step = 1.0f / total_height; - float alpha = 0.0f; - - for (i32 i = 0; i < total_height; i++, alpha += alpha_step) { - i32 second_half = (i > height_first_half) || (t1.y == t0.y); - i32 segment_height = second_half ? height_second_half : height_first_half; - float beta = (float)(i - (second_half ? height_first_half : 0)) / segment_height; - - // Interpolated points for this scanline - ivec2 A = { - t0.x + (t2.x - t0.x) * alpha, - t0.y + i - }; - - ivec2 B = second_half - ? (ivec2){ t1.x + (t2.x - t1.x) * beta, t1.y + (i - height_first_half) } - : (ivec2){ t0.x + (t1.x - t0.x) * beta, t0.y + i }; - - // Interpolated colors for this scanline - C color_a = { - c0.r + (c2.r - c0.r) * alpha, - c0.g + (c2.g - c0.g) * alpha, - c0.b + (c2.b - c0.b) * alpha - }; - - C color_b = second_half - ? (C){ - c1.r + (c2.r - c1.r) * beta, - c1.g + (c2.g - c1.g) * beta, - c1.b + (c2.b - c1.b) * beta - } - : (C){ - c0.r + (c1.r - c0.r) * beta, - c0.g + (c1.g - c0.g) * beta, - c0.b + (c1.b - c0.b) * beta - }; - - // Sort A and B for left-to-right filling - if (A.x > B.x) { - VEC2I_SWAP(A, B); - C_SWAP(color_a, color_b); - } - - // Fill the horizontal span between A and B, interpolating color - for (i32 x = A.x; x <= B.x; x++) { - float t = (float)(x - A.x) / (B.x - A.x); - - // Linearly interpolate color across the span - C color = { - color_a.r + (color_b.r - color_a.r) * t, - color_a.g + (color_b.g - color_a.g) * t, - color_a.b + (color_b.b - color_a.b) * t - }; - - REN_FB_set(ren, x, A.y, color); - } - } +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 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); + } + } } +//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); +// } +// } +//} + void REN_push_triangle(REN* ren, ivec2 verts[3], C colors[3]) { u8 i; - ivec2 tmp[3]; - - if (ren->nvertices + 3 > 10) { - LOG(LOG_DEBUG, "Vertex attribute buffer full, forcing draw... and NVERTICES IS %d\n", ren->nvertices); + + 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+1); + 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)); + + for (i = 0; i < 3; i++) { + ren->verts[ren->nvertices] = verts[i]; + ren->colors[ren->nvertices] = colors[i]; + ren->nvertices++; + } +} + +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 = realloc(ren->verts, sizeof(ivec2) * (ren->nvertices + 3)); - ren->colors = realloc(ren->colors, sizeof(C) * (ren->nvertices + 3)); + //ren->verts = (ivec2*)realloc(ren->verts, sizeof(ivec2) * (ren->nvertices + 4)); + //ren->colors = (C*)realloc(ren->colors, sizeof(C) * (ren->nvertices + 4)); for (i = 0; i < 3; i++) { ren->verts[ren->nvertices] = verts[i]; ren->colors[ren->nvertices] = colors[i]; ren->nvertices++; } + + for (i = 1; i < 4; i++) { + ren->verts[ren->nvertices] = verts[i]; + ren->colors[ren->nvertices] = colors[i]; + ren->nvertices++; + } } void REN_draw(REN* ren) { - SDL_SetRenderDrawColor(ren->renderer, 0x33, 0x33, 0x33, 0xff); - SDL_RenderClear(ren->renderer); SDL_UpdateTexture(ren->tex, NULL, ren->fb, W * sizeof(u32)); SDL_RenderCopy(ren->renderer, ren->tex, NULL, NULL); } diff --git a/src/sr.h b/src/sr.h @@ -39,5 +39,6 @@ REN* REN_new(); ivec2 POSITION_from_gp0(u32 val); C COLOR_from_gp0(u32 val); 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);