ultimecia

A ps1 emulator in c
Log | Files | Refs

sr.c (6141B)


      1 /* Based software renderer in one file */
      2 
      3 #include <stdio.h>
      4 #include <string.h>
      5 #include <stdlib.h>
      6 #include <SDL2/SDL.h>
      7 
      8 #include "types.h"
      9 #include "sr.h"
     10 #include "util.h"
     11 
     12 ivec2
     13 POSITION_from_gp0(u32 val)
     14 {
     15 	ivec2 pos;
     16 	pos.x = (i16)val;
     17 	pos.y = (i16)(val >> 16);
     18 
     19 	return pos;
     20 }
     21 
     22 C
     23 COLOR_from_gp0(u32 val)
     24 {
     25 	C c;
     26 	c.r = (u8)val;
     27 	c.g = (u8)(val >> 8);
     28 	c.b = (u8)(val >> 16);
     29 	return c;
     30 }
     31 
     32 void
     33 FB_flip_vert(u32 *data)
     34 {
     35 	u64 bytes_per_line; u32 *line; i32 half, j;
     36 
     37 	bytes_per_line = W;
     38 	line = (u32 *)malloc(bytes_per_line * sizeof(u32));
     39 	half = H>>1;
     40 
     41 	for (j=0; j<half; j++) {
     42 		u64 l1 = j*bytes_per_line;
     43 		u64 l2 = (H-1-j)*bytes_per_line;
     44 		memmove((void *)line,      (void *)(data+l1), bytes_per_line* sizeof(u32));
     45 		memmove((void *)(data+l1), (void *)(data+l2), bytes_per_line* sizeof(u32));
     46 		memmove((void *)(data+l2), (void *)line,      bytes_per_line* sizeof(u32));
     47 	}
     48 	free(line);
     49 }
     50 
     51 C
     52 C_new(u32 b)
     53 {
     54 	C c;
     55 	c.r = (u8)(b & 0xff);
     56 	c.g = (u8)((b >> 8) & 0xff);
     57 	c.b = (u8)((b >> 16) & 0xff);
     58 	return c;
     59 }
     60 
     61 void 
     62 REN_FB_set(REN* ren, i32 x, i32 y, u8 r, u8 g, u8 b) {
     63 
     64 	u32 *fb;
     65 
     66 	if (!ren->fb || x < 0 || y < 0 || x >= W || y >= H) return;
     67 
     68 	r = r > 255 ? 255 : r;
     69 	g = g > 255 ? 255 : g;
     70 	b = b > 255 ? 255 : b;
     71 
     72 	fb = ren->fb + (x + y * W);
     73 	*fb = r | (g << 8) | (b << 16);
     74 }
     75 
     76 REN*
     77 REN_new(void)
     78 {
     79 	REN* ren;
     80 	ren = (REN*)malloc(sizeof(REN));
     81 	ren->window = SDL_CreateWindow("Ultimecia", 400 , 300, WIN_W, WIN_H, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
     82 	ren->renderer = SDL_CreateRenderer(ren->window, -1, 0);
     83 	ren->tex = SDL_CreateTexture(ren->renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, W, H);
     84 	ren->verts = (ivec2*)malloc(sizeof(ivec2) * 10000);
     85 	ren->colors = (C*)malloc(sizeof(C) * 10000);
     86 	ren->fb = (u32*)malloc(W*H*sizeof(u32));
     87 	memset(ren->fb, 0, (u32)(W*H)*sizeof(u32));
     88 	ren->nvertices = 0;
     89 
     90 	return ren;
     91 }
     92 
     93 void
     94 draw_scanline(REN* ren, int y, int x1, C c1, int x2, C c2)
     95 {
     96 	int dx, x;
     97 	float r, g, b, dr, dg, db;
     98 	if (x1 > x2) {
     99 		swap_int(&x1, &x2);
    100 		swap_color(&c1, &c2);
    101 	}
    102 
    103 	dx = x2 - x1;
    104 	if (dx == 0) return;
    105 
    106 	dr = (c2.r - c1.r) / (float)dx;
    107 	dg = (c2.g - c1.g) / (float)dx;
    108 	db = (c2.b - c1.b) / (float)dx;
    109 
    110 	r = c1.r, g = c1.g, b = c1.b;
    111 	for (x = x1; x <= x2; x++) {
    112 		REN_FB_set(ren, x, y, (u8)r,(u8)g,(u8)b);
    113 		r += dr; g += dg; b += db;
    114 	}
    115 }
    116 
    117 void
    118 REN_triangle(REN* ren, ivec2 verts[3], C colors[3])
    119 {
    120 
    121 	i32 y, dx01, dx02, dx12, dr01, dr02, dg02, db02, dg01, db01, dr12, dg12, db12, xL, xR;
    122 	u32 rL, rR, gL, bL, gR, bR;
    123 
    124 
    125 	/* Check for degenerate triangles */
    126 	if (verts[0].x == verts[1].x && verts[0].y == verts[1].y) return;
    127 	if (verts[1].x == verts[2].x && verts[1].y == verts[2].y) return;
    128 	if (verts[2].x == verts[0].x && verts[2].y == verts[0].y) return;
    129 
    130 	/* Sort vertices by y-coordinate to ensure we process from top to bottom */
    131 	if (verts[0].y > verts[1].y) { swap_vec2(&verts[0], &verts[1]); swap_color(&colors[0], &colors[1]); }
    132 	if (verts[0].y > verts[2].y) { swap_vec2(&verts[0], &verts[2]); swap_color(&colors[0], &colors[2]); }
    133 	if (verts[1].y > verts[2].y) { swap_vec2(&verts[1], &verts[2]); swap_color(&colors[1], &colors[2]); }
    134 
    135 	/* Calculate edge slopes using fixed-point arithmetic */
    136 	dx01 = ((verts[1].x - verts[0].x) << 16) / (verts[1].y - verts[0].y + 1);
    137 	dx02 = ((verts[2].x - verts[0].x) << 16) / (verts[2].y - verts[0].y + 1);
    138 	dx12 = ((verts[2].x - verts[1].x) << 16) / (verts[2].y - verts[1].y + 1);
    139 
    140 	/* Calculate color slopes using fixed-point arithmetic */
    141 	dr01 = ((colors[1].r - colors[0].r) << 16) / (verts[1].y - verts[0].y + 1);
    142 	dg01 = ((colors[1].g - colors[0].g) << 16) / (verts[1].y - verts[0].y + 1);
    143 	db01 = ((colors[1].b - colors[0].b) << 16) / (verts[1].y - verts[0].y + 1);
    144 
    145 	dr02 = ((colors[2].r - colors[0].r) << 16) / (verts[2].y - verts[0].y + 1);
    146 	dg02 = ((colors[2].g - colors[0].g) << 16) / (verts[2].y - verts[0].y + 1);
    147 	db02 = ((colors[2].b - colors[0].b) << 16) / (verts[2].y - verts[0].y + 1);
    148 
    149 	dr12 = ((colors[2].r - colors[1].r) << 16) / (verts[2].y - verts[1].y + 1);
    150 	dg12 = ((colors[2].g - colors[1].g) << 16) / (verts[2].y - verts[1].y + 1);
    151 	db12 = ((colors[2].b - colors[1].b) << 16) / (verts[2].y - verts[1].y + 1);
    152 
    153 	/* Rasterize top part */
    154 	xL = verts[0].x << 16;
    155 	rL = colors[0].r << 16, gL = colors[0].g << 16, bL = colors[0].b << 16;
    156 	xR = verts[0].x << 16;
    157 	rR = colors[0].r << 16, gR = colors[0].g << 16, bR = colors[0].b << 16;
    158 
    159 	for (y = verts[0].y; y < verts[1].y; y++) {
    160 		draw_scanline(ren, y, xL >> 16, (C){(rL >> 16), (gL >> 16), (bL >> 16)},
    161 				xR >> 16, (C){(rR >> 16), (gR >> 16), (bR >> 16)});
    162 		xL += dx01; rL += dr01; gL += dg01; bL += db01;
    163 		xR += dx02; rR += dr02; gR += dg02; bR += db02;
    164 	}
    165 
    166 	/* Rasterize bottom part */
    167 	xL = verts[1].x << 16, rL = colors[1].r << 16, gL = colors[1].g << 16, bL = colors[1].b << 16;
    168 	for (y = verts[1].y; y < verts[2].y; y++) {
    169 		draw_scanline(ren, y, xL >> 16, (C){(u8)(rL >> 16), (u8)(gL >> 16), (u8)(bL >> 16)},
    170 				xR >> 16, (C){(u8)(rR >> 16), (u8)(gR >> 16), (u8)(bR >> 16)});
    171 		xL += dx12; rL += dr12; gL += dg12; bL += db12;
    172 		xR += dx02; rR += dr02; gR += dg02; bR += db02;
    173 	}
    174 }
    175 
    176 void
    177 REN_push_triangle(REN* ren, ivec2 verts[3], C colors[3])
    178 {
    179 	u8 i;
    180 
    181 	REN_flush(ren);
    182 
    183 	for (i = 0; i < 3; i++) {
    184 		ren->verts[ren->nvertices] = verts[i];
    185 		ren->colors[ren->nvertices] = colors[i];
    186 		ren->nvertices++;
    187 	}
    188 }
    189 
    190 void
    191 REN_push_quad(REN* ren, ivec2 verts[4], C colors[4])
    192 {
    193 	u8 i;
    194 
    195 	REN_flush(ren);
    196 
    197 	/* First triangle: vertices 0,1,2 */
    198 	for (i = 0; i < 3; i++) {
    199 		ren->verts[ren->nvertices] = verts[i];
    200 		ren->colors[ren->nvertices] = colors[i];
    201 		ren->nvertices++;
    202 	}
    203 	for (i = 1; i < 4; i++) {
    204 		ren->verts[ren->nvertices] = verts[i];
    205 		ren->colors[ren->nvertices] = colors[i];
    206 		ren->nvertices++;
    207 	}
    208 }
    209 
    210 void
    211 REN_flush(REN* ren) {
    212 	u32 i;
    213 	for (i = 0; i < ren->nvertices; i += 3)
    214 		REN_triangle(ren, ren->verts + i, ren->colors + i);
    215 	ren->nvertices = 0;
    216 }
    217 
    218 void
    219 REN_draw(REN* ren)
    220 {
    221 	SDL_UpdateTexture(ren->tex, NULL, ren->fb, W * sizeof(u32));
    222 	SDL_RenderCopy(ren->renderer, ren->tex, NULL, NULL);
    223 }
    224 
    225 void
    226 REN_display(REN* ren)
    227 {
    228 	if (ren->nvertices > 0)
    229 		REN_flush(ren);
    230 
    231 	REN_draw(ren);
    232 	SDL_RenderPresent(ren->renderer);
    233 }