W3dRasterizer.Mod 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. MODULE W3dRasterizer; (** AUTHOR "TF"; PURPOSE "Quick implementiation of a 3d rasterizer "; *)
  2. IMPORT
  3. SYSTEM, KernelLog, Vectors := W3dVectors, AbstractWorld := W3dAbstractWorld, Raster;
  4. CONST Paranoid = FALSE;
  5. TYPE
  6. Vertex* = OBJECT(AbstractWorld.Vertex)
  7. VAR
  8. p*, pt*, n*, nt* : Vectors.TVector3d;
  9. u*, v*, x*, y* : LONGREAL;
  10. color* : LONGINT;
  11. behind* : BOOLEAN;
  12. PROCEDURE SetPos*(p : Vectors.TVector3d);
  13. BEGIN
  14. SELF.p := p
  15. END SetPos;
  16. PROCEDURE SetUV*(u, v : LONGREAL);
  17. BEGIN
  18. SELF.u := u; SELF.v := v
  19. END SetUV;
  20. PROCEDURE SetColor*(color : LONGINT);
  21. BEGIN
  22. SELF.color := color
  23. END SetColor;
  24. END Vertex;
  25. Texture* = OBJECT (AbstractWorld.Texture)
  26. VAR
  27. img* : Raster.Image;
  28. END Texture;
  29. Triangle* = RECORD
  30. normal* : Vectors.TVector3d;
  31. vert* : ARRAY 3 OF Vertex;
  32. color* : LONGINT;
  33. transColor*: LONGINT;
  34. tex* : Texture;
  35. mask0*, culled* : BOOLEAN;
  36. END;
  37. Rasterizer* = OBJECT
  38. VAR img*, saveimg: Raster.Image;
  39. zBuffer, savezBuffer : POINTER TO ARRAY OF REAL;
  40. invBuffer : POINTER TO ARRAY OF LONGINT;
  41. width*, height* : LONGINT;
  42. (* Global to avoid stack clearing penalty, TODO: check accesstimes *)
  43. x0, x1, x2, x3, dxL, dxR, xL, xR, xStart, xEnd, tr: REAL;
  44. y0, y1, y2, dx, zStride, stride, color: LONGINT; (* buffer variables *)
  45. adrBase, zBufBase: ADDRESS;
  46. tx0, tx1, tx2, tx3, ty0, ty1, ty2, ty3, txStart, tyStart, dtxStart, dtyStart, dtx, dty: REAL; (* parameters for affine texture *)
  47. z0, z1, z2, z3, zStart, dzStart, dz : REAL; (* z values used for affine mapping *)
  48. zinv0, zinv1, zinv2, zinv3, zinvStart, dzinvStart, dzinv : REAL; (* used for perspective mapping *)
  49. invertable : BOOLEAN;
  50. invAdrStride, invIdx : LONGINT;
  51. invAdrBase: ADDRESS;
  52. PROCEDURE CCW(tri : Triangle):BOOLEAN;
  53. BEGIN
  54. RETURN (tri.vert[1].x - tri.vert[0].x) * (tri.vert[2].y - tri.vert[0].y) -
  55. (tri.vert[2].x - tri.vert[0].x) * (tri.vert[1].y - tri.vert[0].y) >= 0
  56. END CCW;
  57. PROCEDURE SetSize*(w, h : LONGINT);
  58. BEGIN
  59. NEW(img);
  60. width := w; height := h;
  61. Raster.Create(img, w, h, Raster.BGR565);
  62. NEW(saveimg); Raster.Create(saveimg, w, h, Raster.BGR565);
  63. stride := img.bpr;
  64. NEW(zBuffer, w * h); NEW(savezBuffer, w * h);
  65. NEW(invBuffer, w * h);
  66. zStride := w * 4;
  67. invAdrStride := w * 4
  68. END SetSize;
  69. PROCEDURE Keep*;
  70. VAR mode : Raster.Mode;
  71. BEGIN
  72. Raster.InitMode(mode, Raster.srcCopy);
  73. Raster.Copy(img, saveimg, 0, 0, width, height, 0, 0, mode);
  74. SYSTEM.MOVE(ADDRESSOF(zBuffer[0]), ADDRESSOF(savezBuffer[0]), width * height * SIZEOF(REAL))
  75. END Keep;
  76. PROCEDURE Restore*;
  77. VAR mode : Raster.Mode;
  78. BEGIN
  79. Raster.InitMode(mode, Raster.srcCopy);
  80. Raster.Copy(saveimg, img, 0, 0, width, height, 0, 0, mode);
  81. SYSTEM.MOVE(ADDRESSOF(savezBuffer[0]), ADDRESSOF(zBuffer[0]), width * height * SIZEOF(REAL))
  82. END Restore;
  83. PROCEDURE SetInvertable*(invertable : BOOLEAN);
  84. BEGIN
  85. SELF.invertable := invertable
  86. END SetInvertable;
  87. PROCEDURE SetObjectIndex*(idx : LONGINT);
  88. BEGIN
  89. SELF.invIdx := idx
  90. END SetObjectIndex;
  91. (** Return 0 if no object found *)
  92. PROCEDURE GetInvIdx*(x, y : LONGINT) : LONGINT;
  93. BEGIN
  94. IF (invBuffer#NIL) & (x >= 0) & (x < width) & (y >= 0) & (y < height) THEN RETURN invBuffer[y * width + x] ELSE RETURN 0 END
  95. END GetInvIdx;
  96. PROCEDURE Clear*(color: LONGINT);
  97. VAR pix : Raster.Pixel;
  98. mode : Raster.Mode;
  99. i : LONGINT;
  100. BEGIN
  101. Raster.InitMode(mode, Raster.srcCopy);
  102. Raster.SetRGB(pix, color DIV 65536 MOD 256, color DIV 256 MOD 256, color MOD 256);
  103. Raster.Fill(img, 0, 0, width, height, pix, mode);
  104. FOR i := 0 TO width * height - 1 DO zBuffer[i] := MAX(LONGINT) END;
  105. IF invertable THEN FOR i := 0 TO width * height - 1 DO invBuffer[i] := 0 END END
  106. END Clear;
  107. PROCEDURE RenderLine;
  108. VAR adr, zAdr, invAdr: ADDRESS; x : LONGINT; z, ttx, tty: REAL;
  109. BEGIN
  110. xL := xStart; xR := xEnd; z := zStart;
  111. ttx := txStart; tty := tyStart;
  112. (* Line is out left... adjust all left based parameters *)
  113. IF xL < 0 THEN z := z - xL * dz; xL := 0 END;
  114. IF xR > width THEN xR := width END;
  115. adr := adrBase + 2 * ENTIER(xL);
  116. zAdr := zBufBase + 4 * ENTIER(xL);
  117. invAdr := invAdrBase + 4 * ENTIER(xL);
  118. FOR x := ENTIER(xL) TO ENTIER(xR + 0.5) - 1 DO
  119. IF Paranoid THEN
  120. IF ~((adr >= img.adr) & (adr < img.adr + img.height * img.bpr)) THEN
  121. KernelLog.String("Assertion failed! (A)"); KernelLog.Int(x, 5); KernelLog.Ln;
  122. RETURN
  123. END;
  124. IF ~((zAdr >= ADDRESSOF(zBuffer[0])) & (zAdr < ADDRESSOF(zBuffer[0]) + width * height * 4)) THEN
  125. KernelLog.String("Assertion failed! (B)"); KernelLog.Int(x, 5); KernelLog.Ln;
  126. RETURN
  127. END
  128. END;
  129. IF z < SYSTEM.VAL(REAL, SYSTEM.GET32(zAdr)) THEN
  130. SYSTEM.PUT16(adr, color);
  131. SYSTEM.PUT32(zAdr, SYSTEM.VAL(LONGINT, z));
  132. IF invertable THEN SYSTEM.PUT32(invAdr, invIdx) END
  133. END;
  134. INC(zAdr, 4); INC(invAdr, 4); INC(adr, 2); z := z + dz
  135. END;
  136. INC(adrBase, stride); INC(zBufBase, zStride);
  137. INC(invAdrBase, invAdrStride);
  138. xStart := xStart + dxL; xEnd := xEnd + dxR;
  139. zStart := zStart + dzStart
  140. END RenderLine;
  141. PROCEDURE RenderLineTex(tex : Texture);
  142. VAR adr, zAdr, invAdr: ADDRESS; x, txi, tyi, tadr : LONGINT; z, tx, ty: REAL;
  143. BEGIN
  144. xL := xStart;
  145. xR := xEnd;
  146. tx := txStart; ty := tyStart;
  147. z := zStart;
  148. (* Line is out left... adjust all left based parameters *)
  149. IF xL < 0 THEN
  150. z := z - xL * dz;
  151. tx := tx - xL * dtx;
  152. ty := ty - xL * dty;
  153. xL := 0;
  154. END;
  155. IF xR > width THEN xR := width END;
  156. adr := adrBase + 2 * ENTIER(xL);
  157. zAdr := zBufBase + 4 * ENTIER(xL);
  158. invAdr := invAdrBase + 4 * ENTIER(xL);
  159. FOR x := ENTIER(xL) TO ENTIER(xR + 0.5) - 1 DO
  160. IF Paranoid THEN
  161. IF ~((adr >= img.adr) & (adr < img.adr + img.height * img.bpr)) THEN
  162. KernelLog.String("Assertion failed! (A)"); KernelLog.Int(x, 5); KernelLog.Ln;
  163. RETURN
  164. END;
  165. IF ~((zAdr >= ADDRESSOF(zBuffer[0])) & (zAdr < ADDRESSOF(zBuffer[0]) + width * height * 4)) THEN
  166. KernelLog.String("Assertion failed! (B)"); KernelLog.Int(x, 5); KernelLog.Ln;
  167. RETURN
  168. END
  169. END;
  170. IF z < SYSTEM.VAL(REAL, SYSTEM.GET32(zAdr)) THEN
  171. txi := ENTIER(tx); tyi := ENTIER(ty); tadr := 2* txi + tyi * tex.img.bpr;
  172. IF tadr < 0 THEN color := 0 ELSIF tadr >= tex.img.height * tex.img.bpr THEN color := 0 ELSE
  173. color := SYSTEM.GET16(tex.img.adr + tadr);
  174. END;
  175. SYSTEM.PUT16(adr, color);
  176. SYSTEM.PUT32(zAdr, SYSTEM.VAL(LONGINT, z));
  177. IF invertable THEN SYSTEM.PUT32(invAdr, invIdx) END
  178. END;
  179. INC(zAdr, 4); INC(invAdr, 4); INC(adr, 2);
  180. tx := tx + dtx; ty := ty + dty;
  181. z := z + dz
  182. END;
  183. INC(adrBase, stride);
  184. INC(zBufBase, zStride);
  185. INC(invAdrBase, invAdrStride);
  186. xStart := xStart + dxL;
  187. xEnd := xEnd + dxR;
  188. zStart := zStart + dzStart;
  189. txStart := txStart + dtxStart; tyStart := tyStart + dtyStart;
  190. END RenderLineTex;
  191. PROCEDURE RenderTriangle*(VAR tri : Triangle);
  192. VAR p0, p1, p2, t : Vertex; y, dy : LONGINT; f, dxinv, dyinv:REAL;
  193. BEGIN
  194. IF tri.culled & ~CCW(tri) THEN RETURN END;
  195. color := tri.transColor;
  196. p0 := tri.vert[0]; p1 := tri.vert[1]; p2 := tri.vert[2];
  197. IF p1.y < p0.y THEN t := p0; p0 := p1; p1 := t END;
  198. IF p2.y < p1.y THEN t := p1; p1 := p2; p2 := t END;
  199. IF p1.y < p0.y THEN t := p0; p0 := p1; p1 := t END;
  200. y0 := ENTIER(p0.y); y1 := ENTIER(p1.y); y2 := ENTIER(p2.y);
  201. IF (y0 >= height) OR (y2 < 0) OR (y0 = y2) THEN RETURN END;
  202. x0 := SHORT(p0.x); x1 := SHORT(p1.x); x2 := SHORT(p2.x);
  203. f := (y1 - y0) / (y2 - y0); x3 := x0 + (x2 - x0) * f;
  204. dx := ENTIER(x3) - ENTIER(x1);
  205. IF dx = 0 THEN RETURN END;
  206. dxinv := 1 / (x3 - x1);
  207. z0 := SHORT(p0.pt.z);
  208. z1 := SHORT(p1.pt.z);
  209. z2 := SHORT(p2.pt.z);
  210. z3 := z0 + (z2 - z0) * f;
  211. IF tri.tex # NIL THEN
  212. tx0 := SHORT((tri.tex.img.width - 1) * p0.u);
  213. ty0 := SHORT((tri.tex.img.height - 1) * p0.v);
  214. tx1 := SHORT((tri.tex.img.width - 1) * p1.u);
  215. ty1 := SHORT((tri.tex.img.height - 1) * p1.v);
  216. tx2 := SHORT((tri.tex.img.width - 1) * p2.u);
  217. ty2 := SHORT((tri.tex.img.height - 1) * p2.v)
  218. END;
  219. tx3 := tx0 + (tx2 - tx0) * f;
  220. ty3 := ty0 + (ty2 - ty0) * f;
  221. dz := (z3 - z1) * dxinv;
  222. dtx := (tx3 - tx1) * dxinv;
  223. dty := (ty3 - ty1) * dxinv;
  224. IF dx < 0 THEN
  225. tr := x1; x1 := x3; x3 := tr;
  226. tx1:= tx3; ty1:= ty3;
  227. z1 := z3
  228. END;
  229. IF y1 >= 0 THEN (* otherwise invisible part *)
  230. dy := y1 - y0;
  231. IF dy # 0 THEN
  232. dyinv := 1 / dy;
  233. dxL := (x1 - x0) * dyinv; dxR := (x3 - x0) * dyinv;
  234. dzStart := (z1 - z0) * dyinv; (* z difference per raster line *)
  235. dtxStart := (tx1 - tx0) * dyinv; dtyStart := (ty1 - ty0) * dyinv
  236. END;
  237. xStart := x0; xEnd := x0; zStart := z0; txStart := tx0; tyStart := ty0;
  238. IF y0 < 0 THEN
  239. xStart := xStart - y0 * dxL;
  240. xEnd := xEnd - y0 * dxR;
  241. zStart := zStart - y0 * dzStart;
  242. txStart := txStart - y0 * dtxStart; tyStart := tyStart - y0 * dtyStart;
  243. y0 := 0
  244. END;
  245. adrBase := img.adr + stride * y0;
  246. zBufBase := ADDRESSOF(zBuffer[0]) + zStride * y0;
  247. invAdrBase := ADDRESSOF(invBuffer[0]) + invAdrStride * y0;
  248. IF y1 > height THEN y1 := height END;
  249. IF tri.tex # NIL THEN FOR y := y0 TO y1 - 1 DO RenderLineTex(tri.tex) END
  250. ELSE FOR y := y0 TO y1 - 1 DO RenderLine END
  251. END;
  252. END;
  253. IF y1 < height THEN (* otherwise bottom part is out *)
  254. dy := y2 - y1;
  255. IF dy # 0 THEN
  256. dyinv := 1 / dy;
  257. dxL := (x2 - x1) * dyinv; dxR := (x2 - x3) * dyinv;
  258. dzStart := (z2 - z1) * dyinv; (* z difference per raster line *)
  259. dtxStart := (tx2 - tx1) * dyinv; dtyStart := (ty2 - ty1) * dyinv
  260. END;
  261. xStart := x1; zStart := z1; xEnd := x3; txStart := tx1; tyStart := ty1;
  262. IF y1 < 0 THEN
  263. xStart := xStart - y1 * dxL;
  264. xEnd := xEnd - y1 * dxR;
  265. zStart := zStart - y1 * dzStart;
  266. txStart := txStart - y1 * dtxStart; tyStart := tyStart - y1 * dtyStart;
  267. y1 := 0
  268. END;
  269. IF y2 > height THEN y2 := height END;
  270. adrBase := img.adr + stride * y1;
  271. zBufBase := ADDRESSOF(zBuffer[0]) + zStride * y1;
  272. invAdrBase := ADDRESSOF(invBuffer[0]) + invAdrStride * y1;
  273. IF tri.tex # NIL THEN FOR y := y1 TO y2 - 1 DO RenderLineTex(tri.tex) END
  274. ELSE FOR y := y1 TO y2 - 1 DO RenderLine END
  275. END
  276. END;
  277. END RenderTriangle;
  278. (* Expensive perspective case *)
  279. PROCEDURE RenderPerspLineTex(tex : Texture);
  280. VAR adr, zAdr, invAdr: ADDRESS; x, txi, tyi, tadr: LONGINT; z, zinv, rzinv, tx, ty, txr, tyr: REAL;
  281. BEGIN
  282. xL := xStart;
  283. xR := xEnd;
  284. tx := txStart; ty := tyStart;
  285. zinv := zinvStart;
  286. (* Line is out left... adjust all left based parameters *)
  287. IF xL < 0 THEN
  288. zinv := zinv - xL * dzinv;
  289. tx := tx - xL * dtx;
  290. ty := ty - xL * dty;
  291. xL := 0;
  292. END;
  293. IF xR > width THEN xR := width END;
  294. adr := adrBase + 2 * ENTIER(xL);
  295. zAdr := zBufBase + 4 * ENTIER(xL);
  296. invAdr := invAdrBase + 4 * ENTIER(xL);
  297. FOR x := ENTIER(xL) TO ENTIER(xR + 0.5) - 1 DO
  298. rzinv := 1 / zinv;
  299. z := rzinv;
  300. txr := ENTIER(tx * rzinv);
  301. tyr := ENTIER(ty * rzinv);
  302. IF Paranoid THEN
  303. IF ~((adr >= img.adr) & (adr < img.adr + img.height * img.bpr)) THEN
  304. KernelLog.String("Assertion failed! (A)"); KernelLog.Int(x, 5); KernelLog.Ln;
  305. RETURN
  306. END;
  307. IF ~((zAdr >= ADDRESSOF(zBuffer[0])) & (zAdr < ADDRESSOF(zBuffer[0]) + width * height * 4)) THEN
  308. KernelLog.String("Assertion failed! (B)"); KernelLog.Int(x, 5); KernelLog.Ln;
  309. RETURN
  310. END
  311. END;
  312. IF z < SYSTEM.VAL(REAL, SYSTEM.GET32(zAdr)) THEN
  313. txi := ENTIER(txr); tyi := ENTIER(tyr); tadr := 2* txi + tyi * tex.img.bpr;
  314. IF tadr < 0 THEN color := 0 ELSIF tadr >= tex.img.height * tex.img.bpr THEN color := 0 ELSE
  315. color := SYSTEM.GET16(tex.img.adr + tadr)
  316. END;
  317. SYSTEM.PUT16(adr, color);
  318. SYSTEM.PUT32(zAdr, SYSTEM.VAL(LONGINT, z));
  319. IF invertable THEN SYSTEM.PUT32(invAdr, invIdx) END
  320. END;
  321. INC(zAdr, 4); INC(invAdr, 4); INC(adr, 2);
  322. tx := tx + dtx; ty := ty + dty;
  323. zinv:= zinv + dzinv
  324. END;
  325. INC(adrBase, stride);
  326. INC(zBufBase, zStride);
  327. INC(invAdrBase, invAdrStride);
  328. xStart := xStart + dxL;
  329. xEnd := xEnd + dxR;
  330. txStart := txStart + dtxStart; tyStart := tyStart + dtyStart;
  331. zinvStart := zinvStart + dzinvStart;
  332. END RenderPerspLineTex;
  333. PROCEDURE RenderPerspLineFlat;
  334. VAR adr, zAdr, invAdr: ADDRESS; x: LONGINT; z, zinv, rzinv: REAL;
  335. BEGIN
  336. xL := xStart;
  337. xR := xEnd;
  338. zinv := zinvStart;
  339. (* Line is out left... adjust all left based parameters *)
  340. IF xL < 0 THEN
  341. zinv := zinv - xL * dzinv;
  342. xL := 0;
  343. END;
  344. IF xR > width THEN xR := width END;
  345. adr := adrBase + 2 * ENTIER(xL);
  346. zAdr := zBufBase + 4 * ENTIER(xL);
  347. invAdr := invAdrBase + 4 * ENTIER(xL);
  348. FOR x := ENTIER(xL) TO ENTIER(xR + 0.5) - 1 DO
  349. rzinv := 1 / zinv;
  350. z := rzinv;
  351. IF Paranoid THEN
  352. IF ~((adr >= img.adr) & (adr < img.adr + img.height * img.bpr)) THEN
  353. KernelLog.String("Assertion failed! (A)"); KernelLog.Int(x, 5); KernelLog.Ln;
  354. RETURN
  355. END;
  356. IF ~((zAdr >= ADDRESSOF(zBuffer[0])) & (zAdr < ADDRESSOF(zBuffer[0]) + width * height * 4)) THEN
  357. KernelLog.String("Assertion failed! (B)"); KernelLog.Int(x, 5); KernelLog.Ln;
  358. RETURN
  359. END
  360. END;
  361. IF z < SYSTEM.VAL(REAL, SYSTEM.GET32(zAdr)) THEN
  362. SYSTEM.PUT16(adr, color);
  363. SYSTEM.PUT32(zAdr, SYSTEM.VAL(LONGINT, z));
  364. IF invertable THEN SYSTEM.PUT32(invAdr, invIdx) END
  365. END;
  366. INC(zAdr, 4); INC(invAdr, 4); INC(adr, 2);
  367. zinv:= zinv + dzinv
  368. END;
  369. INC(adrBase, stride);
  370. INC(zBufBase, zStride);
  371. INC(invAdrBase, invAdrStride);
  372. xStart := xStart + dxL;
  373. xEnd := xEnd + dxR;
  374. zinvStart := zinvStart + dzinvStart;
  375. END RenderPerspLineFlat;
  376. PROCEDURE RenderPerspTriangle*(VAR tri : Triangle);
  377. VAR p0, p1, p2, t : Vertex; y, dy : LONGINT; f, dyinv, dxinv : REAL;
  378. BEGIN
  379. IF tri.culled & ~CCW(tri) THEN RETURN END;
  380. color := tri.transColor;
  381. p0 := tri.vert[0]; p1 := tri.vert[1]; p2 := tri.vert[2];
  382. IF p1.y < p0.y THEN t := p0; p0 := p1; p1 := t END;
  383. IF p2.y < p1.y THEN t := p1; p1 := p2; p2 := t END;
  384. IF p1.y < p0.y THEN t := p0; p0 := p1; p1 := t END;
  385. y0 := ENTIER(p0.y); y1 := ENTIER(p1.y); y2 := ENTIER(p2.y);
  386. IF (y0 >= height) OR (y2 < 0) OR (y0 = y2) THEN RETURN END;
  387. x0 := SHORT(p0.x); x1 := SHORT(p1.x); x2 := SHORT(p2.x);
  388. f := (y1 - y0) / (y2 - y0);
  389. x3 := x0 + (x2 - x0) * f;
  390. dx := (ENTIER(x3) -ENTIER(x1));
  391. IF dx = 0 THEN RETURN END;
  392. dxinv := 1 / dx (*(x3 - x1);*);
  393. zinv0 := SHORT(1 / p0.pt.z); zinv1 := SHORT(1 / p1.pt.z); zinv2 := SHORT(1 / p2.pt.z);
  394. zinv3 := zinv0 + (zinv2 - zinv0) * f;
  395. IF tri.tex # NIL THEN
  396. tx0 := SHORT((tri.tex.img.width - 1) * p0.u * zinv0);
  397. ty0 := SHORT((tri.tex.img.height - 1) * p0.v * zinv0);
  398. tx1 := SHORT((tri.tex.img.width - 1) * p1.u * zinv1);
  399. ty1 := SHORT((tri.tex.img.height - 1) * p1.v * zinv1);
  400. tx2 := SHORT((tri.tex.img.width - 1) * p2.u * zinv2);
  401. ty2 := SHORT((tri.tex.img.height - 1) * p2.v * zinv2)
  402. END;
  403. tx3 := tx0 + (tx2 - tx0) * f;
  404. ty3 := ty0 + (ty2 - ty0) * f;
  405. dtx := (tx3 - tx1) * dxinv;
  406. dty := (ty3 - ty1) * dxinv;
  407. dzinv := (zinv3 - zinv1) * dxinv;
  408. IF dx < 0 THEN
  409. tr := x1; x1 := x3; x3 := tr;
  410. tx1:= tx3; ty1:= ty3;
  411. zinv1 := zinv3;
  412. END;
  413. IF y1 >= 0 THEN (* otherwise invisible part *)
  414. dy := y1 - y0; dyinv := 1 / dy;
  415. IF dy # 0 THEN
  416. dxL := (x1 - x0) * dyinv; dxR := (x3 - x0) * dyinv;
  417. dtxStart := (tx1 - tx0) * dyinv; dtyStart := (ty1 - ty0) * dyinv;
  418. dzinvStart := (zinv1 - zinv0) * dyinv;
  419. END;
  420. xStart := x0; xEnd := x0; txStart := tx0; tyStart := ty0;
  421. zinvStart := zinv0;
  422. IF y0 < 0 THEN
  423. xStart := xStart - y0 * dxL;
  424. xEnd := xEnd - y0 * dxR;
  425. txStart := txStart - y0 * dtxStart; tyStart := tyStart - y0 * dtyStart;
  426. zinvStart := zinvStart - y0 * dzinvStart;
  427. y0 := 0
  428. END;
  429. adrBase := img.adr + stride * y0;
  430. zBufBase := ADDRESSOF(zBuffer[0]) + zStride * y0;
  431. invAdrBase := ADDRESSOF(invBuffer[0]) + invAdrStride * y0;
  432. IF y1 > height THEN y1 := height END;
  433. IF tri.tex # NIL THEN FOR y := y0 TO y1 - 1 DO RenderPerspLineTex(tri.tex) END
  434. ELSE FOR y := y0 TO y1 - 1 DO RenderPerspLineFlat END
  435. END;
  436. END;
  437. IF y1 < height THEN (* otherwise bottom part is out *)
  438. dy := y2 - y1; dyinv := 1 / dy;
  439. IF dy # 0 THEN
  440. dxL := (x2 - x1) * dyinv; dxR := (x2 - x3) * dyinv;
  441. dtxStart := (tx2 - tx1) * dyinv; dtyStart := (ty2 - ty1) * dyinv;
  442. dzinvStart := (zinv2 - zinv1) * dyinv;
  443. END;
  444. xStart := x1; xEnd := x3; txStart := tx1; tyStart := ty1;
  445. zinvStart := zinv1;
  446. IF y1 < 0 THEN
  447. xStart := xStart - y1 * dxL;
  448. xEnd := xEnd - y1 * dxR;
  449. txStart := txStart - y1 * dtxStart; tyStart := tyStart - y1 * dtyStart;
  450. zinvStart := zinvStart - y1 * dzinvStart;
  451. y1 := 0
  452. END;
  453. IF y2 > height THEN y2 := height END;
  454. adrBase := img.adr + stride * y1;
  455. zBufBase := ADDRESSOF(zBuffer[0]) + zStride * y1;
  456. invAdrBase := ADDRESSOF(invBuffer[0]) + invAdrStride * y1;
  457. IF tri.tex # NIL THEN FOR y := y1 TO y2 - 1 DO RenderPerspLineTex(tri.tex) END
  458. ELSE FOR y := y1 TO y2 - 1 DO RenderPerspLineFlat END
  459. END
  460. END;
  461. END RenderPerspTriangle;
  462. (* Experimental Subdivision case *)
  463. PROCEDURE SubDivLineTex(tex : Texture);
  464. VAR adr, zAdr, invAdr: ADDRESS; x, txi, tyi, tadr: LONGINT; zinv, txr, tyr, zr, rzinv, tx, ty, sdtx, sdty, stx, sty, szr, ezr, dzr, subDivInv: REAL;
  465. i : LONGINT;
  466. CONST SubDiv = 16;
  467. BEGIN
  468. subDivInv := 1 / SubDiv;
  469. xL := xStart;
  470. xR := xEnd;
  471. zinv := zinvStart;
  472. tx := txStart; ty := tyStart;
  473. (* Line is out left... adjust all left based parameters *)
  474. IF xL < 0 THEN
  475. zinv := zinv - xL * dzinv;
  476. tx := tx - xL * dtx;
  477. ty := ty - xL * dty;
  478. xL := 0;
  479. END;
  480. IF xR > width THEN xR := width END;
  481. szr := 1 / zinv;
  482. stx := tx * szr; sty := ty * szr;
  483. ezr := 1 / ( zinv + SubDiv * dzinv);
  484. sdtx := ((tx + SubDiv * dtx)*ezr - stx) * subDivInv;
  485. sdty := ((ty + SubDiv * dty)*ezr - sty) * subDivInv;
  486. txr := stx; tyr := sty; zr := szr;
  487. dzr := (ezr - szr) * subDivInv;
  488. adr := adrBase + 2 * ENTIER(xL);
  489. zAdr := zBufBase + 4 * ENTIER(xL);
  490. invAdr := invAdrBase + 4 * ENTIER(xL);
  491. i := 0;
  492. FOR x := ENTIER(xL) TO ENTIER(xR + 0.5) - 1 DO
  493. INC(i);
  494. IF i = SubDiv THEN
  495. rzinv := 1 / zinv; txr := tx * rzinv; tyr := ty * rzinv; zr := rzinv;
  496. ezr := 1 / ( zinv + SubDiv * dzinv);
  497. dzr := (ezr - zr) * subDivInv;
  498. sdtx := ((tx + SubDiv * dtx)*ezr - txr) * subDivInv;
  499. sdty := ((ty + SubDiv * dty)*ezr - tyr) * subDivInv;
  500. i := 0;
  501. END;
  502. IF Paranoid THEN
  503. IF ~((adr >= img.adr) & (adr < img.adr + img.height * img.bpr)) THEN
  504. KernelLog.String("Assertion failed! (A)"); KernelLog.Int(x, 5); KernelLog.Ln;
  505. RETURN
  506. END;
  507. IF ~((zAdr >= ADDRESSOF(zBuffer[0])) & (zAdr < ADDRESSOF(zBuffer[0]) + width * height * 4)) THEN
  508. KernelLog.String("Assertion failed! (B)"); KernelLog.Int(x, 5); KernelLog.Ln;
  509. RETURN
  510. END
  511. END;
  512. IF zr < SYSTEM.VAL(REAL, SYSTEM.GET32(zAdr)) THEN
  513. txi := ENTIER(txr); tyi := ENTIER(tyr); tadr := 2* txi + tyi * tex.img.bpr;
  514. IF tadr < 0 THEN color := 0 ELSIF tadr >= tex.img.height * tex.img.bpr THEN color := 0 ELSE
  515. color := SYSTEM.GET16(tex.img.adr + tadr);
  516. END;
  517. SYSTEM.PUT16(adr, color);
  518. SYSTEM.PUT32(zAdr, SYSTEM.VAL(LONGINT, zr));
  519. IF invertable THEN SYSTEM.PUT32(invAdr, invIdx) END
  520. END;
  521. INC(zAdr, 4); INC(invAdr, 4); INC(adr, 2);
  522. txr := txr + sdtx; tyr := tyr + sdty;
  523. tx := tx +dtx; ty := ty +dty; zinv := zinv +dzinv;
  524. zr := zr + dzr
  525. END;
  526. INC(adrBase, stride);
  527. INC(zBufBase, zStride);
  528. INC(invAdrBase, invAdrStride);
  529. xStart := xStart + dxL;
  530. xEnd := xEnd + dxR;
  531. txStart := txStart + dtxStart; tyStart := tyStart + dtyStart;
  532. zinvStart := zinvStart + dzinvStart;
  533. END SubDivLineTex;
  534. PROCEDURE SubDivLineFlat;
  535. VAR adr, zAdr, invAdr: ADDRESS; x: LONGINT; zinv, zr, rzinv, szr, ezr, dzr, subDivInv: REAL;
  536. i : LONGINT;
  537. CONST SubDiv = 16;
  538. BEGIN
  539. subDivInv := 1 / SubDiv;
  540. xL := xStart;
  541. xR := xEnd;
  542. zinv := zinvStart;
  543. (* Line is out left... adjust all left based parameters *)
  544. IF xL < 0 THEN
  545. zinv := zinv - xL * dzinv;
  546. xL := 0;
  547. END;
  548. IF xR > width THEN xR := width END;
  549. szr := 1 / zinv ;zr := szr;
  550. ezr := 1 / ( zinv + SubDiv * dzinv);
  551. dzr := (ezr - szr) * subDivInv;
  552. adr := adrBase + 2 * ENTIER(xL);
  553. zAdr := zBufBase + 4 * ENTIER(xL);
  554. invAdr := invAdrBase + 4 * ENTIER(xL);
  555. i := 0;
  556. FOR x := ENTIER(xL) TO ENTIER(xR + 0.5) - 1 DO
  557. INC(i);
  558. IF i = SubDiv THEN
  559. rzinv := 1 / zinv; zr := rzinv;
  560. ezr := 1 / ( zinv + SubDiv * dzinv);
  561. dzr := (ezr - zr) * subDivInv;
  562. i := 0
  563. END;
  564. IF Paranoid THEN
  565. IF ~((adr >= img.adr) & (adr < img.adr + img.height * img.bpr)) THEN
  566. KernelLog.String("Assertion failed! (A)"); KernelLog.Int(x, 5); KernelLog.Ln;
  567. RETURN
  568. END;
  569. IF ~((zAdr >= ADDRESSOF(zBuffer[0])) & (zAdr < ADDRESSOF(zBuffer[0]) + width * height * 4)) THEN
  570. KernelLog.String("Assertion failed! (B)"); KernelLog.Int(x, 5); KernelLog.Ln;
  571. RETURN
  572. END
  573. END;
  574. IF zr < SYSTEM.VAL(REAL, SYSTEM.GET32(zAdr)) THEN
  575. SYSTEM.PUT16(adr, color);
  576. SYSTEM.PUT32(zAdr, SYSTEM.VAL(LONGINT, zr));
  577. IF invertable THEN SYSTEM.PUT32(invAdr, invIdx) END
  578. END;
  579. INC(zAdr, 4); INC(invAdr, 4); INC(adr, 2);
  580. zinv := zinv +dzinv;
  581. zr := zr + dzr
  582. END;
  583. INC(adrBase, stride);
  584. INC(zBufBase, zStride);
  585. INC(invAdrBase, invAdrStride);
  586. xStart := xStart + dxL;
  587. xEnd := xEnd + dxR;
  588. txStart := txStart + dtxStart; tyStart := tyStart + dtyStart;
  589. zinvStart := zinvStart + dzinvStart;
  590. END SubDivLineFlat;
  591. PROCEDURE SubDivTriangle*(VAR tri : Triangle);
  592. VAR p0, p1, p2, t : Vertex; y, dy : LONGINT; f, dyinv, dxinv : REAL;
  593. BEGIN
  594. IF tri.culled & ~CCW(tri) THEN RETURN END;
  595. color := tri.transColor;
  596. p0 := tri.vert[0]; p1 := tri.vert[1]; p2 := tri.vert[2];
  597. IF p1.y < p0.y THEN t := p0; p0 := p1; p1 := t END;
  598. IF p2.y < p1.y THEN t := p1; p1 := p2; p2 := t END;
  599. IF p1.y < p0.y THEN t := p0; p0 := p1; p1 := t END;
  600. y0 := ENTIER(p0.y); y1 := ENTIER(p1.y); y2 := ENTIER(p2.y);
  601. IF (y0 >= height) OR (y2 < 0) OR (y0 = y2) THEN RETURN END;
  602. x0 := SHORT(p0.x); x1 := SHORT(p1.x); x2 := SHORT(p2.x);
  603. f := (y1 - y0) / (y2 - y0);
  604. x3 := x0 + (x2 - x0) * f;
  605. dx := (ENTIER(x3 + 0.5) -ENTIER(x1));
  606. IF dx = 0 THEN RETURN END;
  607. dxinv := 1 / (x3 - x1);
  608. zinv0 := SHORT(1 / p0.pt.z); zinv1 := SHORT(1 / p1.pt.z); zinv2 := SHORT(1 / p2.pt.z);
  609. zinv3 := zinv0 + (zinv2 - zinv0) * f;
  610. IF tri.tex # NIL THEN
  611. tx0 := SHORT((tri.tex.img.width - 1) * p0.u * zinv0);
  612. ty0 := SHORT((tri.tex.img.height - 1) * p0.v * zinv0);
  613. tx1 := SHORT((tri.tex.img.width - 1) * p1.u * zinv1);
  614. ty1 := SHORT((tri.tex.img.height - 1) * p1.v * zinv1);
  615. tx2 := SHORT((tri.tex.img.width - 1) * p2.u * zinv2);
  616. ty2 := SHORT((tri.tex.img.height - 1) * p2.v * zinv2)
  617. END;
  618. tx3 := tx0 + (tx2 - tx0) * f;
  619. ty3 := ty0 + (ty2 - ty0) * f;
  620. dtx := (tx3 - tx1) * dxinv;
  621. dty := (ty3 - ty1) * dxinv;
  622. dzinv := (zinv3 - zinv1) * dxinv;
  623. IF dx < 0 THEN
  624. tr := x1; x1 := x3; x3 := tr;
  625. tx1:= tx3; ty1:= ty3;
  626. zinv1 := zinv3;
  627. END;
  628. IF y1 >= 0 THEN (* otherwise invisible part *)
  629. dy := y1 - y0; dyinv := 1 / dy;
  630. IF dy # 0 THEN
  631. dxL := (x1 - x0) * dyinv; dxR := (x3 - x0) * dyinv;
  632. dtxStart := (tx1 - tx0) * dyinv; dtyStart := (ty1 - ty0) * dyinv;
  633. dzinvStart := (zinv1 - zinv0) * dyinv;
  634. END;
  635. xStart := x0; xEnd := x0; txStart := tx0; tyStart := ty0;
  636. zinvStart := zinv0;
  637. IF y0 < 0 THEN
  638. xStart := xStart - y0 * dxL;
  639. xEnd := xEnd - y0 * dxR;
  640. txStart := txStart - y0 * dtxStart; tyStart := tyStart - y0 * dtyStart;
  641. zinvStart := zinvStart - y0 * dzinvStart;
  642. y0 := 0
  643. END;
  644. adrBase := img.adr + stride * y0;
  645. zBufBase := ADDRESSOF(zBuffer[0]) + zStride * y0;
  646. invAdrBase := ADDRESSOF(invBuffer[0]) + invAdrStride * y0;
  647. IF y1 > height THEN y1 := height END;
  648. IF tri.tex # NIL THEN FOR y := y0 TO y1 - 1 DO SubDivLineTex(tri.tex) END
  649. ELSE FOR y := y0 TO y1 - 1 DO SubDivLineFlat END
  650. END;
  651. END;
  652. IF y1 < height THEN (* otherwise bottom part is out *)
  653. dy := y2 - y1; dyinv := 1 / dy;
  654. IF dy # 0 THEN
  655. dxL := (x2 - x1) * dyinv; dxR := (x2 - x3) * dyinv;
  656. dtxStart := (tx2 - tx1) * dyinv; dtyStart := (ty2 - ty1) * dyinv;
  657. dzinvStart := (zinv2 - zinv1) * dyinv;
  658. END;
  659. xStart := x1; xEnd := x3; txStart := tx1; tyStart := ty1;
  660. zinvStart := zinv1;
  661. IF y1 < 0 THEN
  662. xStart := xStart - y1 * dxL;
  663. xEnd := xEnd - y1 * dxR;
  664. txStart := txStart - y1 * dtxStart; tyStart := tyStart - y1 * dtyStart;
  665. zinvStart := zinvStart - y1 * dzinvStart;
  666. y1 := 0
  667. END;
  668. IF y2 > height THEN y2 := height END;
  669. adrBase := img.adr + stride * y1;
  670. zBufBase := ADDRESSOF(zBuffer[0]) + zStride * y1;
  671. invAdrBase := ADDRESSOF(invBuffer[0]) + invAdrStride * y1;
  672. IF tri.tex # NIL THEN FOR y := y1 TO y2 - 1 DO SubDivLineTex(tri.tex) END
  673. ELSE FOR y := y1 TO y2 - 1 DO SubDivLineFlat END
  674. END
  675. END;
  676. END SubDivTriangle;
  677. PROCEDURE SubDivLine*(a, b: Vertex);
  678. VAR tdx, tdy : LONGREAL;
  679. tv : Vertex;
  680. xr, yr, dxinv, dyinv, invdz, invaz, invbz, invz, z, dz, dx, dy : LONGREAL;
  681. iy, ix, i : LONGINT;
  682. CONST SubDiv = 8;
  683. SubDivInv = 1 / SubDiv;
  684. BEGIN
  685. tdx := ABS(b.x - a.x); tdy := ABS(b.y - a.y);
  686. IF tdx > tdy THEN
  687. IF a.x > b.x THEN tv := a; a := b; b := tv END;
  688. IF (a.x > width) OR (b.x < 0) THEN RETURN END;
  689. invaz := 1 / a.pt.z; invbz := 1 / b.pt.z;
  690. invz := invaz; z := a.pt.z;
  691. IF tdx > 0 THEN
  692. dxinv := 1 / tdx;
  693. invdz := (invbz - invaz) * dxinv; dz := (b.pt.z - a.pt.z) * dxinv; dy := (b.y - a.y) * dxinv
  694. ELSE invdz := 0; dz := 0; dy := 0
  695. END;
  696. xr := a.x; yr := a.y;
  697. IF xr < 0 THEN invz := invz - invdz * xr; yr := yr - dy * xr; xr := 0 END;
  698. z := 1 / invz;
  699. dz := ((1 / (invz + SubDiv * invdz)) - z) * SubDivInv;
  700. i := 0;
  701. FOR ix := ENTIER(xr) TO MIN(width, ENTIER(b.x + 0.5)) - 1 DO
  702. INC(i);
  703. IF i = SubDiv THEN
  704. z := 1 / invz;
  705. dz := ((1 / (invz + SubDiv * invdz)) - z) * SubDivInv;
  706. i := 0;
  707. END;
  708. iy := ENTIER(yr);
  709. IF (iy > 0) & (iy < height) THEN
  710. IF zBuffer[iy * width + ix] > z THEN
  711. zBuffer[iy * width + ix] := SHORT(z);
  712. SYSTEM.PUT16(img.adr + img.bpr * iy + ix*2, color);
  713. END
  714. END;
  715. yr := yr + dy; invz := invz + invdz; z := z + dz
  716. END
  717. ELSE
  718. IF a.y > b.y THEN tv := a; a := b; b := tv END;
  719. IF (a.y > height) OR (b.y < 0) THEN RETURN END;
  720. invaz := 1 / a.pt.z; invbz := 1 / b.pt.z;
  721. invz := invaz; z := a.pt.z;
  722. IF tdy > 0 THEN
  723. dyinv := 1 / tdy;
  724. invdz := (invbz - invaz) * dyinv; dz := (b.pt.z - a.pt.z) * dyinv; dx := (b.x - a.x) * dyinv
  725. ELSE invdz := 0; dz := 0; dx := 0
  726. END;
  727. xr := a.x; yr := a.y;
  728. IF yr < 0 THEN
  729. invz := invz - invdz * yr;
  730. xr := xr - dx * yr;
  731. yr := 0
  732. END;
  733. z := 1 / invz;
  734. dz := ((1 / (invz + SubDiv * invdz)) - z) * SubDivInv;
  735. i := 0;
  736. FOR iy := ENTIER(yr) TO MIN(height, ENTIER(b.y + 0.5)) - 1 DO
  737. INC(i);
  738. IF i = SubDiv THEN
  739. z := 1 / invz;
  740. dz := ((1 / (invz + SubDiv * invdz)) - z) * SubDivInv;
  741. i := 0
  742. END;
  743. ix := ENTIER(xr);
  744. IF (ix > 0) & (ix < width) THEN
  745. IF zBuffer[iy * width + ix] > z THEN
  746. zBuffer[iy * width + ix] := SHORT(z);
  747. SYSTEM.PUT16(img.adr + img.bpr * iy + ix*2, color)
  748. END
  749. END;
  750. xr := xr + dx; invz := invz + invdz; z := z + dz
  751. END
  752. END
  753. END SubDivLine;
  754. END Rasterizer;
  755. END W3dRasterizer.