GLS.PolygonTesselation.pas 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. //
  2. // The graphics engine GLXEngine. The unit of GLScene for Delphi
  3. //
  4. unit GLS.PolygonTesselation;
  5. (* Code to generate triangle strips and fans for polygons *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. Winapi.OpenGL,
  10. System.SysUtils,
  11. GLS.OpenGLAdapter,
  12. Stage.OpenGLTokens,
  13. Stage.VectorTypes,
  14. GLS.VectorLists,
  15. Stage.VectorGeometry,
  16. GLS.VectorFileObjects,
  17. GLS.PersistentClasses;
  18. (* Tesselates the polygon outlined by the Vertexes. And adds them to the first
  19. facegroup of the Mesh. *)
  20. procedure DoTesselate(Vertexes: TGLAffineVectorList; Mesh: TGLBaseMesh;
  21. normal: PAffineVector = nil; invertNormals: Boolean = False);
  22. //---------------------------------------------------------------------------
  23. implementation
  24. //---------------------------------------------------------------------------
  25. {$IFDEF USE_MULTITHREAD}
  26. threadvar
  27. {$ELSE}
  28. var
  29. {$ENDIF}
  30. TessMesh: TGLMeshObject;
  31. TessFace: TFGIndexTexCoordList;
  32. TessVerticesCount, TessExtraVertices: Integer;
  33. TessVertices: PAffineVectorArray;
  34. procedure DoTessBegin(mode: Cardinal);
  35. {$IFDEF MSWINDOWS} stdcall;{$ELSE} cdecl;{$ENDIF}
  36. begin
  37. TessFace := TFGIndexTexCoordList.CreateOwned(TessMesh.FaceGroups);
  38. case mode of
  39. GL_TRIANGLES: TessFace.Mode := fgmmTriangles;
  40. GL_TRIANGLE_STRIP: TessFace.Mode := fgmmTriangleStrip;
  41. GL_TRIANGLE_FAN: TessFace.Mode := fgmmTriangleFan;
  42. end;
  43. end;
  44. procedure DoTessVertex3fv(v: PAffineVector);
  45. {$IFDEF MSWINDOWS} stdcall;{$ELSE} cdecl;{$ENDIF}
  46. begin
  47. TessFace.Add(TessMesh.Vertices.Add(v^), 0, 0);
  48. end;
  49. procedure DoTessEnd;
  50. {$IFDEF MSWINDOWS} stdcall;{$ELSE} cdecl;{$ENDIF}
  51. begin
  52. end;
  53. procedure DoTessError(errno: Cardinal);
  54. {$IFDEF MSWINDOWS} stdcall;{$ELSE} cdecl;{$ENDIF}
  55. begin
  56. Assert(False, IntToStr(errno) + ': ' + string(gluErrorString(errno)));
  57. end;
  58. function AllocNewVertex: PAffineVector;
  59. begin
  60. Inc(TessExtraVertices);
  61. // Allocate more memory if needed
  62. if TessExtraVertices > TessVerticesCount then
  63. begin
  64. TessVerticesCount := TessVerticesCount * 2;
  65. Reallocmem(TessVertices, TessVerticesCount * SizeOf(TAffineVector));
  66. end;
  67. Result := @TessVertices[TessExtraVertices - 1];
  68. end;
  69. procedure DoTessCombine(coords: PDoubleVector; vertex_data: Pointer; weight: PGLFloat; var outData: Pointer);
  70. {$IFDEF MSWINDOWS} stdcall;{$ELSE} cdecl;{$ENDIF}
  71. begin
  72. outData := AllocNewVertex;
  73. SetVector(PAffineVector(outData)^, coords[0], coords[1], coords[2]);
  74. end;
  75. procedure DoTesselate(Vertexes: TGLAffineVectorList; Mesh: TGLBaseMesh; normal: PAffineVector = nil; invertNormals: Boolean = False);
  76. var
  77. Tess: PGLUTesselator;
  78. i: Integer;
  79. dblVector: TAffineDblVector;
  80. begin
  81. // Select or Create FaceGroup
  82. if Mesh.MeshObjects.Count = 0 then
  83. begin
  84. TessMesh := TGLMeshObject.CreateOwned(Mesh.MeshObjects);
  85. Mesh.MeshObjects[0].Mode := momFaceGroups;
  86. end
  87. else
  88. TessMesh := Mesh.MeshObjects[0];
  89. // vertices count.
  90. TessVerticesCount := Vertexes.Count;
  91. // allocate extra buffer used by GLU in complex polygons.
  92. GetMem(TessVertices, TessVerticesCount * SizeOf(TAffineVector));
  93. // make a Tessellation GLU object.
  94. Tess := gluNewTess;
  95. // set up callback events
  96. gluTessCallback(Tess, GLU_TESS_BEGIN, @DoTessBegin);
  97. gluTessCallback(tess, GLU_TESS_VERTEX, @DoTessVertex3fv);
  98. gluTessCallback(tess, GLU_TESS_END, @DoTessEnd);
  99. gluTessCallback(tess, GLU_TESS_ERROR, @DoTessError);
  100. gluTessCallback(tess, GLU_TESS_COMBINE, @DoTessCombine);
  101. if Assigned(normal) then
  102. gluTessNormal(tess, normal^.X, normal^.Y, normal^.Z)
  103. else
  104. gluTessNormal(tess, 0, 1, 0);
  105. // start tesselation of polygon
  106. gluTessBeginPolygon(tess, nil);
  107. // build outline, a polygon can have multiple outlines.
  108. gluTessBeginContour(tess);
  109. TessExtraVertices := 0;
  110. if invertNormals then
  111. begin
  112. for i := Vertexes.Count - 1 downto 0 do
  113. begin
  114. SetVector(dblVector, Vertexes.Items[i]);
  115. gluTessVertex(tess, dblVector, Vertexes.ItemAddress[i]);
  116. end;
  117. end
  118. else
  119. begin
  120. for i := 0 to Vertexes.Count - 1 do
  121. begin
  122. SetVector(dblVector, Vertexes.Items[i]);
  123. gluTessVertex(tess, dblVector, Vertexes.ItemAddress[i]);
  124. end;
  125. end;
  126. gluTessEndContour(tess);
  127. // End Tesselation of polygon, THIS is where the data is processed! (And all the events triggered!)
  128. gluTessEndPolygon(tess);
  129. // Delete the Tessellation GLU object.
  130. gluDeleteTess(tess);
  131. // deallocate extra buffer used by GLU in complex polygons.
  132. FreeMem(TessVertices, TessVerticesCount * SizeOf(TAffineVector));
  133. end;
  134. end.