#include "map.h" #include "maths.h" #include "plat.h" #include "render.h" #include static int font_w = 960; static unsigned font_data[] = { 0x00000000, 0x00003000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0cc0c000, 0x8000301b, 0x60601803, 0x00000000, 0x20000000, 0x0780c078, 0x83f0e01e, 0xe0783f07, 0x60000001, 0x1e018000, 0x07e0c078, 0xe3f87e1f, 0xe0cc1e0f, 0x1e638f01, 0x1f0c6318, 0x07e1f07e, 0xc330fc1e, 0x30cc318c, 0x021e0fc3, 0x000101e0, 0x00e00000, 0x0000e000, 0xc00e0007, 0x3c038c00, 0x00000000, 0x00000000, 0x00001000, 0x00000000, 0x30380000, 0x0000c070, 0x0cc1e000, 0xc630f81b, 0xc0301806, 0x00000cc0, 0x30000000, 0x0cc0f0cc, 0xc030f033, 0x30cc330c, 0x30000003, 0x33030000, 0x8cc1e0cc, 0xc230cc33, 0xc0cc3308, 0x0c630600, 0x318ce3b8, 0x0cc318cc, 0xc330b433, 0x30cc318c, 0x06060cc3, 0x00038180, 0x00c00018, 0x8000c000, 0x000c000d, 0x30030000, 0x00000000, 0x00000000, 0x00001800, 0x00000000, 0x300c0000, 0x0409e0c0, 0x8481e000, 0xc3300c3f, 0x80180c06, 0x000c0781, 0x18000000, 0x0c00c0ec, 0xc1f0d830, 0x30cc1800, 0x180c0303, 0x30060000, 0x8cc330ec, 0xc0318c01, 0xc0cc3180, 0x0c330600, 0x318de3f8, 0x0cc318cc, 0xc3303003, 0x3078318c, 0x0c060643, 0x0006c180, 0x07c0f018, 0x81e0f81e, 0xf06c3701, 0x30330f00, 0x1e07c1f8, 0x0ee37076, 0xc330fc3e, 0x30c6318c, 0x300c0fc3, 0x0e0f20c0, 0x0001e000, 0x8180781b, 0x80180013, 0x000c1fe1, 0x0c000000, 0x0600c0dc, 0xc300cc1c, 0xe0780c07, 0x0c0c0303, 0x180c03f0, 0x87c330ec, 0xc1f18c01, 0xc0fc0187, 0x0c1f0600, 0x318fe358, 0x07c3187c, 0xc330300e, 0xe030358c, 0x18060301, 0x000c6180, 0x0cc18030, 0xc330cc33, 0xc0dc1987, 0x301b0c00, 0x330cc358, 0x0dc198cc, 0xc3301803, 0x306c358c, 0x00060643, 0x1b060180, 0x0000c000, 0xc0c0c01b, 0x8018001e, 0x003f0781, 0x060003f0, 0x0300c0cc, 0xc301fc30, 0x00cc0c0c, 0x0c000003, 0x0c0c0000, 0x8cc3f00c, 0xc0318c01, 0xc0cc3980, 0x0c330660, 0x318f6318, 0x06c3980c, 0xc3303018, 0xc078358c, 0x30060180, 0x00000180, 0x0cc1f000, 0x83f0cc03, 0xc0cc1981, 0x301f0c00, 0x330cc358, 0x00c198cc, 0xc330181e, 0x3038358c, 0x300c0303, 0x318000c0, 0x80000000, 0xc6607c3f, 0xc030000c, 0x300c0cc0, 0x03030000, 0x0180c0cc, 0xc330c033, 0x30cc0c0c, 0x180c0303, 0x000603f0, 0x8cc3308c, 0xc230cc33, 0xc0cc3300, 0x8c630660, 0x318e6318, 0x0cc1f00c, 0x83303033, 0xc0cc1f07, 0x600609c0, 0x00000180, 0x0cc19800, 0x8030cc33, 0xc0cc1f01, 0x30330cc0, 0x330cc358, 0x00c198cc, 0x8330d830, 0xe06c1f07, 0x300c0981, 0x318000c0, 0x0000c000, 0x8630301b, 0x6060001b, 0x300c0000, 0x01830000, 0x0fc3f078, 0x81e0c01e, 0xe0780c07, 0x300c0301, 0x0c030000, 0x07e33078, 0xe3f87e1f, 0xe0cc3e01, 0xfe6383c1, 0x1f0c6318, 0x0ce3c01e, 0x01e0781e, 0xe0cc1b03, 0xc01e0fc1, 0x000001e0, 0x07e3f000, 0xc1e0f81e, 0xf0ce1803, 0xfc338783, 0x1e0cc318, 0x01e1f07c, 0x06e0701f, 0x80c61b03, 0x30380fc1, 0x3f800070, 0x0000c000, 0x0000301b, 0x00000000, 0x18000000, 0x00800000, 0x00000000, 0x00000000, 0x00000000, 0x60060000, 0x00018000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0x7f800000, 0x00000000, 0x00000000, 0x00000f00, 0x00000000, 0x00000000, 0x0001800c, 0x00000000, 0xf0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0003c01e, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; static int smol_font_w = 384; static unsigned smol_font_data[] = { 0x2296a520, 0x40000524, 0x77757767, 0x60002077, 0x6773637e, 0x69b15475, 0x95576767, 0x02616755, 0x66640102, 0x00021421, 0x00020000, 0xf0326000, 0x2543e520, 0x20002242, 0x41152645, 0x92740277, 0x1135175d, 0x9bf13427, 0x95523595, 0x05422272, 0x72d66364, 0x73f25003, 0x95576677, 0xfa6233a9, 0x06267000, 0x20727542, 0x27674145, 0x44022045, 0x53151571, 0x9d915525, 0xf55243d7, 0x00422122, 0x47351550, 0x55d23425, 0xb5522277, 0xf5222266, 0x0b935020, 0x12022024, 0x277437e7, 0x42742277, 0x61736756, 0x69975775, 0xb27235e1, 0x70646725, 0x32666370, 0x75945625, 0xf2763241, 0xf0326639, }; Colour make_colour(unsigned rgb, unsigned char a) { Colour r; r.r = (unsigned char)(rgb >> 16); r.g = (unsigned char)(rgb >> 8); r.b = (unsigned char)rgb; r.a = a; return r; } Colour make_red(void) { return make_colour(0xff0000, 0xff); } Colour make_green(void) { return make_colour(0x00ff00, 0xff); } Colour make_blue(void) { return make_colour(0x0000ff, 0xff); } Colour make_cyan(void) { return make_colour(0x00ffff, 0xff); } Colour make_pink(void) { return make_colour(0xff00ff, 0xff); } Colour make_yellow(void) { return make_colour(0xffff00, 0xff); } Colour make_aliceblue(void) { return make_colour(0xf0f8ff, 0xff); } Colour blend(Colour dst, Colour src) { int ima; ima = 0xff - src.a; dst.r = (unsigned char)(((src.r * src.a) + (dst.r * ima)) >> 8); dst.g = (unsigned char)(((src.g * src.a) + (dst.g * ima)) >> 8); dst.b = (unsigned char)(((src.b * src.a) + (dst.b * ima)) >> 8); return dst; } Colour blend_mod(Colour dst, Colour src, Colour mod) { int ima; src.a = (src.a * mod.a) >> 8; ima = 0xff - src.a; dst.r = (unsigned char)(((src.r * mod.r * src.a) >> 16) + ((dst.r * ima) >> 8)); dst.g = (unsigned char)(((src.g * mod.g * src.a) >> 16) + ((dst.g * ima) >> 8)); dst.b = (unsigned char)(((src.b * mod.b * src.a) >> 16) + ((dst.b * ima) >> 8)); return dst; } Colour col_mul(Colour a, Colour b) { Colour r; r.r = (a.r * b.r) >> 8; r.g = (a.g * b.g) >> 8; r.b = (a.b * b.b) >> 8; r.a = (a.a * b.a) >> 8; return r; } void ren_begin(Renderer* r, Colour* t, int* d, int w, int h) { r->t = t; r->vp[0] = w; r->vp[1] = h; r->d = d; r->clip[0] = 0; r->clip[1] = 0; r->clip[2] = w; r->clip[3] = h; r->asp = (w << fbits) / h; r->n = 256; } void ren_end(Renderer* r) { (void)r; } void ren_clear(Renderer* r) { Colour c = { 0 }; ren_clearc(r, c); } void ren_clearc(Renderer* r, Colour c) { Colour* d = &r->t[r->clip[0] + r->clip[1] * r->vp[0]]; int s = r->vp[0] - (r->clip[2] - r->clip[0]), y; for (y = r->clip[1]; y < r->clip[3]; y++) { int x; for (x = r->clip[0]; x < r->clip[2]; x++) { *d = c; d++; } d += s; } } void ren_cleard(Renderer* r, int depth) { int* d = &r->d[r->clip[0] + r->clip[1] * r->vp[0]]; int s = r->vp[0] - (r->clip[2] - r->clip[0]), y; for (y = r->clip[1]; y < r->clip[3]; y++) { int x; for (x = r->clip[0]; x < r->clip[2]; x++) { *d = depth; d++; } d += s; } } void ren_clip(Renderer* r, const Rect* c) { r->clip[0] = c->x; r->clip[1] = c->y; r->clip[2] = c->x + c->w; r->clip[3] = c->y + c->h; } void ren_point(Renderer* r, Colour c, int x, int y) { if (x < r->clip[0]) return; if (y < r->clip[1]) return; if (x >= r->clip[2]) return; if (y >= r->clip[3]) return; r->t[x + y * r->vp[0]] = c; } #define imp_ren_char(chw, chh, fw, data) \ int i, j, k, l, ex, ey, s; \ Colour* dst; \ Rect re = { 0, 0, chw, chh }; \ Rect sub = { 0, 0, chh, chh }; \ re.x = x; \ re.y = y; \ sub.x = (ch - ' ') * chw; \ rect_clipsr(&re, &sub, r->clip); \ ex = re.x + re.w; \ ey = re.y + re.h; \ dst = r->t + (re.x + re.y * r->vp[0]); \ s = r->vp[0] - re.w; \ for (j = re.y, l = sub.y; j < ey; j++, l++) { \ for (i = re.x, k = sub.x; i < ex; i++, k++) { \ int si = k + l * fw; \ unsigned bits = data[si >> 5]; \ int bit = bits & 1 << (si & 0x1f); \ if (bit) \ *dst = blend(*dst, c); \ dst++; \ } \ dst += s; \ } void ren_char( Renderer* r, Colour c, int x, int y, char ch ) { imp_ren_char( 10, 10, font_w, font_data ); } void ren_chars( Renderer* r, Colour c, int x, int y, char ch ) { imp_ren_char( 4, 4, smol_font_w, smol_font_data ); } #undef imp_ren_char void ren_text( Renderer* r, Colour c, int x, int y, const char* t ) { const char* s; for (s = t; *s; s++, x += 10) ren_char(r, c, x, y, *s); } void ren_texts( Renderer* r, Colour c, int x, int y, const char* t ) { const char* s; for (s = t; *s; s++, x += 5) ren_chars(r, c, x, y, *s); } void swap_vert(int* a, int* b, int ec) { int t, i; for (i = 0; i < ec; i++) { t = a[i]; a[i] = b[i]; b[i] = t; } } int tri_hand( const int* v0, const int* v1, const int* v2 ) { return (v1[0] - v0[0]) * (v2[1] - v0[1]) - (v2[0] - v0[0]) * (v1[1] - v0[1]) > 0; } int tri_winding( const int* v0, const int* v1, const int* v2 ) { return (v1[1] - v0[1]) * (v2[0] - v1[0]) - (v1[0] - v0[0]) * (v2[1] - v1[1]); } /*Colour sample_tex( const Texture* t, int u, int v ) { vec3 start, end, col; int i; Colour r = { 0 }; const unsigned* data = (const unsigned*)&t[1]; int x = ((u * t->w) >> fbits) & (t->w - 1); int y = ((v * t->h) >> fbits) & (t->h - 1); unsigned palette = data[(x / 4 + y / 4 * (t->w / 4)) * 2]; unsigned indices = data[(x / 4 + y / 4 * (t->w / 4)) * 2 + 1]; start.r = (float)((palette & (31 << 27)) >> 27) / 32.0f; start.g = (float)((palette & (63 << 21)) >> 21) / 64.0f; start.b = (float)((palette & (31 << 16)) >> 16) / 32.0f; end.r = (float)((palette & (31 << 11)) >> 11) / 32.0f; end.g = (float)((palette & (63 << 5)) >> 5) / 64.0f; end.b = (float)((palette & (31 )) ) / 32.0f; i = x % 4 + (y % 4) * 4; i = (indices & (3 << i * 2)) >> i * 2; lerp(&col, &start, &end, (float)i / 3.0f); r.r = (int)(col.r * 255.0f); r.g = (int)(col.g * 255.0f); r.b = (int)(col.b * 255.0f); return r; }*/ Colour sample_tex( const Texture* t, int u, int v ) { int x = ((u * t->w) >> fbits) & (t->w - 1); int y = ((v * t->h) >> fbits) & (t->h - 1); Colour r; int s[3]; int i; int coord = ((x >> 2) + (y >> 2) * (t->w >> 2)) << 1; const unsigned* data = (const unsigned*)&t[1]; unsigned pal = data[coord]; unsigned ind = data[coord + 1]; s[0] = (pal & (31 << 27)) >> 24; s[1] = (pal & (63 << 21)) >> 19; s[2] = (pal & (31 << 16)) >> 13; i = ((x & 3) + ((y & 3) << 2)) << 1; i = (ind & (3 << i)) >> i; r.r = s[0] + (i * ((int)((pal & (31 << 11)) >> 8) - s[0]) / 3); r.g = s[1] + (i * ((int)((pal & (63 << 5)) >> 3) - s[1]) / 3); r.b = s[2] + (i * ((int)((pal & (31 )) << 3) - s[2]) / 3); r.a = 0xff; return r; } typedef struct { int x, y; int dx, dy; int sx, sy; int e; } Line; void init_line( Line* l, const int* f, const int* t ) { const int dx = abs(t[0] - f[0]); const int dy = -abs(t[1] - f[1]); l->e = dx + dy; l->dx = dx; l->dy = dy; l->sx = f[0] < t[0]? 1: -1; l->sy = f[1] < t[1]? 1: -1; l->x = f[0]; l->y = f[1]; } void init_lerp( Line* l, int a, int b, int x, int y ) { int f[2], t[2]; f[0] = a; f[1] = x; t[0] = b; t[1] = y; init_line(l, f, t); } void step_line( Line* l ) { const int e2 = l->e * 2; const int dx = l->dx; const int dy = l->dy; if (e2 > dy) { l->e += dy; l->x += l->sx; } if (e2 <= dx) { l->e += dx; l->y += l->sy; } } void ren_line( Renderer* r, Colour c, const int* s, const int* e ) { Line l; init_line(&l, s, e); while (l.x != e[0] || l.y != e[1]) { Colour* dst = &r->t[l.x + l.y * r->vp[0]]; if (l.x < r->clip[0] || l.y < r->clip[1]) goto step; if (l.x >= r->clip[2] || l.y >= r->clip[3]) goto step; *dst = blend(*dst, c); step: step_line(&l); } } void ren_tri( Renderer* r, const int* iv0, const int* iv1, const int* iv2, const Texture* tex ) { #define ic 6 #define ec 8 int ha, i; const int fcx = r->clip[2]; const int fcy = r->clip[3]; int v0[ec], v1[ec], v2[ec]; Line ne, fe; /* near and far edges */ Line ni[ic], fi[ic]; /* near and far interpolants */ Line xi[ic]; /* scanline interpolant */ if (tri_winding(iv0, iv1, iv2) > 0) return; vec_cpy(v0, iv0, ec); vec_cpy(v1, iv1, ec); vec_cpy(v2, iv2, ec); if (v0[1] > v1[1]) swap_vert(v0, v1, ec); if (v1[1] > v2[1]) swap_vert(v1, v2, ec); if (v0[1] > v1[1]) swap_vert(v0, v1, ec); ha = tri_hand(v0, v1, v2); if (ha) { init_line(&ne, v0, v2); init_line(&fe, v0, v1); for (i = 0; i < ic; i++) { init_lerp( &ni[i], v0[2 + i], v2[2 + i], v0[1], v2[1] ); init_lerp( &fi[i], v0[2 + i], v1[2 + i], v0[1], v1[1] ); } } else { init_line(&ne, v0, v1); init_line(&fe, v0, v2); for (i = 0; i < ic; i++) { init_lerp( &ni[i], v0[2 + i], v1[2 + i], v0[1], v1[1] ); init_lerp( &fi[i], v0[2 + i], v2[2 + i], v0[1], v2[1] ); } } if (v0[1] > fcy) return; if (v1[1] > fcy) v1[1] = fcy; #define scanline\ int x, ex = mini(fe.x, fcx);\ if (fe.y >= r->clip[1]) { \ for (i = 0; i < ic; i++)\ init_lerp(\ &xi[i],\ ni[i].x, fi[i].x,\ ne.x, fe.x\ );\ for (x = ne.x; x < ex; x++) {\ Colour col;\ if (x >= r->clip[0]) { \ col.r = (xi[3].x * 255) >> fbits;\ col.g = (xi[4].x * 255) >> fbits;\ col.b = (xi[5].x * 255) >> fbits;\ col.a = 0xff;\ if (xi[0].x < r->d[x + fe.y * r->vp[0]]) { \ r->t[x + fe.y * r->vp[0]] = col_mul(\ sample_tex(tex, xi[1].x, xi[2].x),\ col\ );\ r->d[x + fe.y * r->vp[0]] = xi[0].x; \ } \ } \ for (i = 0; i < ic; i++)\ while (xi[i].y != x)\ step_line(&xi[i]);\ }\ }\ step_line(&fe);\ for (i = 0; i < ic; i++)\ while (fi[i].y != fe.y)\ step_line(&fi[i]);\ while (ne.y != fe.y)\ step_line(&ne);\ for (i = 0; i < ic; i++)\ while (ni[i].y != ne.y)\ step_line(&ni[i]); while (fe.y < v1[1]) { scanline } if (ha) { init_line(&fe, v1, v2); for (i = 0; i < ic; i++) init_lerp( &fi[i], v1[2 + i], v2[2 + i], v1[1], v2[1] ); } else { init_line(&ne, v1, v2); for (i = 0; i < ic; i++) init_lerp( &ni[i], v1[2 + i], v2[2 + i], v1[1], v2[1] ); } if (v2[1] > fcy) v2[1] = fcy; while (fe.y < v2[1]) { scanline } #undef scanline #undef ic #undef ec } #define max_clip 6 void ren_tri3( Renderer* r, const int* iv0, const int* iv1, const int* iv2, const Texture* tex ) { #define ec 8 #define ec2 (ec) int tri[ec2 * 3]; int tc = 1, i; vec_cpy(&tri[0], iv0, ec); vec_cpy(&tri[8], iv1, ec); vec_cpy(&tri[16], iv2, ec); if (tri[2] < r->n) tri[2] = r->n; if (tri[10] < r->n) tri[10] = r->n; if (tri[18] < r->n) tri[18] = r->n; if ( tri[2] == tri[10] && tri[2] == tri[18] ) return; for (i = 0; i < tc; i++) { int ti = i * ec, j; for (j = 0; j < 3; j++) { int vi = ti + j * ec; persp(&tri[vi], r->asp); ndc2clip(r->vp, &tri[vi]); } if (!tri_os(r, &tri[0], &tri[8], &tri[16])) continue; ren_tri( r, &tri[ti], &tri[ti + 8], &tri[ti + 16], tex ); } #undef ec #undef ec2 } int tri_os( const Renderer* r, const int* v0, const int* v1, const int* v2 ) { return point_os(r, v0[0], v0[1]) || point_os(r, v1[0], v1[1]) || point_os(r, v2[0], v2[1]); } int point_os( const Renderer* r, int x, int y ) { return x >= r->clip[0] && y >= r->clip[1] && x < r->clip[2] && y < r->clip[3]; } void ren_mesh( Renderer* r, const Mesh* m, const Texture* tex ) { int vc = m->vc; int tri[8 * 3]; int n[4]; int i; for (i = 0; i < vc; i += 3) { int j; for (j = 0; j < 3; j++) { Mesh_Vert v = m->verts[i + j]; int* wv = &tri[j * 8]; vec_cpy(wv, &m->p[v.p * 3], 3); wv[3] = f1; mtx_apply(mtx_peek(), wv); } for (j = 0; j < 3; j++) { Mesh_Vert v = m->verts[i + j]; int* wv = &tri[j * 8]; n[0] = m->n[v.n * 3 + 0]; n[1] = m->n[v.n * 3 + 1]; n[2] = m->n[v.n * 3 + 2]; n[3] = 0; mtx_apply(mtx_peek(), n); wv[3] = m->t[v.t * 2 + 0]; wv[4] = m->t[v.t * 2 + 1]; { /* todo proper lighting */ int ld[] = { f1/2, f1/2, -f1/2 }; int nd[] = { f1/2, f1/2, f1/2 }; int vd[] = { 0, 0, -f1 }; int rd[4]; int d = maxi(0, vec_dot(n, ld, 3)), s, l; int a = 60; vec_ref(rd, nd, vd, 3); s = fpow(maxi(0, vec_dot(n, rd, 3)), 7) * 4; l = mini(d + s + a, f1); wv[5] = l; wv[6] = l; wv[7] = l; } } ren_tri3(r, &tri[0], &tri[8], &tri[16], tex); } } void ren_map( Renderer* r, const struct Map* map, const int* pos, const int* dir, const int* left ) { int x, w, h, hh; const int* data = (const int*)&map[1]; w = r->vp[0] << fbits; h = r->vp[1] << fbits; hh = h / 2; for (x = r->clip[0]; x < r->clip[2]; x++) { Line l; int ray = ((2 * x) << (fbits * 2)) / w - f1; int d[2], plane[2]; d[0] = ((left[0] * ray) >> fbits); d[1] = ((left[1] * ray) >> fbits); plane[0] = pos[0] - d[0]; plane[1] = pos[1] - d[1]; d[0] = dir[0] - d[0]; d[1] = dir[1] - d[1]; d[0] = (pos[0] + d[0] * 4); d[1] = (pos[1] + d[1] * 4); init_line(&l, pos, d); while (1) { int mp[2], tile; mp[0] = l.x >> fbits; mp[1] = l.y >> fbits; if ( mp[0] < 0 || mp[1] < 0 || mp[0] >= map->w || mp[1] >= map->h ) break; tile = data[mp[0] + mp[1] * map->w]; if (tile) { int lp[2], sy, ey, d, y; lp[0] = l.x; lp[1] = l.y; d = vec_dist(lp, lp, plane, 2); sy = (r->vp[1] / 2) - (((hh << fbits) / d) >> fbits); ey = (r->vp[1] / 2) + (((hh << fbits) / d) >> fbits); sy = maxi(sy, r->clip[1]); ey = mini(ey, r->clip[3]); for (y = sy; y < ey; y++) { int coord = x + y * r->vp[0]; Colour c = { 0, 0, 0, 255 }; c.r = (((16 << fbits ) - d) / 16); if (d < r->d[coord]) { r->d[coord] = d; r->t[coord] = c; } } break; } step_line(&l); } } }