ultimecia

A ps1 emulator in c
Log | Files | Refs

commit 3d325d0ec55fbe4c90f1c3af682b57d87cec76f9
parent 84a31fb7042db237390325e6d3b33ea02ed491ce
Author: Edea Kramer <edea@lunarcry.home>
Date:   Sat,  2 Nov 2024 20:26:37 +0200

- Changes default SDL_PIXELFORMAT to RGB888 to represent true color of ps1
(we don't need alpha).
- Implemented color implementation on REN_triangle.
- Probably we need backbuffering

Diffstat:
Msrc/gpu.c | 1-
Msrc/main.c | 1+
Msrc/sr.c | 201++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/sr.h | 8+++++---
4 files changed, 143 insertions(+), 68 deletions(-)

diff --git a/src/gpu.c b/src/gpu.c @@ -368,7 +368,6 @@ GPU_gp0_triangle_shaded_opaque(GPU* gpu) colors[2] = COLOR_from_gp0(gpu->gp0_command.buffer[4]); REN_push_triangle(gpu->ren, positions, colors); - //REN_display(gpu->ren); fprintf(stdout, "Draw triangle shaded\n"); } diff --git a/src/main.c b/src/main.c @@ -57,6 +57,7 @@ main(int argc, char **argv) free(inter->ram->data); free(inter->ram); free(inter->dma); + free(inter->gpu); free(inter); free(cpu); diff --git a/src/sr.c b/src/sr.c @@ -28,7 +28,6 @@ COLOR_from_gp0(u32 val) c.r = (u8)val; c.g = (u8)(val >> 8); c.b = (u8)(val >> 16); - c.a = (u8)((val >> 24) & 0xff); return c; } @@ -105,11 +104,10 @@ C_new(u32 b) c.r = (u8)(b & 0xff); c.g = (u8)((b >> 8) & 0xff); c.b = (u8)((b >> 16) & 0xff); - c.a = (u8)((b >> 24) & 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, 4); } +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) @@ -121,79 +119,157 @@ void REN_FB_set(REN* ren, i32 x, i32 y, C c) { (!ren->fb || x<0 || y<0 || x>=W | REN* REN_new() { - REN* ren; - ren = (REN*)malloc(sizeof(REN)); - ren->window = SDL_CreateWindow("Ultimecia", 400, 400, WIN_W, WIN_H, SDL_WINDOW_SHOWN); - ren->renderer = SDL_CreateRenderer(ren->window, -1, 0); - ren->tex = SDL_CreateTexture(ren->renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, W, H); - ren->verts = NULL; - ren->colors = NULL; - ren->fb = malloc(W*H*sizeof(u32)); - memset(ren->fb, 0, (u32)(W*H)*sizeof(u32)); - ren->nvertices = 0; - printf("FFFFFFFFFFFFFFFFUCK"); - return ren; + REN* ren; + ren = (REN*)malloc(sizeof(REN)); + ren->window = SDL_CreateWindow("Ultimecia", 400, 750, 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)); + 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]) { - // SORT the vertices, t0, t1, t2 lower−to−upper (bubblesort yay!) - ivec2 temp, t0, t1, t2; + 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); - if (t0.y>t2.y) VEC2I_SWAP(t0, t2); - if (t1.y>t2.y) VEC2I_SWAP(t1, t2); - - i32 total_height = t2.y - t0.y; - - for (i32 i = 0; i < total_height; i++) { - i32 second_half = i > (t1.y - t0.y) || t1.y == t0.y; - i32 segment_height = second_half ? t2.y - t1.y : t1.y - t0.y; - float alpha = (float)i / total_height; - float beta = (float)(i - (second_half ? t1.y - t0.y : 0)) / segment_height; // how far down are we - - 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 - (t1.y - t0.y)) - } : - (ivec2){ - t0.x + (t1.x - t0.x) * beta, - t0.y + i - }; - - if (A.x > B.x) VEC2I_SWAP(A, B); - // Draw horizontal span between A and B - for (i32 x = A.x; x <= B.x; x++) { - REN_FB_set(ren, x, A.y, colors[0]); - } - } + 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 the vertices, t0, t1, t2 lower−to−upper (bubblesort yay!) +// ivec2 temp, t0, t1, t2; +// i32 first_half, second_half; +// t0 = verts[0]; t1 = verts[1]; t2 = verts[2]; +// +// if (t0.y>t1.y) VEC2I_SWAP(t0, t1); +// if (t0.y>t2.y) VEC2I_SWAP(t0, t2); +// if (t1.y>t2.y) VEC2I_SWAP(t1, t2); +// +// 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; +// +// 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 }; +// +// if (A.x > B.x) VEC2I_SWAP(A, B); +// +// i32 row_buffer[W*4]; +// i32 row_index = 0; +// for (i32 x = A.x; x <= B.x; x++) { +// row_buffer[row_index++] = x; +// } +// +// for (i32 j = 0; j < row_index; j++) { +// REN_FB_set(ren, row_buffer[j], A.y, colors[j%3]); +// } +// } +// +//} + void REN_push_triangle(REN* ren, ivec2 verts[3], C colors[3]) { u8 i; - long VERTEX_BUFFER_LEN = 64*1024; ivec2 tmp[3]; - if (ren->nvertices + 3 > 1000) { + if (ren->nvertices + 3 > 10) { printf("Vertex attribute buffer full, forcing draw... and NVERTICES IS %d\n", ren->nvertices); - for(int i = 0; i < ren->nvertices-3; i++) { - REN_triangle(ren, ren->verts+(i*2), ren->colors); - //triangle(ren, t0[0],t0[1], t0[2], C_new(0xffffffff));//ren->colors[i]); - //printf("Vert 1 -> x: %d, y: %d\nVert 2 -> x: %d, y: %d\nVert 3 -> x: %d, y: %d\n", ren->verts[i].x, ren->verts[i].y, ren->verts[i+1].x, ren->verts[i+1].y, ren->verts[i+2].x, ren->verts[i+3].y); + for(int i = 0; i < ren->nvertices-3; i+=3) { + REN_triangle(ren, ren->verts+i, ren->colors+1); + printf("Drawing... %d\n", i/3); } - + ren->nvertices=0; } + ren->verts = realloc(ren->verts, sizeof(ivec2) * (ren->nvertices + 3)); ren->colors = 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]; @@ -204,12 +280,10 @@ REN_push_triangle(REN* ren, ivec2 verts[3], C colors[3]) void REN_draw(REN* ren) { - SDL_RenderClear(ren->renderer); - SDL_UpdateTexture(ren->tex, NULL, ren->fb, W * sizeof(u32)); - SDL_RenderCopy(ren->renderer, ren->tex, NULL, NULL); - - // With this uncommented it fucks it up and it doesn't draw - //ren->nvertices=0; + 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); } void @@ -217,5 +291,4 @@ REN_display(REN* ren) { REN_draw(ren); SDL_RenderPresent(ren->renderer); - //SDL_Delay(1000); } diff --git a/src/sr.h b/src/sr.h @@ -5,13 +5,15 @@ #define W 640 #define H 480 -#define WIN_W 1024 -#define WIN_H 1024 +#define WIN_W 640 +#define WIN_H 480 +#define VERTEX_BUFFER_LEN 64*1024 #define VEC2I_SWAP(x, y) { ivec2 temp = x; x = y; y = temp; } +#define C_SWAP(x, y) { C temp = x; x = y; y = temp; } #define I_SWAP(x, y) { int temp = x; x = y; y = temp; } -typedef struct {u8 b;u8 g;u8 r; u8 a;} C; +typedef struct {u8 b;u8 g;u8 r;} C; typedef struct { double x, y, z; } point; typedef struct { int x, y; } ivec2; typedef struct { double x, y, z; } vec3f;