GLS.FileVRML.pas 18 KB

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