GXS.Feedback.pas 9.1 KB

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