GLFileVRML.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. {
  5. Preliminary VRML vector file support.
  6. }
  7. unit GLFileVRML;
  8. interface
  9. {$I GLScene.inc}
  10. uses
  11. System.Classes,
  12. System.SysUtils,
  13. System.Math,
  14. GLVectorFileObjects,
  15. GLMaterial,
  16. GLApplicationFileIO,
  17. GLVectorTypes,
  18. GLVectorGeometry,
  19. GLVectorLists,
  20. FileVRMLParser,
  21. GLMeshUtils;
  22. type
  23. TGLVRMLVectorFile = class(TGLVectorFile)
  24. public
  25. class function Capabilities: TGLDataFileCapabilities; override;
  26. procedure LoadFromStream(aStream: TStream); override;
  27. end;
  28. // ------------------------------------------------------------------
  29. implementation
  30. // ------------------------------------------------------------------
  31. procedure TessellatePolygon(PolyVerts: TAffineVectorList;
  32. PolyIndices, TriIndices: TIntegerList);
  33. function IsPolyClockWise: Boolean;
  34. var
  35. i, j: Integer;
  36. det: Single;
  37. mat: TAffineMatrix;
  38. begin
  39. det := 0;
  40. for i := 0 to PolyIndices.Count - 1 do
  41. begin
  42. for j := 0 to 2 do
  43. if (i + j) >= PolyIndices.Count then
  44. mat.V[j] := PolyVerts[PolyIndices[i + j - PolyIndices.Count]]
  45. else
  46. mat.V[j] := PolyVerts[PolyIndices[i + j]];
  47. det := det + MatrixDeterminant(mat);
  48. end;
  49. Result := (det < 0);
  50. end;
  51. function IsTriClockWise(v0, v1, v2: TAffineVector): Boolean;
  52. var
  53. mat: TAffineMatrix;
  54. begin
  55. mat.V[0] := v0;
  56. mat.V[1] := v1;
  57. mat.V[2] := v2;
  58. Result := (MatrixDeterminant(mat) < 0);
  59. end;
  60. function PointInTriangle(p, v0, v1, v2: TAffineVector;
  61. IsClockWise: Boolean = False): Boolean;
  62. begin
  63. Result := not((IsTriClockWise(v1, v0, p) = IsClockWise) or
  64. (IsTriClockWise(v0, v2, p) = IsClockWise) or
  65. (IsTriClockWise(v2, v1, p) = IsClockWise));
  66. end;
  67. var
  68. i, j, prev, next, min_vert, min_prev, min_next: Integer;
  69. PolyCW, NoPointsInTriangle: Boolean;
  70. V: TAffineMatrix;
  71. temp: TIntegerList;
  72. min_dist, d, area: Single;
  73. begin
  74. temp := TIntegerList.Create;
  75. try
  76. PolyCW := IsPolyClockWise;
  77. temp.Assign(PolyIndices);
  78. while temp.Count > 3 do
  79. begin
  80. min_dist := 10E7;
  81. min_vert := -1;
  82. min_prev := -1;
  83. min_next := -1;
  84. for i := 0 to temp.Count - 1 do
  85. begin
  86. prev := i - 1;
  87. next := i + 1;
  88. if prev < 0 then
  89. prev := temp.Count - 1;
  90. if next > temp.Count - 1 then
  91. next := 0;
  92. V.V[0] := PolyVerts[temp[prev]];
  93. V.V[1] := PolyVerts[temp[i]];
  94. V.V[2]:= PolyVerts[temp[next]];
  95. if IsTriClockWise(V.V[0], V.V[1], V.V[2]) = PolyCW then
  96. begin
  97. NoPointsInTriangle := True;
  98. for j := 0 to temp.Count - 1 do
  99. begin
  100. if (j <> i) and (j <> prev) and (j <> next) then
  101. begin
  102. if PointInTriangle(PolyVerts[temp[j]], V.V[0], V.V[1], V.V[2], PolyCW) then
  103. begin
  104. NoPointsInTriangle := False;
  105. Break;
  106. end;
  107. end;
  108. end;
  109. area := TriangleArea(V.V[0], V.V[1], V.V[2]);
  110. if NoPointsInTriangle and (area > 0) then
  111. begin
  112. d := VectorDistance2(V.V[0], V.V[2]);
  113. if d < min_dist then
  114. begin
  115. min_dist := d;
  116. min_prev := prev;
  117. min_vert := i;
  118. min_next := next;
  119. end;
  120. end;
  121. end;
  122. end;
  123. if min_vert = -1 then
  124. begin
  125. raise Exception.Create('Failed to tessellate polygon.');
  126. end
  127. else
  128. begin
  129. TriIndices.Add(temp[min_prev], temp[min_vert], temp[min_next]);
  130. temp.Delete(min_vert);
  131. end;
  132. end;
  133. TriIndices.Add(temp[0], temp[1], temp[2]);
  134. finally
  135. temp.Free;
  136. end;
  137. end;
  138. // ------------------
  139. // ------------------ TGLVRMLVectorFile ------------------
  140. // ------------------
  141. class function TGLVRMLVectorFile.Capabilities: TGLDataFileCapabilities;
  142. begin
  143. Result := [dfcRead];
  144. end;
  145. procedure TGLVRMLVectorFile.LoadFromStream(aStream: TStream);
  146. var
  147. mesh: TMeshObject;
  148. uniqueMatID: Integer;
  149. currentMaterial: TGLLibMaterial;
  150. currentTransform: TMatrix;
  151. creaseAngle: Single;
  152. function GetUniqueMaterialName: String;
  153. var
  154. libMat: TGLLibMaterial;
  155. begin
  156. repeat
  157. Result := 'UntitledMaterial' + IntToStr(uniqueMatID);
  158. Inc(uniqueMatID);
  159. libMat := Owner.MaterialLibrary.Materials.GetLibMaterialByName(Result);
  160. until not Assigned(libMat);
  161. end;
  162. function AddMaterialToLibrary(VRMLMaterial: TVRMLMaterial): TGLLibMaterial;
  163. var
  164. matname: String;
  165. begin
  166. Result := nil;
  167. if not Assigned(Owner.MaterialLibrary) then
  168. Exit;
  169. if VRMLMaterial.DefName = '' then
  170. matname := GetUniqueMaterialName
  171. else
  172. matname := VRMLMaterial.DefName;
  173. Result := Owner.MaterialLibrary.Materials.GetLibMaterialByName(matname);
  174. if not Assigned(Result) then
  175. begin
  176. Result := Owner.MaterialLibrary.Materials.Add;
  177. Result.Name := matname;
  178. end;
  179. // Assign values from the current material
  180. if Assigned(currentMaterial) then
  181. Result.Material.FrontProperties.Assign
  182. (currentMaterial.Material.FrontProperties);
  183. with Result.Material.FrontProperties do
  184. begin
  185. if VRMLMaterial.HasDiffuse then
  186. Diffuse.Color := VectorMake(VRMLMaterial.DiffuseColor, Diffuse.Color.W);
  187. if VRMLMaterial.HasAmbient then
  188. Ambient.Color := VectorMake(VRMLMaterial.AmbientColor, Ambient.Color.W);
  189. if VRMLMaterial.HasSpecular then
  190. Specular.Color := VectorMake(VRMLMaterial.SpecularColor,
  191. Specular.Color.W);
  192. if VRMLMaterial.HasEmissive then
  193. Emission.Color := VectorMake(VRMLMaterial.EmissiveColor,
  194. Emission.Color.W);
  195. if Shininess = 0 then
  196. Shininess := 16;
  197. if VRMLMaterial.HasShininess then
  198. Shininess := Floor(128 * VRMLMaterial.Shininess);
  199. if VRMLMaterial.HasTransparency then
  200. begin
  201. Diffuse.Color := VectorMake(AffineVectorMake(Diffuse.Color),
  202. 1 - VRMLMaterial.Transparency);
  203. Ambient.Color := VectorMake(AffineVectorMake(Ambient.Color),
  204. 1 - VRMLMaterial.Transparency);
  205. Specular.Color := VectorMake(AffineVectorMake(Specular.Color),
  206. 1 - VRMLMaterial.Transparency);
  207. Emission.Color := VectorMake(AffineVectorMake(Emission.Color),
  208. 1 - VRMLMaterial.Transparency);
  209. end;
  210. end;
  211. if VRMLMaterial.HasTransparency then
  212. Result.Material.BlendingMode := bmTransparency;
  213. end;
  214. procedure RebuildMesh;
  215. var
  216. i, j, k, l: Integer;
  217. newfg: TFGVertexIndexList;
  218. fg: TFGVertexNormalTexIndexList;
  219. vertices, normals, texcoords, triNormals, newVertices, newNormals,
  220. newTexCoords: TAffineVectorList;
  221. optimized: TIntegerList;
  222. cosAngle: Single;
  223. normal: TAffineVector;
  224. s, t: array [0 .. 2] of Integer;
  225. n: array [0 .. 2] of TIntegerList;
  226. smooth, hasVertices, hasNormals, hasNormalIndices, hasTexCoords,
  227. hasTexCoordIndices: Boolean;
  228. begin
  229. if not Assigned(mesh) then
  230. Exit;
  231. hasVertices := mesh.vertices.Count > 0;
  232. hasNormals := mesh.normals.Count > 0;
  233. hasTexCoords := mesh.texcoords.Count > 0;
  234. if not hasVertices then
  235. Exit;
  236. vertices := TAffineVectorList.Create;
  237. normals := TAffineVectorList.Create;
  238. texcoords := TAffineVectorList.Create;
  239. newVertices := TAffineVectorList.Create;
  240. newNormals := TAffineVectorList.Create;
  241. newTexCoords := TAffineVectorList.Create;
  242. triNormals := TAffineVectorList.Create;
  243. n[0] := TIntegerList.Create;
  244. n[1] := TIntegerList.Create;
  245. n[2] := TIntegerList.Create;
  246. for i := 0 to mesh.FaceGroups.Count - 1 do
  247. begin
  248. fg := TFGVertexNormalTexIndexList(mesh.FaceGroups[i]);
  249. hasNormalIndices := fg.NormalIndices.Count > 0;
  250. hasTexCoordIndices := fg.TexCoordIndices.Count > 0;
  251. vertices.Clear;
  252. normals.Clear;
  253. texcoords.Clear;
  254. triNormals.Clear;
  255. if not hasNormals then
  256. begin
  257. for j := 0 to (fg.VertexIndices.Count div 3) - 1 do
  258. begin
  259. normal := VectorCrossProduct
  260. (VectorNormalize(VectorSubtract(mesh.vertices[fg.VertexIndices[3 * j
  261. + 1]], mesh.vertices[fg.VertexIndices[3 * j]])),
  262. VectorNormalize(VectorSubtract(mesh.vertices[fg.VertexIndices[3 * j
  263. + 2]], mesh.vertices[fg.VertexIndices[3 * j]])));
  264. triNormals.Add(VectorNormalize(normal));
  265. end;
  266. end;
  267. for j := 0 to (fg.VertexIndices.Count div 3) - 1 do
  268. begin
  269. vertices.Add(mesh.vertices[fg.VertexIndices[3 * j]],
  270. mesh.vertices[fg.VertexIndices[3 * j + 1]],
  271. mesh.vertices[fg.VertexIndices[3 * j + 2]]);
  272. if hasNormals then
  273. begin
  274. if hasNormalIndices then
  275. begin
  276. normals.Add(mesh.normals[fg.NormalIndices[3 * j]],
  277. mesh.normals[fg.NormalIndices[3 * j + 1]],
  278. mesh.normals[fg.NormalIndices[3 * j + 2]]);
  279. end
  280. else
  281. begin
  282. normals.Add(mesh.normals[fg.VertexIndices[3 * j]],
  283. mesh.normals[fg.VertexIndices[3 * j + 1]],
  284. mesh.normals[fg.VertexIndices[3 * j + 2]]);
  285. end;
  286. end
  287. else
  288. begin
  289. // No normal data, generate the normals
  290. n[0].Clear;
  291. n[1].Clear;
  292. n[2].Clear;
  293. s[0] := fg.VertexIndices[3 * j];
  294. s[1] := fg.VertexIndices[3 * j + 1];
  295. s[2] := fg.VertexIndices[3 * j + 2];
  296. for k := 0 to (fg.VertexIndices.Count div 3) - 1 do
  297. if j <> k then
  298. begin
  299. t[0] := fg.VertexIndices[3 * k];
  300. t[1] := fg.VertexIndices[3 * k + 1];
  301. t[2] := fg.VertexIndices[3 * k + 2];
  302. if (s[0] = t[0]) or (s[0] = t[1]) or (s[0] = t[2]) then
  303. n[0].Add(k);
  304. if (s[1] = t[0]) or (s[1] = t[1]) or (s[1] = t[2]) then
  305. n[1].Add(k);
  306. if (s[2] = t[0]) or (s[2] = t[1]) or (s[2] = t[2]) then
  307. n[2].Add(k);
  308. end;
  309. for k := 0 to 2 do
  310. begin
  311. if n[k].Count > 0 then
  312. begin
  313. smooth := True;
  314. for l := 0 to n[k].Count - 1 do
  315. begin
  316. cosAngle := VectorAngleCosine(triNormals[j],
  317. triNormals[n[k][l]]);
  318. smooth := smooth and (cosAngle > Cos(creaseAngle));
  319. if not smooth then
  320. Break;
  321. end;
  322. if smooth then
  323. begin
  324. normal := triNormals[j];
  325. for l := 0 to n[k].Count - 1 do
  326. AddVector(normal, triNormals[n[k][l]]);
  327. ScaleVector(normal, 1 / (n[k].Count + 1));
  328. normals.Add(VectorNormalize(normal));
  329. end
  330. else
  331. normals.Add(triNormals[j]);
  332. end
  333. else
  334. begin
  335. normals.Add(triNormals[j]);
  336. end;
  337. end;
  338. end;
  339. if hasTexCoords then
  340. begin
  341. if hasTexCoordIndices then
  342. begin
  343. texcoords.Add(mesh.texcoords[fg.TexCoordIndices[3 * j]],
  344. mesh.texcoords[fg.TexCoordIndices[3 * j + 1]],
  345. mesh.texcoords[fg.TexCoordIndices[3 * j + 2]]);
  346. end
  347. else
  348. begin
  349. texcoords.Add(mesh.texcoords[fg.VertexIndices[3 * j]],
  350. mesh.texcoords[fg.VertexIndices[3 * j + 1]],
  351. mesh.texcoords[fg.VertexIndices[3 * j + 2]]);
  352. end;
  353. end;
  354. end;
  355. // Optimize the mesh
  356. if hasTexCoords then
  357. begin
  358. optimized := BuildVectorCountOptimizedIndices(vertices, normals,
  359. texcoords);
  360. RemapReferences(texcoords, optimized);
  361. end
  362. else
  363. optimized := BuildVectorCountOptimizedIndices(vertices, normals);
  364. RemapReferences(normals, optimized);
  365. RemapAndCleanupReferences(vertices, optimized);
  366. optimized.Offset(newVertices.Count);
  367. // Replace the facegroup with a vertex-only index list
  368. newfg := TFGVertexIndexList.Create;
  369. newfg.Owner := mesh.FaceGroups;
  370. newfg.Mode := fg.Mode;
  371. newfg.MaterialName := fg.MaterialName;
  372. newfg.VertexIndices.Assign(optimized);
  373. mesh.FaceGroups.Insert(i, newfg);
  374. mesh.FaceGroups.RemoveAndFree(fg);
  375. optimized.Free;
  376. newVertices.Add(vertices);
  377. newNormals.Add(normals);
  378. newTexCoords.Add(texcoords);
  379. end;
  380. vertices.Free;
  381. normals.Free;
  382. texcoords.Free;
  383. n[0].Free;
  384. n[1].Free;
  385. n[2].Free;
  386. triNormals.Free;
  387. if newVertices.Count > 0 then
  388. mesh.vertices.Assign(newVertices);
  389. if newNormals.Count > 0 then
  390. mesh.normals.Assign(newNormals);
  391. if newTexCoords.Count > 0 then
  392. mesh.texcoords.Assign(newTexCoords);
  393. newVertices.Free;
  394. newNormals.Free;
  395. newTexCoords.Free;
  396. end;
  397. procedure RecursNodes(node: TVRMLNode);
  398. var
  399. i, j, n: Integer;
  400. points: TSingleList;
  401. indices, fgindices: TIntegerList;
  402. fg: TFGVertexNormalTexIndexList;
  403. face: TIntegerList;
  404. tempLibMat: TGLLibMaterial;
  405. saveTransform, mat: TMatrix;
  406. saveMaterial: TGLLibMaterial;
  407. axis: TAffineVector;
  408. angle: Single;
  409. begin
  410. // Store current transform and material
  411. saveTransform := currentTransform;
  412. saveMaterial := currentMaterial;
  413. // Look for a child node data (transforms and materials)
  414. for i := 0 to node.Count - 1 do
  415. if node[i] is TVRMLTransform then
  416. begin
  417. if not VectorEquals(TVRMLTransform(node[i]).Rotation, NullHMGVector)
  418. then
  419. begin
  420. axis := AffineVectorMake(TVRMLTransform(node[i]).Rotation);
  421. angle := TVRMLTransform(node[i]).Rotation.W;
  422. mat := MatrixMultiply(CreateRotationMatrix(axis, angle),
  423. CreateRotationMatrixZ(Pi / 2));
  424. end
  425. else
  426. mat := IdentityHMGMatrix;
  427. for j := 0 to 2 do
  428. mat.V[j] := VectorScale(mat.V[j], TVRMLTransform(node[i]).ScaleFactor.V[j]);
  429. mat.V[3] := PointMake(TVRMLTransform(node[i]).Center);
  430. currentTransform := MatrixMultiply(mat, currentTransform);
  431. end
  432. else if node[i] is TVRMLMaterial then
  433. begin
  434. currentMaterial := AddMaterialToLibrary(TVRMLMaterial(node[i]));
  435. end
  436. else if node[i] is TVRMLShapeHints then
  437. begin
  438. creaseAngle := TVRMLShapeHints(node[i]).creaseAngle;
  439. end
  440. else if node[i] is TVRMLUse then
  441. begin
  442. if Assigned(Owner.MaterialLibrary) then
  443. begin
  444. tempLibMat := Owner.MaterialLibrary.Materials.GetLibMaterialByName
  445. (TVRMLUse(node[i]).Value);
  446. if Assigned(tempLibMat) then
  447. currentMaterial := tempLibMat;
  448. end;
  449. end;
  450. // Read node data
  451. if (node.Name = 'Coordinate3') and (node.Count > 0) then
  452. begin
  453. RebuildMesh;
  454. mesh := TMeshObject.CreateOwned(Owner.MeshObjects);
  455. points := TVRMLSingleArray(node[0]).Values;
  456. for i := 0 to (points.Count div 3) - 1 do
  457. mesh.vertices.Add(points[3 * i], points[3 * i + 1], points[3 * i + 2]);
  458. mesh.vertices.TransformAsPoints(currentTransform);
  459. end
  460. else if (node.Name = 'Normal') and (node.Count > 0) and Assigned(mesh) then
  461. begin
  462. points := TVRMLSingleArray(node[0]).Values;
  463. for i := 0 to (points.Count div 3) - 1 do
  464. mesh.normals.Add(points[3 * i], points[3 * i + 1], points[3 * i + 2]);
  465. mesh.normals.TransformAsVectors(currentTransform);
  466. end
  467. else if (node.Name = 'TextureCoordinate2') and (node.Count > 0) and
  468. Assigned(mesh) then
  469. begin
  470. points := TVRMLSingleArray(node[0]).Values;
  471. for i := 0 to (points.Count div 2) - 1 do
  472. mesh.texcoords.Add(points[2 * i], points[2 * i + 1], 0);
  473. end
  474. else if (node.Name = 'IndexedFaceSet') and (node.Count > 0) and
  475. Assigned(mesh) then
  476. begin
  477. fg := TFGVertexNormalTexIndexList.CreateOwned(mesh.FaceGroups);
  478. mesh.Mode := momFaceGroups;
  479. face := TIntegerList.Create;
  480. if Assigned(currentMaterial) then
  481. fg.MaterialName := currentMaterial.Name;
  482. for n := 0 to node.Count - 1 do
  483. begin
  484. if node[n].Name = 'CoordIndexArray' then
  485. fgindices := fg.VertexIndices
  486. else if node[n].Name = 'NormalIndexArray' then
  487. fgindices := fg.NormalIndices
  488. else if node[n].Name = 'TextureCoordIndexArray' then
  489. fgindices := fg.TexCoordIndices
  490. else
  491. fgindices := nil;
  492. if not Assigned(fgindices) then
  493. Continue;
  494. indices := TVRMLIntegerArray(node[n]).Values;
  495. i := 0;
  496. while i < indices.Count do
  497. begin
  498. if indices[i] = -1 then
  499. begin
  500. if face.Count <= 4 then
  501. begin
  502. for j := 0 to face.Count - 3 do
  503. fgindices.Add(face[0], face[j + 1], face[j + 2]);
  504. end
  505. else
  506. begin
  507. TessellatePolygon(mesh.vertices, face, fgindices);
  508. end;
  509. face.Clear;
  510. end
  511. else
  512. begin
  513. face.Add(indices[i]);
  514. end;
  515. i := i + 1;
  516. end;
  517. end;
  518. face.Free;
  519. end
  520. else
  521. begin
  522. // Continue recursion through child nodes
  523. for i := 0 to node.Count - 1 do
  524. RecursNodes(node[i]);
  525. end;
  526. // Load transform and material from stored values
  527. currentTransform := saveTransform;
  528. currentMaterial := saveMaterial;
  529. end;
  530. var
  531. str: TStringList;
  532. parser: TVRMLParser;
  533. begin
  534. str := TStringList.Create;
  535. parser := TVRMLParser.Create;
  536. currentMaterial := nil;
  537. currentTransform := IdentityHMGMatrix;
  538. creaseAngle := 0.5;
  539. mesh := nil;
  540. uniqueMatID := 0;
  541. try
  542. str.LoadFromStream(aStream);
  543. parser.Parse(str.Text);
  544. currentMaterial := nil;
  545. RecursNodes(parser.RootNode);
  546. RebuildMesh;
  547. finally
  548. str.Free;
  549. parser.Free;
  550. end;
  551. end;
  552. // ------------------------------------------------------------------
  553. initialization
  554. // ------------------------------------------------------------------
  555. RegisterVectorFileFormat('wrl', 'VRML files', TGLVRMLVectorFile);
  556. end.