nuclear@0: /* nuclear@0: 256-color 3D graphics hack for real-mode DOS. nuclear@0: Copyright (C) 2011 John Tsiombikas nuclear@0: nuclear@0: This program is free software: you can redistribute it and/or modify nuclear@0: it under the terms of the GNU General Public License as published by nuclear@0: the Free Software Foundation, either version 3 of the License, or nuclear@0: (at your option) any later version. nuclear@0: nuclear@0: This program is distributed in the hope that it will be useful, nuclear@0: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@0: GNU General Public License for more details. nuclear@0: nuclear@0: You should have received a copy of the GNU General Public License nuclear@0: along with this program. If not, see . nuclear@0: */ nuclear@0: static void SCAN_EDGE(struct vertex *v0, struct vertex *v1) nuclear@0: { nuclear@0: int i, start, end; nuclear@0: float dx, dy, dfdx; nuclear@0: #ifdef INTERP_DEPTH nuclear@0: float z, dz, dfdz; nuclear@0: #endif nuclear@0: #ifdef INTERP_ENERGY nuclear@0: float e, de, dfde; nuclear@0: #endif nuclear@3: #ifdef INTERP_TEX nuclear@3: float u, v, du, dv, dfdu, dfdv; nuclear@3: #endif nuclear@3: float x; nuclear@0: struct vertex *edge; nuclear@0: nuclear@0: dy = v1->pos.y - v0->pos.y; nuclear@0: if(dy < 1e-6 && dy > -1e-6) { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: dx = v1->pos.x - v0->pos.x; nuclear@0: dfdx = dx / dy; nuclear@0: nuclear@0: #ifdef INTERP_DEPTH nuclear@0: dz = v1->pos.z - v0->pos.z; nuclear@0: dfdz = dz / dy; nuclear@0: #endif nuclear@0: #ifdef INTERP_ENERGY nuclear@0: de = v1->energy - v0->energy; nuclear@0: dfde = de / dy; nuclear@0: #endif nuclear@3: #ifdef INTERP_TEX nuclear@3: du = v1->tc.x - v0->tc.x; nuclear@3: dv = v1->tc.y - v0->tc.y; nuclear@3: dfdu = du / dy; nuclear@3: dfdv = dv / dy; nuclear@3: #endif nuclear@0: nuclear@0: if(dy < 0.0) { nuclear@0: struct vertex *tmp = v0; nuclear@0: v0 = v1; nuclear@0: v1 = tmp; nuclear@0: edge = (st->ord == MGL_CCW) ? vright : vleft; nuclear@0: } else { nuclear@0: edge = (st->ord == MGL_CCW) ? vleft : vright; nuclear@0: } nuclear@0: nuclear@0: start = (int)ROUND(v0->pos.y); nuclear@0: end = (int)ROUND(v1->pos.y); nuclear@0: nuclear@9: if(start >= 0) { nuclear@9: nuclear@9: x = v0->pos.x; nuclear@0: #ifdef INTERP_DEPTH nuclear@9: z = v0->pos.z; nuclear@0: #endif nuclear@0: #ifdef INTERP_ENERGY nuclear@9: e = v0->energy; nuclear@0: #endif nuclear@3: #ifdef INTERP_TEX nuclear@9: u = v0->tc.x; nuclear@9: v = v0->tc.y; nuclear@3: #endif nuclear@9: } else { nuclear@9: float lines = -v0->pos.y; nuclear@9: nuclear@9: x = v0->pos.x + dfdx * lines; nuclear@9: #ifdef INTERP_DEPTH nuclear@9: z = v0->pos.z + dfdz * lines; nuclear@9: #endif nuclear@9: #ifdef INTERP_ENERGY nuclear@9: e = v0->energy + dfde * lines; nuclear@9: #endif nuclear@9: #ifdef INTERP_TEX nuclear@9: u = v0->tc.x + dfdu * lines; nuclear@9: v = v0->tc.y + dfdv * lines; nuclear@9: #endif nuclear@9: start = 0; nuclear@9: } nuclear@9: nuclear@9: if(end >= fb->height) { nuclear@9: end = fb->height - 1; nuclear@9: } nuclear@9: nuclear@9: nuclear@0: for(i=start; icidx; nuclear@0: #ifdef INTERP_DEPTH nuclear@0: edge[i].pos.z = z; nuclear@0: z += dfdz; nuclear@0: #endif nuclear@0: nuclear@0: #ifdef INTERP_ENERGY nuclear@0: edge[i].energy = e; nuclear@0: e += dfde; nuclear@0: #else nuclear@0: edge[i].energy = v0->energy; nuclear@0: #endif nuclear@3: nuclear@3: #ifdef INTERP_TEX nuclear@3: edge[i].tc.x = u; nuclear@3: edge[i].tc.y = v; nuclear@3: u += dfdu; nuclear@3: v += dfdv; nuclear@3: #endif nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static void SCAN_LINE(int y, unsigned char *sline) nuclear@0: { nuclear@3: int x0, x1, len, tmp, cidx; nuclear@3: #if defined(INTERP_DEPTH) || defined(INTERP_ENERGY) || defined(INTERP_TEX) nuclear@3: int i; nuclear@0: float x, dx; nuclear@0: #endif nuclear@0: #ifdef INTERP_DEPTH nuclear@0: float z, dz, dfdz; nuclear@0: #endif nuclear@0: #ifdef INTERP_ENERGY nuclear@0: float e, de, dfde; nuclear@0: #endif nuclear@3: #ifdef INTERP_TEX nuclear@3: int tx, ty; nuclear@3: float u, v, du, dv, dfdu, dfdv; nuclear@3: #endif nuclear@0: struct vertex *left, *right; nuclear@0: nuclear@0: x0 = (int)ROUND(vleft[y].pos.x); nuclear@0: x1 = (int)ROUND(vright[y].pos.x); nuclear@0: nuclear@0: if(x1 < x0) { nuclear@0: if(st->flags & MGL_CULL_FACE) { nuclear@0: return; nuclear@0: } nuclear@0: tmp = x0; nuclear@0: x0 = x1; nuclear@0: x1 = tmp; nuclear@0: nuclear@0: left = vright; nuclear@0: right = vleft; nuclear@0: } else { nuclear@0: left = vleft; nuclear@0: right = vright; nuclear@0: } nuclear@0: nuclear@9: if(x1 >= fb->width) { nuclear@9: x1 = fb->width - 1; nuclear@9: } nuclear@0: nuclear@0: cidx = left[y].cidx; nuclear@3: #if !defined(INTERP_DEPTH) && !defined(INTERP_ENERGY) && !defined(INTERP_TEX) nuclear@9: if(x0 < 0) x0 = 0; nuclear@9: len = x1 - x0; nuclear@9: assert(len >= 0); nuclear@0: /* no interpolation at all, just memset the whole scanline */ nuclear@0: memset(sline + x0, cidx + left[y].energy * st->col_range, len); nuclear@0: #else nuclear@0: /* otherwise do a loop and interpolate whatever needs interpolating */ nuclear@0: x = left[y].pos.x; nuclear@0: dx = right[y].pos.x - x; nuclear@0: nuclear@0: if(dx < 0.5 && dx > -0.5) { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@9: if(x0 >= 0) { nuclear@0: #ifdef INTERP_DEPTH nuclear@9: z = left[y].pos.z; nuclear@9: dz = right[y].pos.z - z; nuclear@9: dfdz = dz / dx; nuclear@0: #endif nuclear@0: #ifdef INTERP_ENERGY nuclear@9: e = left[y].energy; nuclear@9: de = right[y].energy - e; nuclear@9: dfde = de / dx; nuclear@0: #endif nuclear@3: #ifdef INTERP_TEX nuclear@9: u = left[y].tc.x; nuclear@9: v = left[y].tc.y; nuclear@9: du = right[y].tc.x - u; nuclear@9: dv = right[y].tc.y - v; nuclear@9: dfdu = du / dx; nuclear@9: dfdv = dv / dx; nuclear@3: #endif nuclear@9: } else { nuclear@9: float dist = -left[y].pos.x; nuclear@9: nuclear@9: #ifdef INTERP_DEPTH nuclear@9: dz = right[y].pos.z - left[y].pos.z; nuclear@9: dfdz = dz / dx; nuclear@9: z = left[y].pos.z + dfdz * dist; nuclear@9: #endif nuclear@9: #ifdef INTERP_ENERGY nuclear@9: de = right[y].energy - left[y].energy; nuclear@9: dfde = de / dx; nuclear@9: e = left[y].energy + dfde * dist; nuclear@9: #endif nuclear@9: #ifdef INTERP_TEX nuclear@9: du = right[y].tc.x - left[y].tc.x; nuclear@9: dv = right[y].tc.y - left[y].tc.y; nuclear@9: dfdu = du / dx; nuclear@9: dfdv = dv / dx; nuclear@9: u = left[y].tc.x + dfdu * dist; nuclear@9: v = left[y].tc.y + dfdv * dist; nuclear@9: #endif nuclear@9: x0 = 0; nuclear@9: } nuclear@9: nuclear@9: len = x1 - x0; nuclear@0: nuclear@0: for(i=0; ipixels; nuclear@9: unsigned short zval = (unsigned short)(z * USHRT_MAX); nuclear@9: unsigned short *zptr = fb->zbuf[ZTILE(pix)] + ZTILE_OFFS(pix); nuclear@9: nuclear@9: if(z < 0.0 || z >= 1.0 || zval > *zptr) { nuclear@9: # ifdef INTERP_TEX nuclear@9: u += dfdu; nuclear@9: v += dfdv; nuclear@9: # endif nuclear@9: # ifdef INTERP_ENERGY nuclear@9: e += dfde; nuclear@9: # endif nuclear@9: z += dfdz; nuclear@9: continue; nuclear@9: } nuclear@9: nuclear@9: *zptr = zval; nuclear@3: z += dfdz; nuclear@3: #endif nuclear@3: #ifdef INTERP_TEX nuclear@3: tx = (int)(u * st->tex.width) & st->tex.xmask; nuclear@3: ty = (int)(v * st->tex.height) & st->tex.ymask; nuclear@3: c = st->tex.pixels[(ty << st->tex.xshift) + tx]; nuclear@3: nuclear@3: u += dfdu; nuclear@3: v += dfdv; nuclear@3: #endif nuclear@0: #ifdef INTERP_ENERGY nuclear@3: c += e * st->col_range; nuclear@0: e += dfde; nuclear@3: #else nuclear@3: c += left[y].energy * st->col_range; nuclear@0: #endif nuclear@3: sline[x0 + i] = c; nuclear@0: } nuclear@0: #endif /* flat */ nuclear@0: }