GLS.PolygonTesselation.pas 4.4 KB

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