GLS.Feedback.pas 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. //
  2. // The graphics engine GLScene
  3. //
  4. unit GLS.Feedback;
  5. (*
  6. A scene object encapsulating the OpenGL feedback buffer.
  7. This object, when Active, will render it's children using
  8. the GL_FEEDBACK render mode. This will render the children
  9. into the feedback Buffer rather than into the frame buffer.
  10. Mesh data can be extracted from the buffer using the
  11. BuildMeshFromBuffer procedure. For custom parsing of the
  12. buffer use the Buffer SingleList. The Buffered property
  13. will indicate if there is valid data in the buffer.
  14. *)
  15. interface
  16. {$I Stage.Defines.inc}
  17. uses
  18. Winapi.OpenGL,
  19. System.Classes,
  20. System.SysUtils,
  21. Stage.OpenGLTokens,
  22. Stage.VectorTypes,
  23. Stage.VectorGeometry,
  24. Stage.PipelineTransform,
  25. GLS.PersistentClasses,
  26. GLS.VectorLists,
  27. GLS.Scene,
  28. GLS.VectorFileObjects,
  29. GLS.Texture,
  30. GLS.RenderContextInfo,
  31. GLS.Context,
  32. GLS.State,
  33. GLS.MeshUtils;
  34. type
  35. TGLFeedbackMode = (fm2D, fm3D, fm3DColor, fm3DColorTexture, fm4DColorTexture);
  36. // An object encapsulating the OpenGL feedback rendering mode.
  37. TGLFeedback = class(TGLBaseSceneObject)
  38. private
  39. FActive: Boolean;
  40. FBuffer: TGLSingleList;
  41. FMaxBufferSize: Cardinal;
  42. FBuffered: Boolean;
  43. FCorrectionScaling: Single;
  44. FMode: TGLFeedbackMode;
  45. protected
  46. procedure SetMaxBufferSize(const Value: Cardinal);
  47. procedure SetMode(const Value: TGLFeedbackMode);
  48. public
  49. constructor Create(AOwner: TComponent); override;
  50. destructor Destroy; override;
  51. procedure DoRender(var ARci: TGLRenderContextInfo;
  52. ARenderSelf, ARenderChildren: Boolean); override;
  53. (* Parse the the feedback buffer for polygon data and build
  54. a mesh into the assigned lists. *)
  55. procedure BuildMeshFromBuffer(
  56. Vertices: TGLAffineVectorList = nil;
  57. Normals: TGLAffineVectorList = nil;
  58. Colors: TGLVectorList = nil;
  59. TexCoords: TGLAffineVectorList = nil;
  60. VertexIndices: TGLIntegerList = nil);
  61. // True when there is data in the buffer ready for parsing
  62. property Buffered: Boolean read FBuffered;
  63. // The feedback buffer
  64. property Buffer: TGLSingleList read FBuffer;
  65. (* Vertex positions in the buffer needs to be scaled by
  66. CorrectionScaling to get correct coordinates. *)
  67. property CorrectionScaling: Single read FCorrectionScaling;
  68. published
  69. // Maximum size allocated for the feedback buffer
  70. property MaxBufferSize: Cardinal read FMaxBufferSize write SetMaxBufferSize;
  71. // Toggles the feedback rendering
  72. property Active: Boolean read FActive write FActive;
  73. // The type of data that is collected in the feedback buffer
  74. property Mode: TGLFeedbackMode read FMode write SetMode;
  75. property Visible;
  76. end;
  77. // ----------------------------------------------------------------------
  78. implementation
  79. // ----------------------------------------------------------------------
  80. // ----------
  81. // ---------- TGLFeedback ----------
  82. // ----------
  83. constructor TGLFeedback.Create(AOwner: TComponent);
  84. begin
  85. inherited;
  86. FMaxBufferSize := $100000;
  87. FBuffer := TGLSingleList.Create;
  88. FBuffer.Capacity := FMaxBufferSize div SizeOf(Single);
  89. FBuffered := False;
  90. FActive := False;
  91. FMode := fm3DColorTexture;
  92. end;
  93. destructor TGLFeedback.Destroy;
  94. begin
  95. FBuffer.Free;
  96. inherited;
  97. end;
  98. procedure TGLFeedback.DoRender(var ARci: TglRenderContextInfo;
  99. ARenderSelf, ARenderChildren: Boolean);
  100. function RecursChildRadius(obj: TglBaseSceneObject): Single;
  101. var
  102. i: Integer;
  103. childRadius: Single;
  104. begin
  105. childRadius := 0;
  106. Result := obj.BoundingSphereRadius + VectorLength(obj.AbsolutePosition);
  107. for i := 0 to obj.Count - 1 do
  108. childRadius := RecursChildRadius(obj.Children[i]);
  109. if childRadius > Result then
  110. Result := childRadius;
  111. end;
  112. var
  113. i: integer;
  114. radius: Single;
  115. atype: cardinal;
  116. begin
  117. FBuffer.Count := 0;
  118. try
  119. if (csDesigning in ComponentState) or not Active then
  120. exit;
  121. if not ARenderChildren then
  122. exit;
  123. FCorrectionScaling := 1.0;
  124. for i := 0 to Count - 1 do
  125. begin
  126. radius := RecursChildRadius(Children[i]);
  127. if radius > FCorrectionScaling then
  128. FCorrectionScaling := radius + 1e-5;
  129. end;
  130. case FMode of
  131. fm2D: aType := GL_2D;
  132. fm3D: aType := GL_3D;
  133. fm3DColor: aType := GL_3D_COLOR;
  134. fm3DColorTexture: aType := GL_3D_COLOR_TEXTURE;
  135. fm4DColorTexture: aType := GL_4D_COLOR_TEXTURE;
  136. else
  137. aType := GL_3D_COLOR_TEXTURE;
  138. end;
  139. FBuffer.Count := FMaxBufferSize div SizeOf(Single);
  140. gl.FeedBackBuffer(FMaxBufferSize, atype, @FBuffer.List[0]);
  141. ARci.GLStates.Disable(stCullFace);
  142. ARci.ignoreMaterials := FMode < fm3DColor;
  143. ARci.PipelineTransformation.Push;
  144. ARci.PipelineTransformation.SetProjectionMatrix(IdentityHmgMatrix);
  145. ARci.PipelineTransformation.SetViewMatrix(
  146. CreateScaleMatrix(VectorMake(
  147. 1.0 / FCorrectionScaling,
  148. 1.0 / FCorrectionScaling,
  149. 1.0 / FCorrectionScaling)));
  150. ARci.GLStates.ViewPort := Vector4iMake(-1, -1, 2, 2);
  151. gl.RenderMode(GL_FEEDBACK);
  152. Self.RenderChildren(0, Count - 1, ARci);
  153. FBuffer.Count := gl.RenderMode(GL_RENDER);
  154. ARci.PipelineTransformation.Pop;
  155. finally
  156. ARci.ignoreMaterials := False;
  157. FBuffered := (FBuffer.Count > 0);
  158. if ARenderChildren then
  159. Self.RenderChildren(0, Count - 1, ARci);
  160. end;
  161. ARci.GLStates.ViewPort :=
  162. Vector4iMake(0, 0, ARci.viewPortSize.cx, ARci.viewPortSize.cy);
  163. end;
  164. procedure TGLFeedback.BuildMeshFromBuffer(
  165. Vertices: TGLAffineVectorList = nil;
  166. Normals: TGLAffineVectorList = nil;
  167. Colors: TGLVectorList = nil;
  168. TexCoords: TGLAffineVectorList = nil;
  169. VertexIndices: TGLIntegerList = nil);
  170. var
  171. value: Single;
  172. i, j, LCount, skip: Integer;
  173. vertex, color, texcoord: TGLVector;
  174. tempVertices, tempNormals, tempTexCoords: TGLAffineVectorList;
  175. tempColors: TGLVectorList;
  176. tempIndices: TGLIntegerList;
  177. ColorBuffered, TexCoordBuffered: Boolean;
  178. begin
  179. Assert(FMode <> fm2D, 'Cannot build mesh from fm2D feedback mode.');
  180. tempVertices := TGLAffineVectorList.Create;
  181. tempColors := TGLVectorList.Create;
  182. tempTexCoords := TGLAffineVectorList.Create;
  183. ColorBuffered := (FMode = fm3DColor) or
  184. (FMode = fm3DColorTexture) or
  185. (FMode = fm4DColorTexture);
  186. TexCoordBuffered := (FMode = fm3DColorTexture) or
  187. (FMode = fm4DColorTexture);
  188. i := 0;
  189. skip := 3;
  190. if FMode = fm4DColorTexture then
  191. Inc(skip, 1);
  192. if ColorBuffered then
  193. Inc(skip, 4);
  194. if TexCoordBuffered then
  195. Inc(skip, 4);
  196. while i < FBuffer.Count - 1 do
  197. begin
  198. value := FBuffer[i];
  199. if value = GL_POLYGON_TOKEN then
  200. begin
  201. Inc(i);
  202. value := FBuffer[i];
  203. LCount := Round(value);
  204. Inc(i);
  205. if LCount = 3 then
  206. begin
  207. for j := 0 to 2 do
  208. begin
  209. vertex.X := FBuffer[i];
  210. Inc(i);
  211. vertex.Y := FBuffer[i];
  212. Inc(i);
  213. vertex.Z := FBuffer[i];
  214. Inc(i);
  215. if FMode = fm4DColorTexture then
  216. Inc(i);
  217. if ColorBuffered then
  218. begin
  219. color.X := FBuffer[i];
  220. Inc(i);
  221. color.Y := FBuffer[i];
  222. Inc(i);
  223. color.Z := FBuffer[i];
  224. Inc(i);
  225. color.W := FBuffer[i];
  226. Inc(i);
  227. end;
  228. if TexCoordBuffered then
  229. begin
  230. texcoord.X := FBuffer[i];
  231. Inc(i);
  232. texcoord.Y := FBuffer[i];
  233. Inc(i);
  234. texcoord.Z := FBuffer[i];
  235. Inc(i);
  236. texcoord.W := FBuffer[i];
  237. Inc(i);
  238. end;
  239. vertex.Z := 2 * vertex.Z - 1;
  240. ScaleVector(vertex, FCorrectionScaling);
  241. tempVertices.Add(AffineVectorMake(vertex));
  242. tempColors.Add(color);
  243. tempTexCoords.Add(AffineVectorMake(texcoord));
  244. end;
  245. end
  246. else
  247. begin
  248. Inc(i, skip * LCount);
  249. end;
  250. end
  251. else
  252. begin
  253. Inc(i);
  254. end;
  255. end;
  256. if Assigned(VertexIndices) then
  257. begin
  258. tempIndices := BuildVectorCountOptimizedIndices(tempVertices, nil, nil);
  259. RemapAndCleanupReferences(tempVertices, tempIndices);
  260. VertexIndices.Assign(tempIndices);
  261. end
  262. else
  263. begin
  264. tempIndices := TGLIntegerList.Create;
  265. tempIndices.AddSerie(0, 1, tempVertices.Count);
  266. end;
  267. tempNormals := BuildNormals(tempVertices, tempIndices);
  268. if Assigned(Vertices) then
  269. Vertices.Assign(tempVertices);
  270. if Assigned(Normals) then
  271. Normals.Assign(tempNormals);
  272. if Assigned(Colors) and ColorBuffered then
  273. Colors.Assign(tempColors);
  274. if Assigned(TexCoords) and TexCoordBuffered then
  275. TexCoords.Assign(tempTexCoords);
  276. tempVertices.Destroy;
  277. tempNormals.Destroy;
  278. tempColors.Destroy;
  279. tempTexCoords.Destroy;
  280. tempIndices.Destroy;
  281. end;
  282. procedure TGLFeedback.SetMaxBufferSize(const Value: Cardinal);
  283. begin
  284. if Value <> FMaxBufferSize then
  285. begin
  286. FMaxBufferSize := Value;
  287. FBuffered := False;
  288. FBuffer.Count := 0;
  289. FBuffer.Capacity := FMaxBufferSize div SizeOf(Single);
  290. end;
  291. end;
  292. procedure TGLFeedback.SetMode(const Value: TGLFeedbackMode);
  293. begin
  294. if Value <> FMode then
  295. begin
  296. FMode := Value;
  297. FBuffered := False;
  298. FBuffer.Count := 0;
  299. end;
  300. end;
  301. //------------------------------------------------
  302. initialization
  303. //------------------------------------------------
  304. RegisterClasses([TGLFeedback]);
  305. end.