W3dWorld.Mod 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. MODULE W3dWorld; (** AUTHOR "TF"; PURPOSE "Implementation of a 3d world data structure and renderer"; *)
  2. IMPORT
  3. AbstractWorld := W3dAbstractWorld, Vectors := W3dVectors, Matrix := W3dMatrix, Raster, Classes := TFClasses,
  4. Rasterizer := W3dRasterizer, W3dGeometry;
  5. CONST TraceNormals = FALSE;
  6. TYPE
  7. Vertex* = Rasterizer.Vertex;
  8. VertexArray = POINTER TO ARRAY OF Vertex;
  9. Texture = Rasterizer.Texture;
  10. Triangle = Rasterizer.Triangle;
  11. TriangleArray = POINTER TO ARRAY OF Triangle;
  12. AABB = RECORD a, b : Vectors.TVector3d; empty : BOOLEAN END;
  13. Object* = OBJECT (AbstractWorld.Object)
  14. VAR
  15. triangles : TriangleArray;
  16. nofTriangles : LONGINT;
  17. vertices : VertexArray;
  18. nofVertices : LONGINT;
  19. aabb : AABB;
  20. bsCenter : Vectors.TVector3d;
  21. bsRadius : LONGREAL;
  22. bsValid : BOOLEAN;
  23. isAnimated : BOOLEAN;
  24. index : LONGINT;
  25. PROCEDURE &Init*;
  26. BEGIN
  27. NEW(vertices, 64);
  28. NEW(triangles, 32);
  29. aabb.empty := TRUE;
  30. bsValid := FALSE
  31. END Init;
  32. PROCEDURE SetIndex*(idx : LONGINT);
  33. BEGIN
  34. index := idx
  35. END SetIndex;
  36. PROCEDURE AddTexture*(img : Raster.Image): AbstractWorld.Texture;
  37. VAR t : Texture;
  38. BEGIN
  39. NEW(t);
  40. t.img := img;
  41. RETURN t
  42. END AddTexture;
  43. PROCEDURE AddVertex*(p : Vectors.TVector3d): AbstractWorld.Vertex;
  44. VAR n : VertexArray; i : LONGINT;
  45. v: Vertex;
  46. BEGIN
  47. NEW(v); v.SetPos(p); GrowAABB(aabb, p); bsValid := FALSE;
  48. IF nofVertices = LEN(vertices) THEN
  49. NEW(n, LEN(vertices) * 2);
  50. FOR i := 0 TO nofVertices - 1 DO n[i] := vertices[i] END;
  51. vertices := n
  52. END;
  53. vertices[nofVertices] := v; INC(nofVertices);
  54. RETURN v
  55. END AddVertex;
  56. PROCEDURE CalcBS;
  57. BEGIN
  58. bsCenter := Vectors.VScaled3(Vectors.VAdd3(aabb.a, aabb.b), 0.5); bsRadius := Vectors.VLength3VV(aabb.a, aabb.b) / 2;
  59. bsValid := TRUE
  60. END CalcBS;
  61. PROCEDURE AddTriangle*(a, b, c : AbstractWorld.Vertex; color : LONGINT; tex : AbstractWorld.Texture; mask0, culled: BOOLEAN);
  62. VAR n : TriangleArray; i : LONGINT;
  63. f : REAL;
  64. BEGIN
  65. IF nofTriangles = LEN(triangles) THEN
  66. NEW(n, LEN(triangles) * 2);
  67. FOR i := 0 TO nofTriangles - 1 DO n[i] := triangles[i] END;
  68. triangles := n
  69. END;
  70. triangles[nofTriangles].vert[0] := a(Vertex);
  71. triangles[nofTriangles].vert[1] := b(Vertex);
  72. triangles[nofTriangles].vert[2] := c(Vertex);
  73. triangles[nofTriangles].color := color;
  74. triangles[nofTriangles].culled := culled;
  75. triangles[nofTriangles].normal := Vectors.VNormed3(Vectors.Cross(
  76. Vectors.VSub3(b(Vertex).p, a(Vertex).p), Vectors.VSub3(c(Vertex).p, a(Vertex).p)));
  77. IF tex # NIL THEN triangles[nofTriangles].tex := tex(Texture) END;
  78. f := (1 + ABS(SHORT(
  79. Vectors.Scalar3(triangles[nofTriangles].normal, Vectors.VNormed3(Vectors.Vector3d(0.2, 0.9, 0.4)))))) / 2;
  80. triangles[nofTriangles].transColor := ASH(ENTIER(color MOD 256 * f), -3) +
  81. ASH(ASH(ENTIER(color DIV 256 MOD 256 * f ), -2), 5) +
  82. ASH(ASH(ENTIER(color DIV 65536 MOD 256 * f), -3), 11);
  83. INC(nofTriangles)
  84. END AddTriangle;
  85. PROCEDURE Clear*;
  86. VAR i : LONGINT;
  87. BEGIN
  88. FOR i := nofVertices - 1 TO 0 BY - 1 DO vertices[i] := NIL END;
  89. nofTriangles := 0;
  90. nofVertices := 0;
  91. END Clear;
  92. END Object;
  93. World* = OBJECT (AbstractWorld.World)
  94. VAR
  95. objects, animated : Classes.List;
  96. p, d, u : Vectors.TVector3d;
  97. trans : Matrix.Matrix4x4;
  98. distpp : LONGREAL;
  99. rasterizer : Rasterizer.Rasterizer;
  100. width, height : LONGINT;
  101. quality* : LONGINT;
  102. frustum* : W3dGeometry.Frustum;
  103. clearColor : LONGINT;
  104. tempTri : Triangle;
  105. tempv0, tempv1 : Vertex;
  106. changed, invertable : BOOLEAN;
  107. worldValid : BOOLEAN; (* is the non-animated part of the world valid ?
  108. No if not rendered, trans matrix changed or isAnimated of an object is changed *)
  109. PROCEDURE &Init*(w, h, clearColor :LONGINT);
  110. BEGIN
  111. NEW(objects); NEW(animated); distpp := w/2; NEW(rasterizer); rasterizer.SetSize(w, h);
  112. NEW(frustum);
  113. width := w; height := h; SELF.clearColor := clearColor;
  114. NEW(tempv0); NEW(tempv1);
  115. END Init;
  116. PROCEDURE CreateObject*(): AbstractWorld.Object;
  117. VAR obj : Object;
  118. BEGIN
  119. NEW(obj); RETURN obj
  120. END CreateObject;
  121. PROCEDURE AddObject*(x: AbstractWorld.Object);
  122. BEGIN
  123. objects.Add(x)
  124. END AddObject;
  125. PROCEDURE ReplaceObject*(x, y : AbstractWorld.Object);
  126. BEGIN
  127. objects.Replace(x, y)
  128. END ReplaceObject;
  129. PROCEDURE SetAnimated*(obj : AbstractWorld.Object; animated: BOOLEAN);
  130. BEGIN
  131. obj(Object).isAnimated := animated;
  132. worldValid := FALSE
  133. END SetAnimated;
  134. PROCEDURE Clear*;
  135. BEGIN
  136. objects.Clear;
  137. animated.Clear
  138. END Clear;
  139. PROCEDURE SetCamera*(p, d, u : Vectors.TVector3d);
  140. BEGIN {EXCLUSIVE}
  141. SELF.p := p; SELF.d := d; SELF.u := u;
  142. trans := Matrix.CameraMatrix(p, d, u);
  143. frustum.Make(p, d, u, distpp, rasterizer.width, rasterizer.height, 100, 1000);
  144. worldValid := FALSE
  145. END SetCamera;
  146. PROCEDURE ScreenPos(p : Vectors.TVector3d; VAR x, y: LONGREAL);
  147. VAR inv : LONGREAL;
  148. BEGIN
  149. inv := distpp / p.z;
  150. x := p.x * inv + (rasterizer.width DIV 2);
  151. y := rasterizer.height - (p.y * inv + (rasterizer.height DIV 2))
  152. END ScreenPos;
  153. PROCEDURE RasterTriangle(VAR tri : Triangle);
  154. VAR p, d: Vectors.TVector3d;
  155. a, b : Rasterizer.Vertex;
  156. BEGIN
  157. CASE quality OF
  158. 0 :rasterizer.RenderTriangle(tri)
  159. |1 :rasterizer.SubDivTriangle(tri)
  160. |2 :rasterizer.RenderPerspTriangle(tri)
  161. |3 :rasterizer.SubDivLine(tri.vert[0], tri.vert[1]);
  162. rasterizer.SubDivLine(tri.vert[1], tri.vert[2]);
  163. rasterizer.SubDivLine(tri.vert[2], tri.vert[0])
  164. ELSE
  165. END;
  166. IF TraceNormals THEN
  167. p := Vectors.VScaled3(Vectors.VAdd3(Vectors.VAdd3(tri.vert[0].pt, tri.vert[1].pt), tri.vert[2].pt), 0.3333);
  168. d := Vectors.VAdd3(p, Vectors.VScaled3(Vectors.VNormed3(Vectors.Cross(
  169. Vectors.VSub3(tri.vert[1].pt, tri.vert[0].pt), Vectors.VSub3(tri.vert[2].pt, tri.vert[0].pt))), 30));
  170. NEW(a); NEW(b);
  171. a.pt := p; b.pt := d; ScreenPos(a.pt, a.x, a.y); ScreenPos(b.pt, b.x, b.y);
  172. rasterizer.SubDivLine(a, b);
  173. END
  174. END RasterTriangle;
  175. PROCEDURE ClipDrawTriangle(VAR tri : Triangle);
  176. VAR c : LONGINT; v0, v1, v2 : Vertex; d, m: LONGREAL;
  177. BEGIN
  178. IF ~(tri.vert[0].behind OR tri.vert[1].behind OR tri.vert[2].behind) THEN
  179. RasterTriangle(tri)
  180. ELSE
  181. c := 0 ; IF tri.vert[0].behind THEN INC(c) END; IF tri.vert[1].behind THEN INC(c) END;
  182. IF tri.vert[2].behind THEN INC(c) END;
  183. IF c = 2 THEN
  184. IF ~tri.vert[0].behind THEN v0 := tri.vert[0]; v1 := tri.vert[1]; v2 := tri.vert[2] END;
  185. IF ~tri.vert[1].behind THEN v0 := tri.vert[1]; v1 := tri.vert[2]; v2 := tri.vert[0] END;
  186. IF ~tri.vert[2].behind THEN v0 := tri.vert[2]; v1 := tri.vert[0]; v2 := tri.vert[1] END;
  187. d := Vectors.Scalar3(frustum.nearP.n, Vectors.VNormed3(Vectors.VSub3(v1.p, v0.p)));
  188. IF d # 0 THEN
  189. m := - (Vectors.Scalar3(frustum.nearP.n, v0.p) + frustum.nearP.d) / d / Vectors.VLength3VV(v1.p, v0.p);
  190. tempv0.u := v0.u + (v1.u - v0.u) * m;
  191. tempv0.v := v0.v + (v1.v - v0.v) * m;
  192. tempv0.p := Vectors.VAdd3(v0.p, Vectors.VScaled3(Vectors.VSub3(v1.p, v0.p), m));
  193. tempv0.pt := Matrix.Mul(trans, tempv0.p); ScreenPos(tempv0.pt, tempv0.x, tempv0.y);
  194. END;
  195. d := Vectors.Scalar3(frustum.nearP.n, Vectors.VNormed3(Vectors.VSub3(v2.p, v0.p)));
  196. IF d # 0 THEN
  197. m := - (Vectors.Scalar3(frustum.nearP.n, v0.p) + frustum.nearP.d) / d / Vectors.VLength3VV(v2.p, v0.p);
  198. tempv1.u := v0.u + (v2.u - v0.u) * m;
  199. tempv1.v := v0.v + (v2.v - v0.v) * m;
  200. tempv1.p := Vectors.VAdd3(v0.p, Vectors.VScaled3(Vectors.VSub3(v2.p, v0.p), m));
  201. tempv1.pt := Matrix.Mul(trans, tempv1.p); ScreenPos(tempv1.pt, tempv1.x, tempv1.y);
  202. END;
  203. tempTri.vert[0] := v0; tempTri.vert[1] := tempv0; tempTri.vert[2] := tempv1; tempTri.tex := tri.tex;
  204. tempTri.color := tri.color; tempTri.transColor := tri.transColor;
  205. RasterTriangle(tempTri);
  206. ELSIF c = 1 THEN
  207. IF tri.vert[0].behind THEN v0 := tri.vert[0]; v1 := tri.vert[1]; v2 := tri.vert[2] END;
  208. IF tri.vert[1].behind THEN v0 := tri.vert[1]; v1 := tri.vert[2]; v2 := tri.vert[0] END;
  209. IF tri.vert[2].behind THEN v0 := tri.vert[2]; v1 := tri.vert[0]; v2 := tri.vert[1] END;
  210. d := Vectors.Scalar3(frustum.nearP.n, Vectors.VNormed3(Vectors.VSub3(v1.p, v0.p)));
  211. IF d # 0 THEN
  212. m := - (Vectors.Scalar3(frustum.nearP.n, v0.p) + frustum.nearP.d) / d / Vectors.VLength3VV(v0.p, v1.p);
  213. tempv0.u := v0.u + (v1.u - v0.u) * m;
  214. tempv0.v := v0.v + (v1.v - v0.v) * m;
  215. tempv0.p := Vectors.VAdd3(v0.p, Vectors.VScaled3(Vectors.VSub3(v1.p, v0.p), m));
  216. tempv0.pt := Matrix.Mul(trans, tempv0.p); ScreenPos(tempv0.pt, tempv0.x, tempv0.y);
  217. END;
  218. d := Vectors.Scalar3(frustum.nearP.n, Vectors.VNormed3(Vectors.VSub3(v2.p, v0.p)));
  219. IF d # 0 THEN
  220. m := - (Vectors.Scalar3(frustum.nearP.n, v0.p) + frustum.nearP.d) / d / Vectors.VLength3VV(v0.p, v2.p);
  221. tempv1.u := v0.u + (v2.u - v0.u) * m;
  222. tempv1.v := v0.v + (v2.v - v0.v) * m;
  223. tempv1.p := Vectors.VAdd3(v0.p, Vectors.VScaled3(Vectors.VSub3(v2.p, v0.p), m));
  224. tempv1.pt := Matrix.Mul(trans, tempv1.p); ScreenPos(tempv1.pt, tempv1.x, tempv1.y);
  225. END;
  226. tempTri.vert[0] := tempv0; tempTri.vert[1] := tempv1; tempTri.vert[2] := v2; tempTri.tex := tri.tex;
  227. tempTri.color := tri.color; tempTri.transColor := tri.transColor;
  228. RasterTriangle(tempTri);
  229. tempTri.vert[0] := tempv0; tempTri.vert[1] := v1; tempTri.vert[2] := v2; tempTri.tex := tri.tex;
  230. tempTri.color := tri.color; tempTri.transColor := tri.transColor;
  231. RasterTriangle(tempTri);
  232. END;
  233. END
  234. END ClipDrawTriangle;
  235. PROCEDURE RenderInternal*(img : Raster.Image; animatedOnly:BOOLEAN);
  236. VAR i, j : LONGINT; obj : Object; huga : ANY; srcCopy:Raster.Mode;
  237. BEGIN
  238. Raster.InitMode(srcCopy, Raster.srcCopy);
  239. IF animatedOnly & worldValid THEN
  240. rasterizer.Restore;
  241. objects.Lock;
  242. FOR i := 0 TO objects.GetCount() - 1 DO
  243. huga := objects.GetItem(i); obj := huga(Object);
  244. IF obj.isAnimated THEN
  245. IF ~obj.bsValid THEN obj.CalcBS END;
  246. IF ~frustum.IsBSOutsideBehind(obj.bsCenter, obj.bsRadius) THEN
  247. rasterizer.SetObjectIndex(obj.index);
  248. FOR j := 0 TO obj.nofVertices - 1 DO
  249. obj.vertices[j].pt := Matrix.Mul(trans, obj.vertices[j].p);
  250. ScreenPos(obj.vertices[j].pt, obj.vertices[j].x, obj.vertices[j].y);
  251. obj.vertices[j].behind := W3dGeometry.Distance(frustum.nearP, obj.vertices[j].p) > 0;
  252. END;
  253. FOR j := 0 TO obj.nofTriangles - 1 DO ClipDrawTriangle(obj.triangles[j]) END
  254. END
  255. END
  256. END;
  257. objects.Unlock
  258. ELSE
  259. objects.Lock;
  260. rasterizer.SetInvertable(invertable); IF ~invertable THEN changed := TRUE ELSE changed := FALSE END;
  261. rasterizer.Clear(clearColor);
  262. FOR i := 0 TO objects.GetCount() - 1 DO
  263. huga := objects.GetItem(i); obj := huga(Object);
  264. IF ~obj.isAnimated THEN
  265. IF ~obj.bsValid THEN obj.CalcBS END;
  266. IF ~frustum.IsBSOutsideBehind(obj.bsCenter, obj.bsRadius) THEN
  267. rasterizer.SetObjectIndex(obj.index);
  268. FOR j := 0 TO obj.nofVertices - 1 DO
  269. obj.vertices[j].pt := Matrix.Mul(trans, obj.vertices[j].p);
  270. ScreenPos(obj.vertices[j].pt, obj.vertices[j].x, obj.vertices[j].y);
  271. obj.vertices[j].behind := W3dGeometry.Distance(frustum.nearP, obj.vertices[j].p) > 0;
  272. END;
  273. FOR j := 0 TO obj.nofTriangles - 1 DO ClipDrawTriangle(obj.triangles[j]) END
  274. END
  275. END
  276. END;
  277. rasterizer.SetInvertable(FALSE);
  278. rasterizer.Keep; worldValid := TRUE;
  279. FOR i := 0 TO objects.GetCount() - 1 DO
  280. huga := objects.GetItem(i); obj := huga(Object);
  281. IF obj.isAnimated THEN
  282. IF ~obj.bsValid THEN obj.CalcBS END;
  283. IF ~frustum.IsBSOutsideBehind(obj.bsCenter, obj.bsRadius) THEN
  284. rasterizer.SetObjectIndex(obj.index);
  285. FOR j := 0 TO obj.nofVertices - 1 DO
  286. obj.vertices[j].pt := Matrix.Mul(trans, obj.vertices[j].p);
  287. ScreenPos(obj.vertices[j].pt, obj.vertices[j].x, obj.vertices[j].y);
  288. obj.vertices[j].behind := W3dGeometry.Distance(frustum.nearP, obj.vertices[j].p) > 0;
  289. END;
  290. FOR j := 0 TO obj.nofTriangles - 1 DO ClipDrawTriangle(obj.triangles[j]) END
  291. END
  292. END
  293. END;
  294. objects.Unlock
  295. END;
  296. IF img # NIL THEN Raster.Copy(rasterizer.img, img, 0, 0, width, height, 0, 0, srcCopy) END;
  297. END RenderInternal;
  298. PROCEDURE Render*(img : Raster.Image; movingOnly : BOOLEAN);
  299. BEGIN {EXCLUSIVE}
  300. RenderInternal(img, movingOnly)
  301. END Render;
  302. PROCEDURE GetOwnerIndex*(x, y : LONGINT): LONGINT;
  303. BEGIN {EXCLUSIVE}
  304. IF ~changed THEN RETURN rasterizer.GetInvIdx(x, y) ELSE
  305. invertable := TRUE;
  306. RenderInternal(NIL, FALSE);
  307. invertable := FALSE;
  308. RETURN rasterizer.GetInvIdx(x, y)
  309. END
  310. END GetOwnerIndex;
  311. END World;
  312. PROCEDURE GrowAABB(VAR aabb : AABB; p : Vectors.TVector3d);
  313. BEGIN
  314. IF aabb.empty THEN
  315. aabb.a := p; aabb.b := p; aabb.empty := FALSE
  316. ELSE
  317. aabb.a.x := MIN(aabb.a.x, p.x); aabb.a.y := MIN(aabb.a.y, p.y); aabb.a.z := MIN(aabb.a.z, p.z);
  318. aabb.b.x := MAX(aabb.b.x, p.x); aabb.b.y := MAX(aabb.b.y, p.y); aabb.b.z := MAX(aabb.b.z, p.z)
  319. END
  320. END GrowAABB;
  321. END W3dWorld.