NTMAPOUT.H 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. //
  2. // This is the outer loop of the texture mapper.
  3. //
  4. // Put inside a function like:
  5. // void ntmap_outerloop( g3ds_tmap *t )
  6. //
  7. // Uses the following #defines
  8. //
  9. // #define LINEAR 1 // 0=Perspective, 1=Linear
  10. // #define LIGHTING 1 // 0=No lighting, 1=Use lighting
  11. // #define INNER_LOOP asm_tmap_per // Function to be called when ready to draw.
  12. // #define CHECK_WINDOW 1 // Set to 1 to check window clip
  13. // #define USE_UVS 1 // Set to 1 to allow UV interpolation
  14. //
  15. // Optimizations:
  16. // * 1.40% In per/8 method by taking out the scanline function that was between
  17. // the outer loop and the inner. Also, I made the lighting, linear, etc
  18. // be compile-time rather than run-time switches in the outer loop. This
  19. // should also speed up the other forms of the texture mapper, but I didn't
  20. // profile them. This is the change that created ntmapout.h.
  21. // * 0.15% In perspective outer loop by getting rid of the redundant multiply
  22. // (xright*zright) that is done in outer loop and compute_du_dy.
  23. // ***** The two above improvements netted a 1.50% increase in test case ******
  24. //
  25. int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom
  26. int topy,boty,y, dy;
  27. fix dx_dy_left,dx_dy_right;
  28. #if USE_UVS == 1
  29. fix du_dy_left,du_dy_right;
  30. fix dv_dy_left,dv_dy_right;
  31. fix uleft,vleft,uright,vright;
  32. #endif
  33. #if LIGHTING == 1
  34. fix dl_dy_left,dl_dy_right;
  35. fix lleft,lright;
  36. #endif
  37. #if LINEAR == 0
  38. fix zleft,zright;
  39. fix dz_dy_left,dz_dy_right;
  40. #endif
  41. fix recip_dyl, recip_dyr;
  42. int max_y_vertex;
  43. fix xleft,xright;
  44. int next_break_left, next_break_right;
  45. int last_one = 0;
  46. fix dx;
  47. g3ds_vertex *v3d;
  48. #if LINEAR == 0
  49. // If perspective, then we need to multiply all of
  50. // the uv's by one over Z.
  51. v3d = t->verts;
  52. for (y=0; y<t->nv; y++, v3d++) {
  53. v3d->u = fixmul( v3d->u, v3d->z >> Z_SHIFTER );
  54. v3d->v = fixmul( v3d->v, v3d->z >> Z_SHIFTER );
  55. }
  56. #endif
  57. v3d = t->verts;
  58. // Determine top and bottom y coords.
  59. compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex);
  60. // Set top and bottom (of entire texture map) y coordinates.
  61. topy = f2i(v3d[vlt].y2d);
  62. boty = f2i(v3d[max_y_vertex].y2d);
  63. if (topy > Window_clip_bot)
  64. return;
  65. if (boty > Window_clip_bot)
  66. boty = Window_clip_bot;
  67. // Set amount to change x coordinate for each advance to next scanline.
  68. dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
  69. if (dy < FIX_RECIP_TABLE_SIZE)
  70. recip_dyl = fix_recip[dy];
  71. else
  72. recip_dyl = F1_0/dy;
  73. dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl);
  74. dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
  75. if (dy < FIX_RECIP_TABLE_SIZE)
  76. recip_dyr = fix_recip[dy];
  77. else
  78. recip_dyr = F1_0/dy;
  79. dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr);
  80. // Set initial values for x, u, v
  81. xleft = v3d[vlt].x2d;
  82. xright = v3d[vrt].x2d;
  83. #if USE_UVS == 1
  84. uleft = v3d[vlt].u;
  85. vleft = v3d[vlt].v;
  86. du_dy_left = fixmul(t->verts[vlb].u - uleft, recip_dyl);
  87. dv_dy_left = fixmul(t->verts[vlb].v - vleft, recip_dyl);
  88. uright = v3d[vrt].u;
  89. vright = v3d[vrt].v;
  90. du_dy_right = fixmul(t->verts[vrb].u - uright, recip_dyr);
  91. dv_dy_right = fixmul(t->verts[vrb].v - vright, recip_dyr);
  92. #endif
  93. #if LINEAR == 0
  94. zleft = v3d[vlt].z;
  95. dz_dy_left = fixmul(t->verts[vlb].z - zleft, recip_dyl);
  96. zright = v3d[vrt].z;
  97. dz_dy_right = fixmul(t->verts[vrb].z - zright, recip_dyr);
  98. #endif
  99. #if LIGHTING == 1
  100. lleft = v3d[vlt].l;
  101. dl_dy_left = fixmul(t->verts[vlb].l - lleft, recip_dyl);
  102. lright = v3d[vrt].l;
  103. dl_dy_right = fixmul(t->verts[vrb].l - lright, recip_dyr);
  104. #endif
  105. // scan all rows in texture map from top through first break.
  106. next_break_left = f2i(v3d[vlb].y2d);
  107. next_break_right = f2i(v3d[vrb].y2d);
  108. for (y = topy; y < boty; y++) {
  109. // See if we have reached the end of the current left edge, and if so, set
  110. // new values for dx_dy and x,u,v
  111. if (y == next_break_left) {
  112. fix recip_dy;
  113. // Handle problem of double points. Search until y coord is different. Cannot get
  114. // hung in an infinite loop because we know there is a vertex with a lower y coordinate
  115. // because in the for loop, we don't scan all spanlines.
  116. while (y == f2i(v3d[vlb].y2d)) {
  117. vlt = vlb;
  118. vlb = prevmod(vlb,t->nv);
  119. }
  120. next_break_left = f2i(v3d[vlb].y2d);
  121. dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
  122. if (dy < FIX_RECIP_TABLE_SIZE)
  123. recip_dy = fix_recip[dy];
  124. else
  125. recip_dy = F1_0/dy;
  126. dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
  127. xleft = v3d[vlt].x2d;
  128. #if USE_UVS == 1
  129. uleft = v3d[vlt].u;
  130. vleft = v3d[vlt].v;
  131. du_dy_left = fixmul(t->verts[vlb].u - uleft, recip_dy);
  132. dv_dy_left = fixmul(t->verts[vlb].v - vleft, recip_dy);
  133. #endif
  134. #if LINEAR == 0
  135. zleft = v3d[vlt].z;
  136. dz_dy_left = fixmul(t->verts[vlb].z - zleft, recip_dy);
  137. #endif
  138. #if LIGHTING == 1
  139. lleft = v3d[vlt].l;
  140. dl_dy_left = fixmul(t->verts[vlb].l - lleft, recip_dy);
  141. #endif
  142. }
  143. // See if we have reached the end of the current left edge, and if so, set
  144. // new values for dx_dy and x. Not necessary to set new values for u,v.
  145. if (y == next_break_right) {
  146. fix recip_dy;
  147. while (y == f2i(v3d[vrb].y2d)) {
  148. vrt = vrb;
  149. vrb = succmod(vrb,t->nv);
  150. }
  151. next_break_right = f2i(v3d[vrb].y2d);
  152. dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
  153. if (dy < FIX_RECIP_TABLE_SIZE)
  154. recip_dy = fix_recip[dy];
  155. else
  156. recip_dy = F1_0/dy;
  157. dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
  158. xright = v3d[vrt].x2d;
  159. #if USE_UVS == 1
  160. uright = v3d[vrt].u;
  161. vright = v3d[vrt].v;
  162. du_dy_right = fixmul(t->verts[vrb].u - uright, recip_dy);
  163. dv_dy_right = fixmul(t->verts[vrb].v - vright, recip_dy);
  164. #endif
  165. #if LINEAR == 0
  166. zright = v3d[vrt].z;
  167. dz_dy_right = fixmul(t->verts[vrb].z - zright, recip_dy);
  168. #endif
  169. #if LIGHTING == 1
  170. lright = v3d[vrt].l;
  171. dl_dy_right = fixmul(t->verts[vrb].l - lright, recip_dy);
  172. #endif
  173. }
  174. draw_scanline:
  175. fx_xright = f2i(xright);
  176. fx_xleft = f2i(xleft);
  177. dx = fx_xright - fx_xleft;
  178. if ( (y >= Window_clip_top) && (dx>=0) && (xright>=0) && (xleft<=xright) ) {
  179. fix recip_dx;
  180. fx_y = y;
  181. // setup to call assembler scanline renderer
  182. if (dx < FIX_RECIP_TABLE_SIZE)
  183. recip_dx = fix_recip[dx];
  184. else
  185. recip_dx = F1_0/dx;
  186. #if USE_UVS == 1
  187. fx_u = uleft;
  188. fx_du_dx = fixmul(uright - uleft,recip_dx);
  189. fx_v = vleft;
  190. fx_dv_dx = fixmul(vright - vleft,recip_dx);
  191. fx_u_right = uright;
  192. fx_v_right = vright;
  193. #endif
  194. #if LINEAR == 0
  195. fx_z = zleft;
  196. fx_dz_dx = fixmul(zright - zleft,recip_dx);
  197. fx_z_right = zright;
  198. #endif
  199. #if CHECK_WINDOW == 1
  200. if (fx_xleft > Window_clip_right)
  201. goto dont_draw_scanline;
  202. if (fx_xright < Window_clip_left)
  203. goto dont_draw_scanline;
  204. if (fx_xright > Window_clip_right) {
  205. #if LINEAR == 0
  206. // For perspective, we need to do proper clipping
  207. // on fx_z_right, fx_u_right, fx_v_right
  208. int delta = fx_xright - Window_clip_right;
  209. fx_u_right -= fx_du_dx*delta;
  210. fx_v_right -= fx_dv_dx*delta;
  211. fx_z_right -= fx_dz_dx*delta;
  212. fx_xright = Window_clip_right;
  213. #else
  214. fx_xright = Window_clip_right;
  215. #endif
  216. }
  217. #endif
  218. #if LIGHTING == 1
  219. {
  220. fix mul_thing;
  221. if (lleft < 0) lleft = 0;
  222. if (lright < 0) lright = 0;
  223. if (lleft > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lleft = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2);
  224. if (lright > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lright = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2);
  225. fx_l = lleft;
  226. fx_dl_dx = fixmul(lright - lleft,recip_dx);
  227. // This is a pretty ugly hack to prevent lighting overflows.
  228. mul_thing = dx * fx_dl_dx;
  229. if (lleft + mul_thing < 0)
  230. fx_dl_dx += 12;
  231. else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2))
  232. fx_dl_dx -= 12;
  233. // lighting values are passed in fixed point, but need to be in 8 bit integer, 8 bit fraction so we can easily
  234. // get the integer by reading %bh
  235. fx_l >>= 8;
  236. fx_dl_dx >>= 8;
  237. if ( fx_dl_dx < 0 )
  238. fx_dl_dx++; // round towards 0 for negative deltas
  239. }
  240. #endif
  241. if ( fx_xleft < 0 ) fx_xleft = 0;
  242. dest_row_data = write_buffer + y_pointers[fx_y] + fx_xleft;
  243. loop_count = fx_xright - fx_xleft;
  244. if ( loop_count >= 0 ) {
  245. INNER_LOOP();
  246. }
  247. }
  248. #if CHECK_WINDOW == 1
  249. dont_draw_scanline:
  250. #endif
  251. if ( last_one )
  252. return;
  253. #if LIGHTING == 1
  254. lleft += dl_dy_left;
  255. lright += dl_dy_right;
  256. #endif
  257. #if USE_UVS == 1
  258. uleft += du_dy_left;
  259. vleft += dv_dy_left;
  260. uright += du_dy_right;
  261. vright += dv_dy_right;
  262. #endif
  263. xleft += dx_dy_left;
  264. xright += dx_dy_right;
  265. #if LINEAR == 0
  266. zleft += dz_dy_left;
  267. zright += dz_dy_right;
  268. #endif
  269. }
  270. last_one = 1;
  271. goto draw_scanline;
  272. #undef LINEAR
  273. #undef LIGHTING
  274. #undef INNER_LOOP
  275. #undef CHECK_WINDOW
  276. #undef USE_UVS
  277. ÿ