deepstone

annotate src/scantmpl.h @ 40:1fa939507d8b

fast floating point->int conversion
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 15 Sep 2017 05:00:37 +0300
parents 17a5107b6fa4
children
rev   line source
nuclear@25 1 static void SCAN_EDGE(VERTEX *v0, VERTEX *v1)
nuclear@0 2 {
nuclear@0 3 int i, start, end;
nuclear@25 4 fixed dx, dy, dfdx;
nuclear@0 5 #ifdef INTERP_DEPTH
nuclear@25 6 fixed z, dz, dfdz;
nuclear@0 7 #endif
nuclear@0 8 #ifdef INTERP_ENERGY
nuclear@25 9 fixed e, de, dfde;
nuclear@0 10 #endif
nuclear@3 11 #ifdef INTERP_TEX
nuclear@38 12 #ifdef TEXMAP_PERSP_CORRECT
nuclear@38 13 fixed w, dw, dfdw;
nuclear@38 14 #endif
nuclear@25 15 fixed u, v, du, dv, dfdu, dfdv;
nuclear@3 16 #endif
nuclear@25 17 fixed x;
nuclear@25 18 VERTEX *edge;
nuclear@0 19
nuclear@0 20 dy = v1->pos.y - v0->pos.y;
nuclear@25 21 if(dy < FIXED_EPSILON && dy > -FIXED_EPSILON) {
nuclear@0 22 return;
nuclear@0 23 }
nuclear@0 24
nuclear@0 25 dx = v1->pos.x - v0->pos.x;
nuclear@25 26 dfdx = fixed_div(dx, dy);
nuclear@0 27
nuclear@0 28 #ifdef INTERP_DEPTH
nuclear@0 29 dz = v1->pos.z - v0->pos.z;
nuclear@25 30 dfdz = fixed_div(dz, dy);
nuclear@0 31 #endif
nuclear@0 32 #ifdef INTERP_ENERGY
nuclear@0 33 de = v1->energy - v0->energy;
nuclear@25 34 dfde = fixed_div(de, dy);
nuclear@0 35 #endif
nuclear@3 36 #ifdef INTERP_TEX
nuclear@38 37 #ifdef TEXMAP_PERSP_CORRECT
nuclear@38 38 dw = v1->pos.w - v0->pos.w;
nuclear@38 39 dfdw = fixed_div(dw, dy);
nuclear@38 40 #endif
nuclear@38 41
nuclear@3 42 du = v1->tc.x - v0->tc.x;
nuclear@3 43 dv = v1->tc.y - v0->tc.y;
nuclear@25 44 dfdu = fixed_div(du, dy);
nuclear@25 45 dfdv = fixed_div(dv, dy);
nuclear@3 46 #endif
nuclear@0 47
nuclear@25 48 if(dy < 0) {
nuclear@25 49 VERTEX *tmp = v0;
nuclear@0 50 v0 = v1;
nuclear@0 51 v1 = tmp;
nuclear@0 52 edge = (st->ord == MGL_CCW) ? vright : vleft;
nuclear@0 53 } else {
nuclear@0 54 edge = (st->ord == MGL_CCW) ? vleft : vright;
nuclear@0 55 }
nuclear@0 56
nuclear@25 57 start = (int)fixed_round(v0->pos.y);
nuclear@25 58 end = (int)fixed_round(v1->pos.y);
nuclear@0 59
nuclear@9 60 if(start >= 0) {
nuclear@9 61
nuclear@9 62 x = v0->pos.x;
nuclear@0 63 #ifdef INTERP_DEPTH
nuclear@9 64 z = v0->pos.z;
nuclear@0 65 #endif
nuclear@0 66 #ifdef INTERP_ENERGY
nuclear@9 67 e = v0->energy;
nuclear@0 68 #endif
nuclear@3 69 #ifdef INTERP_TEX
nuclear@38 70 #ifdef TEXMAP_PERSP_CORRECT
nuclear@38 71 w = v0->pos.w;
nuclear@38 72 #endif
nuclear@9 73 u = v0->tc.x;
nuclear@9 74 v = v0->tc.y;
nuclear@3 75 #endif
nuclear@9 76 } else {
nuclear@25 77 fixed lines = -v0->pos.y;
nuclear@9 78
nuclear@25 79 x = v0->pos.x + fixed_mul(dfdx, lines);
nuclear@9 80 #ifdef INTERP_DEPTH
nuclear@25 81 z = v0->pos.z + fixed_mul(dfdz, lines);
nuclear@9 82 #endif
nuclear@9 83 #ifdef INTERP_ENERGY
nuclear@25 84 e = v0->energy + fixed_mul(dfde, lines);
nuclear@9 85 #endif
nuclear@9 86 #ifdef INTERP_TEX
nuclear@38 87 #ifdef TEXMAP_PERSP_CORRECT
nuclear@38 88 w = v0->pos.w + fixed_mul(dfdw, lines);
nuclear@38 89 #endif
nuclear@25 90 u = v0->tc.x + fixed_mul(dfdu, lines);
nuclear@25 91 v = v0->tc.y + fixed_mul(dfdv, lines);
nuclear@9 92 #endif
nuclear@9 93 start = 0;
nuclear@9 94 }
nuclear@9 95
nuclear@9 96 if(end >= fb->height) {
nuclear@9 97 end = fb->height - 1;
nuclear@9 98 }
nuclear@9 99
nuclear@9 100
nuclear@0 101 for(i=start; i<end; i++) {
nuclear@0 102 edge[i].pos.x = x;
nuclear@0 103 x += dfdx;
nuclear@0 104
nuclear@0 105 edge[i].cidx = v0->cidx;
nuclear@0 106 #ifdef INTERP_DEPTH
nuclear@0 107 edge[i].pos.z = z;
nuclear@0 108 z += dfdz;
nuclear@0 109 #endif
nuclear@0 110
nuclear@0 111 #ifdef INTERP_ENERGY
nuclear@0 112 edge[i].energy = e;
nuclear@0 113 e += dfde;
nuclear@0 114 #else
nuclear@0 115 edge[i].energy = v0->energy;
nuclear@0 116 #endif
nuclear@3 117
nuclear@3 118 #ifdef INTERP_TEX
nuclear@38 119 #ifdef TEXMAP_PERSP_CORRECT
nuclear@38 120 edge[i].pos.w = w;
nuclear@38 121 w += dfdw;
nuclear@38 122 #endif
nuclear@38 123
nuclear@3 124 edge[i].tc.x = u;
nuclear@3 125 edge[i].tc.y = v;
nuclear@3 126 u += dfdu;
nuclear@3 127 v += dfdv;
nuclear@3 128 #endif
nuclear@0 129 }
nuclear@0 130 }
nuclear@0 131
nuclear@0 132 static void SCAN_LINE(int y, unsigned char *sline)
nuclear@0 133 {
nuclear@3 134 int x0, x1, len, tmp, cidx;
nuclear@3 135 #if defined(INTERP_DEPTH) || defined(INTERP_ENERGY) || defined(INTERP_TEX)
nuclear@3 136 int i;
nuclear@25 137 fixed x, dx;
nuclear@0 138 #endif
nuclear@0 139 #ifdef INTERP_DEPTH
nuclear@25 140 fixed z, dz, dfdz;
nuclear@0 141 #endif
nuclear@0 142 #ifdef INTERP_ENERGY
nuclear@25 143 fixed e, de, dfde;
nuclear@0 144 #endif
nuclear@3 145 #ifdef INTERP_TEX
nuclear@17 146 unsigned int tx, ty;
nuclear@25 147 fixed u, v, du, dv, dfdu, dfdv;
nuclear@38 148 fixed w, dw, dfdw;
nuclear@38 149 fixed tu, tv;
nuclear@3 150 #endif
nuclear@25 151 VERTEX *left, *right;
nuclear@0 152
nuclear@25 153 x0 = (int)fixed_round(vleft[y].pos.x);
nuclear@25 154 x1 = (int)fixed_round(vright[y].pos.x);
nuclear@0 155
nuclear@0 156 if(x1 < x0) {
nuclear@28 157 if(IS_ENABLED(st->flags, MGL_CULL_FACE)) {
nuclear@0 158 return;
nuclear@0 159 }
nuclear@0 160 tmp = x0;
nuclear@0 161 x0 = x1;
nuclear@0 162 x1 = tmp;
nuclear@0 163
nuclear@0 164 left = vright;
nuclear@0 165 right = vleft;
nuclear@0 166 } else {
nuclear@0 167 left = vleft;
nuclear@0 168 right = vright;
nuclear@0 169 }
nuclear@0 170
nuclear@9 171 if(x1 >= fb->width) {
nuclear@9 172 x1 = fb->width - 1;
nuclear@9 173 }
nuclear@0 174
nuclear@0 175 cidx = left[y].cidx;
nuclear@3 176 #if !defined(INTERP_DEPTH) && !defined(INTERP_ENERGY) && !defined(INTERP_TEX)
nuclear@9 177 if(x0 < 0) x0 = 0;
nuclear@9 178 len = x1 - x0;
nuclear@9 179 assert(len >= 0);
nuclear@0 180 /* no interpolation at all, just memset the whole scanline */
nuclear@25 181 memset(sline + x0, cidx + fixed_int(fixed_mul(left[y].energy, fixedi(st->col_range))), len);
nuclear@0 182 #else
nuclear@0 183 /* otherwise do a loop and interpolate whatever needs interpolating */
nuclear@0 184 x = left[y].pos.x;
nuclear@0 185 dx = right[y].pos.x - x;
nuclear@0 186
nuclear@25 187 if(dx < fixedf(0.5) && dx > -fixedf(0.5)) {
nuclear@0 188 return;
nuclear@0 189 }
nuclear@0 190
nuclear@9 191 if(x0 >= 0) {
nuclear@0 192 #ifdef INTERP_DEPTH
nuclear@9 193 z = left[y].pos.z;
nuclear@9 194 dz = right[y].pos.z - z;
nuclear@25 195 dfdz = fixed_div(dz, dx);
nuclear@0 196 #endif
nuclear@0 197 #ifdef INTERP_ENERGY
nuclear@9 198 e = left[y].energy;
nuclear@9 199 de = right[y].energy - e;
nuclear@25 200 dfde = fixed_div(de, dx);
nuclear@0 201 #endif
nuclear@3 202 #ifdef INTERP_TEX
nuclear@38 203 #ifdef TEXMAP_PERSP_CORRECT
nuclear@38 204 w = left[y].pos.w;
nuclear@38 205 dw = right[y].pos.w - w;
nuclear@38 206 dfdw = fixed_div(dw, dx);
nuclear@38 207 #endif
nuclear@38 208
nuclear@9 209 u = left[y].tc.x;
nuclear@9 210 v = left[y].tc.y;
nuclear@9 211 du = right[y].tc.x - u;
nuclear@9 212 dv = right[y].tc.y - v;
nuclear@25 213 dfdu = fixed_div(du, dx);
nuclear@25 214 dfdv = fixed_div(dv, dx);
nuclear@3 215 #endif
nuclear@9 216 } else {
nuclear@25 217 fixed dist = -left[y].pos.x;
nuclear@9 218
nuclear@9 219 #ifdef INTERP_DEPTH
nuclear@9 220 dz = right[y].pos.z - left[y].pos.z;
nuclear@25 221 dfdz = fixed_div(dz, dx);
nuclear@25 222 z = left[y].pos.z + fixed_mul(dfdz, dist);
nuclear@9 223 #endif
nuclear@9 224 #ifdef INTERP_ENERGY
nuclear@9 225 de = right[y].energy - left[y].energy;
nuclear@25 226 dfde = fixed_div(de, dx);
nuclear@25 227 e = left[y].energy + fixed_mul(dfde, dist);
nuclear@9 228 #endif
nuclear@9 229 #ifdef INTERP_TEX
nuclear@38 230 #ifdef TEXMAP_PERSP_CORRECT
nuclear@38 231 dw = right[y].pos.w - left[y].pos.w;
nuclear@38 232 dfdw = fixed_div(dw, dx);
nuclear@38 233 w = left[y].pos.w + fixed_mul(dfdw, dist);
nuclear@38 234 #endif
nuclear@38 235
nuclear@9 236 du = right[y].tc.x - left[y].tc.x;
nuclear@9 237 dv = right[y].tc.y - left[y].tc.y;
nuclear@25 238 dfdu = fixed_div(du, dx);
nuclear@25 239 dfdv = fixed_div(dv, dx);
nuclear@25 240 u = left[y].tc.x + fixed_mul(dfdu, dist);
nuclear@25 241 v = left[y].tc.y + fixed_mul(dfdv, dist);
nuclear@9 242 #endif
nuclear@9 243 x0 = 0;
nuclear@9 244 }
nuclear@9 245
nuclear@9 246 len = x1 - x0;
nuclear@0 247
nuclear@0 248 for(i=0; i<len; i++) {
nuclear@3 249 int c = cidx;
nuclear@3 250
nuclear@3 251 #ifdef INTERP_DEPTH
nuclear@10 252 long pix = (sline + x0 + i) - fb->pixels;
nuclear@25 253 #ifdef RAST_FLOAT
nuclear@40 254 /*unsigned short zval = (unsigned short)(z * USHRT_MAX);*/
nuclear@40 255 float zn = z + 1.0;
nuclear@40 256 unsigned short zval = ((*(long*)&zn) & 0x7fffff) >> 7;
nuclear@25 257 #else
nuclear@25 258 unsigned short zval = (unsigned short)((z >> 1) & 0xffff);
nuclear@25 259 #endif
nuclear@9 260 unsigned short *zptr = fb->zbuf[ZTILE(pix)] + ZTILE_OFFS(pix);
nuclear@9 261
nuclear@25 262 if(z < 0 || z >= fixedi(1) || zval > *zptr) {
nuclear@38 263 #ifdef INTERP_TEX
nuclear@9 264 u += dfdu;
nuclear@9 265 v += dfdv;
nuclear@38 266 #ifdef TEXMAP_PERSP_CORRECT
nuclear@38 267 w += dfdw;
nuclear@38 268 #endif
nuclear@38 269 #endif /* INTERP_TEX */
nuclear@38 270 #ifdef INTERP_ENERGY
nuclear@9 271 e += dfde;
nuclear@38 272 #endif
nuclear@9 273 z += dfdz;
nuclear@9 274 continue;
nuclear@9 275 }
nuclear@9 276
nuclear@9 277 *zptr = zval;
nuclear@3 278 z += dfdz;
nuclear@3 279 #endif
nuclear@3 280 #ifdef INTERP_TEX
nuclear@38 281 #ifdef TEXMAP_PERSP_CORRECT
nuclear@38 282 tu = fixed_div(u, w);
nuclear@38 283 tv = fixed_div(v, w);
nuclear@38 284 #else
nuclear@38 285 tu = u;
nuclear@38 286 tv = v;
nuclear@38 287 #endif
nuclear@38 288 tx = (unsigned int)fixed_int(fixed_mul(tu, fixedi(st->tex.width))) & st->tex.xmask;
nuclear@38 289 ty = (unsigned int)fixed_int(fixed_mul(tv, fixedi(st->tex.height))) & st->tex.ymask;
nuclear@3 290 c = st->tex.pixels[(ty << st->tex.xshift) + tx];
nuclear@3 291
nuclear@3 292 u += dfdu;
nuclear@3 293 v += dfdv;
nuclear@38 294 #ifdef TEXMAP_PERSP_CORRECT
nuclear@38 295 w += dfdw;
nuclear@3 296 #endif
nuclear@38 297 #endif /* INTERP_TEX */
nuclear@0 298 #ifdef INTERP_ENERGY
nuclear@25 299 c += fixed_int(fixed_mul(e, fixedi(st->col_range)));
nuclear@0 300 e += dfde;
nuclear@3 301 #else
nuclear@25 302 c += fixed_int(fixed_mul(left[y].energy, fixedi(st->col_range)));
nuclear@0 303 #endif
nuclear@3 304 sline[x0 + i] = c;
nuclear@0 305 }
nuclear@0 306 #endif /* flat */
nuclear@0 307 }