GXS.ParametricSurfaces.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.ParametricSurfaces;
  5. (*
  6. Parametric surface implementation (like Bezier and BSpline surfaces)
  7. Notes:
  8. The MOParametricSurface is a TgxMeshObject descendant that can be used
  9. to render parametric surfaces. The Renderer property defines if the
  10. surface should be rendered using mesh evaluators (through GLU
  11. Nurbs for BSplines) or through GLScene using the CurvesAndSurfaces.pas
  12. routines to generate the mesh vertices and then rendered through the
  13. standard TgxMeshObject render routine. Please note that BSplines aren't
  14. correctly handled yet in the CurvesAndSurfaces unit so the output mesh
  15. in rendering mode is wrong. I'll have it fixed when I know
  16. what's going wrong. The GLU Nurbs and glMeshEval Beziers work well
  17. though.
  18. The FGBezierSurface is a face group decendant that renders the surface
  19. using mesh evaluators. The ControlPointIndices point to the mesh object
  20. vertices much the same as vertex indices for other face group flavours.
  21. The MinU, MaxU, MinV and MaxV properties allow for drawing specific
  22. parts of the bezier surface, which can be used to blend a patch with
  23. other patches.
  24. *)
  25. interface
  26. {$I Stage.Defines.inc}
  27. uses
  28. Winapi.OpenGL,
  29. Stage.VectorTypes,
  30. GXS.CurvesAndSurfaces,
  31. Stage.VectorGeometry,
  32. GXS.VectorLists,
  33. GXS.PersistentClasses,
  34. GXS.VectorFileObjects,
  35. GXS.Texture,
  36. GXS.State,
  37. GXS.Context,
  38. GXS.RenderContextInfo;
  39. type
  40. (* psrGLXcene tells the surface to render using GLScene code to build
  41. the mesh, whereas, psrOpenVX uses glEvalMesh2 or gluNurbsRenderer
  42. calls to render the surface. *)
  43. TParametricSurfaceRenderer = (psrGLXcene, psrOpenVX);
  44. (* psbBezier indicates building the surface with Bernstein basis
  45. functions, no knot or order properties are used.
  46. psbBSpline indicates building the surface using BSpline basis
  47. functions, these require orders and knot vectors to define the
  48. control point influences on the surface. *)
  49. TParametricSurfaceBasis = (psbBezier, psbBSpline);
  50. TMOParametricSurface = class(TgxMeshObject)
  51. private
  52. FControlPoints, FWeightedControlPoints: TgxAffineVectorList;
  53. FKnotsU, FKnotsV, FWeights: TgxSingleList;
  54. FOrderU, FOrderV, FCountU, FCountV, FResolution: Integer;
  55. FAutoKnots: Boolean;
  56. FContinuity: TBSplineContinuity;
  57. FRenderer: TParametricSurfaceRenderer;
  58. FBasis: TParametricSurfaceBasis;
  59. procedure SetControlPoints(Value: TgxAffineVectorList);
  60. procedure SetKnotsU(Value: TgxSingleList);
  61. procedure SetKnotsV(Value: TgxSingleList);
  62. procedure SetWeights(Value: TgxSingleList);
  63. procedure SetRenderer(Value: TParametricSurfaceRenderer);
  64. procedure SetBasis(Value: TParametricSurfaceBasis);
  65. public
  66. constructor Create; override;
  67. destructor Destroy; override;
  68. procedure WriteToFiler(writer: TgxVirtualWriter); override;
  69. procedure ReadFromFiler(reader: TgxVirtualReader); override;
  70. procedure BuildList(var mrci: TgxRenderContextInfo); override;
  71. procedure Prepare; override;
  72. procedure Clear; override;
  73. (* Generates a mesh approximation of the surface defined by the
  74. properties below. This is used to construct the mesh when using
  75. Renderer = psrGLXcene. If you want to render using OpenGL calls
  76. but would like to obtain the mesh data also use this call to
  77. generate the mesh data. Fills in Vertices, Normals, etc. *)
  78. procedure GenerateMesh;
  79. // Control points define the parametric surface.
  80. property ControlPoints: TgxAffineVectorList read FControlPoints write SetControlPoints;
  81. { KnotsU and KnotsV are the knot vectors in the U and V direction. Knots
  82. define the continuity of curves and how control points influence the
  83. parametric values to build the surface. }
  84. property KnotsU: TgxSingleList read FKnotsU write SetKnotsU;
  85. property KnotsV: TgxSingleList read FKnotsV write SetKnotsV;
  86. { Weights define how much a control point effects the surface. }
  87. property Weights: TgxSingleList read FWeights write SetWeights;
  88. // OrderU and OrderV defines the curve order in the U and V direction
  89. property OrderU: Integer read FOrderU write FOrderU;
  90. property OrderV: Integer read FOrderV write FOrderV;
  91. { CountU and CountV describe the number of control points in the
  92. U and V direciton. Basically a control point width and height
  93. in (u,v) space. }
  94. property CountU: Integer read FCountU write FCountU;
  95. property CountV: Integer read FCountV write FCountV;
  96. { Defines how fine the resultant mesh will be. Higher values create
  97. finer meshes. Resolution = 50 would produce a 50x50 mesh.
  98. The GLU Nurbs rendering uses resolution as the U_STEP and V_STEP
  99. using the sampling method GLU_DOMAIN_DISTANCE, so the resolution
  100. works a little differently there. }
  101. property Resolution: Integer read FResolution write FResolution;
  102. { Automatically generate the knot vectors based on the Continuity.
  103. Only applies to BSpline surfaces. }
  104. property AutoKnots: Boolean read FAutoKnots write FAutoKnots;
  105. property Continuity: TBSplineContinuity read FContinuity write FContinuity;
  106. { Determines whether to use OpenGL calls (psrOpenGL) or the GLScene
  107. mesh objects (psrGLScene) to render the surface. }
  108. property Renderer: TParametricSurfaceRenderer read FRenderer write SetRenderer;
  109. // Basis determines the style of curve, psbBezier or psbBSpline
  110. property Basis: TParametricSurfaceBasis read FBasis write SetBasis;
  111. end;
  112. (* A 3d bezier surface implemented through facegroups. The ControlPointIndices
  113. is an index to control points stored in the MeshObject.Vertices affine
  114. vector list. Similarly the TexCoordIndices point to the owner
  115. MeshObject.TexCoords, one for each control point.
  116. CountU and CountV define the width and height of the surface.
  117. Resolution sets the detail level of the mesh evaluation.
  118. MinU, MaxU, MinV and MaxV define the region of the surface to be rendered,
  119. this is especially useful for blending with neighbouring patches. *)
  120. TFGBezierSurface = class(TgxFaceGroup)
  121. private
  122. FCountU, FCountV: Integer;
  123. FControlPointIndices, FTexCoordIndices: TgxIntegerList;
  124. FResolution: Integer;
  125. FMinU, FMaxU, FMinV, FMaxV: Single;
  126. FTempControlPoints, FTempTexCoords: TgxAffineVectorList;
  127. protected
  128. procedure SetControlPointIndices(const Value: TgxIntegerList);
  129. procedure SetTexCoordIndices(const Value: TgxIntegerList);
  130. public
  131. constructor Create; override;
  132. destructor Destroy; override;
  133. procedure WriteToFiler(writer: TgxVirtualWriter); override;
  134. procedure ReadFromFiler(reader: TgxVirtualReader); override;
  135. procedure BuildList(var mrci: TgxRenderContextInfo); override;
  136. procedure Prepare; override;
  137. property CountU: Integer read FCountU write FCountU;
  138. property CountV: Integer read FCountV write FCountV;
  139. property Resolution: Integer read FResolution write FResolution;
  140. property MinU: Single read FMinU write FMinU;
  141. property MaxU: Single read FMaxU write FMaxU;
  142. property MinV: Single read FMinV write FMinV;
  143. property MaxV: Single read FMaxV write FMaxV;
  144. property ControlPointIndices: TgxIntegerList read FControlPointIndices write SetControlPointIndices;
  145. property TexCoordIndices: TgxIntegerList read FTexCoordIndices write SetTexCoordIndices;
  146. end;
  147. // ----------------------------------------------------------------------
  148. implementation
  149. // ----------------------------------------------------------------------
  150. // ------------------
  151. // ------------------ TMOParametricSurface ------------------
  152. // ------------------
  153. constructor TMOParametricSurface.Create;
  154. begin
  155. inherited;
  156. FControlPoints := TgxAffineVectorList.Create;
  157. FWeightedControlPoints := TgxAffineVectorList.Create;
  158. FKnotsU := TgxSingleList.Create;
  159. FKnotsV := TgxSingleList.Create;
  160. FWeights := TgxSingleList.Create;
  161. Resolution := 20;
  162. end;
  163. destructor TMOParametricSurface.Destroy;
  164. begin
  165. FControlPoints.Free;
  166. FWeightedControlPoints.Free;
  167. FKnotsU.Free;
  168. FKnotsV.Free;
  169. FWeights.Free;
  170. inherited;
  171. end;
  172. procedure TMOParametricSurface.WriteToFiler(writer: TgxVirtualWriter);
  173. begin
  174. inherited WriteToFiler(writer);
  175. with writer do
  176. begin
  177. WriteInteger(0); // Archive Version
  178. FControlPoints.WriteToFiler(writer);
  179. FKnotsU.WriteToFiler(writer);
  180. FKnotsV.WriteToFiler(writer);
  181. FWeights.WriteToFiler(writer);
  182. WriteInteger(FOrderU);
  183. WriteInteger(FOrderV);
  184. WriteInteger(FCountU);
  185. WriteInteger(FCountV);
  186. WriteInteger(FResolution);
  187. WriteBoolean(FAutoKnots);
  188. WriteInteger(Integer(FContinuity));
  189. WriteInteger(Integer(FRenderer));
  190. WriteInteger(Integer(FBasis));
  191. end;
  192. end;
  193. procedure TMOParametricSurface.ReadFromFiler(reader: TgxVirtualReader);
  194. var
  195. archiveVersion: Integer;
  196. begin
  197. inherited ReadFromFiler(reader);
  198. archiveVersion := reader.ReadInteger;
  199. if archiveVersion = 0 then
  200. with reader do
  201. begin
  202. FControlPoints.ReadFromFiler(reader);
  203. FKnotsU.ReadFromFiler(reader);
  204. FKnotsV.ReadFromFiler(reader);
  205. FWeights.ReadFromFiler(reader);
  206. FOrderU := ReadInteger;
  207. FOrderV := ReadInteger;
  208. FCountU := ReadInteger;
  209. FCountV := ReadInteger;
  210. FResolution := ReadInteger;
  211. FAutoKnots := ReadBoolean;
  212. FContinuity := TBSplineContinuity(ReadInteger);
  213. FRenderer := TParametricSurfaceRenderer(ReadInteger);
  214. FBasis := TParametricSurfaceBasis(ReadInteger);
  215. end
  216. else
  217. RaiseFilerException(archiveVersion);
  218. end;
  219. procedure TMOParametricSurface.BuildList(var mrci: TgxRenderContextInfo);
  220. var
  221. NurbsRenderer: GLUnurbsObj;
  222. begin
  223. case FRenderer of
  224. psrGLXcene:
  225. inherited;
  226. psrOpenVX:
  227. begin
  228. glPushAttrib(GL_ENABLE_BIT or GL_EVAL_BIT); // [sttEnable, sttEval]);
  229. // glEnable(GL_MAP2_TEXTURE_COORD_3);
  230. glEnable(GL_MAP2_VERTEX_3);
  231. glEnable(GL_AUTO_NORMAL);
  232. glEnable(GL_NORMALIZE);
  233. case FBasis of
  234. psbBezier:
  235. begin
  236. glMapGrid2f(FResolution, 1, 0, FResolution, 0, 1);
  237. glMap2f(GL_MAP2_TEXTURE_COORD_3, 0, 1, 3, FOrderU, 0, 1, 3 * FCountU, FOrderV, @FWeightedControlPoints.List[0]);
  238. glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, FCountU, 0, 1, 3 * FCountU, FCountV, @FWeightedControlPoints.List[0]);
  239. glEvalMesh2(GL_FILL, 0, FResolution, 0, FResolution);
  240. end;
  241. psbBSpline:
  242. begin
  243. NurbsRenderer := @gluNewNurbsRenderer;
  244. gluNurbsProperty(@NurbsRenderer, GLU_DISPLAY_MODE, GLU_FILL);
  245. gluNurbsProperty(@NurbsRenderer, GLU_SAMPLING_METHOD, GLU_DOMAIN_DISTANCE);
  246. gluNurbsProperty(@NurbsRenderer, GLU_U_STEP, FResolution);
  247. gluNurbsProperty(@NurbsRenderer, GLU_V_STEP, FResolution);
  248. gluBeginSurface(@NurbsRenderer);
  249. gluNurbsSurface(@NurbsRenderer, FKnotsU.Count, @FKnotsU.List[0], FKnotsV.Count, @FKnotsV.List[0], 3, FCountU * 3,
  250. @FWeightedControlPoints.List[0], FOrderU, FOrderV, GL_MAP2_TEXTURE_COORD_3);
  251. gluNurbsSurface(@NurbsRenderer, FKnotsU.Count, @FKnotsU.List[0], FKnotsV.Count, @FKnotsV.List[0], 3, FCountU * 3,
  252. @FWeightedControlPoints.List[0], FOrderU, FOrderV, GL_MAP2_VERTEX_3);
  253. gluEndSurface(@NurbsRenderer);
  254. gluDeleteNurbsRenderer(@NurbsRenderer);
  255. end;
  256. end;
  257. mrci.gxStates.PopAttrib;
  258. end;
  259. end;
  260. end;
  261. procedure TMOParametricSurface.Prepare;
  262. var
  263. i: Integer;
  264. begin
  265. // We want to clear everything but the parametric surface
  266. // data (control points and knot vectors).
  267. inherited Clear;
  268. // Apply weights to control points
  269. FWeightedControlPoints.Assign(FControlPoints);
  270. if FWeights.Count = FControlPoints.Count then
  271. for i := 0 to FWeightedControlPoints.Count - 1 do
  272. FWeightedControlPoints[i] := VectorScale(FWeightedControlPoints[i], FWeights[i]);
  273. case FRenderer of
  274. psrGLXcene:
  275. begin
  276. GenerateMesh;
  277. end;
  278. psrOpenVX:
  279. begin
  280. if (FAutoKnots) and (FBasis = psbBSpline) then
  281. begin
  282. GenerateKnotVector(FKnotsU, FCountU, FOrderU, FContinuity);
  283. GenerateKnotVector(FKnotsV, FCountV, FOrderV, FContinuity);
  284. end;
  285. end;
  286. end;
  287. end;
  288. procedure TMOParametricSurface.Clear;
  289. begin
  290. inherited;
  291. FControlPoints.Clear;
  292. FKnotsU.Clear;
  293. FKnotsV.Clear;
  294. FWeights.Clear;
  295. end;
  296. procedure TMOParametricSurface.GenerateMesh;
  297. var
  298. i, j: Integer;
  299. fg: TgxFGVertexIndexList;
  300. begin
  301. case FBasis of
  302. psbBezier:
  303. begin
  304. if FAutoKnots then
  305. begin
  306. FKnotsU.Clear;
  307. FKnotsV.Clear;
  308. end;
  309. GenerateBezierSurface(FResolution, FCountU, FCountV, FControlPoints, Vertices);
  310. end;
  311. psbBSpline:
  312. begin
  313. if FAutoKnots then
  314. begin
  315. GenerateKnotVector(FKnotsU, FCountU, FOrderU, FContinuity);
  316. GenerateKnotVector(FKnotsV, FCountV, FOrderV, FContinuity);
  317. end;
  318. GenerateBSplineSurface(FResolution, FOrderU, FOrderV, FCountU, FCountV, FKnotsU, FKnotsV, FControlPoints, Vertices);
  319. end;
  320. end;
  321. Mode := momFaceGroups;
  322. fg := TgxFGVertexIndexList.CreateOwned(FaceGroups);
  323. fg.Mode := fgmmTriangles;
  324. for j := 0 to FResolution - 2 do
  325. with fg do
  326. for i := 0 to FResolution - 2 do
  327. begin
  328. VertexIndices.Add(i + FResolution * j);
  329. VertexIndices.Add((i + 1) + FResolution * j);
  330. VertexIndices.Add(i + FResolution * (j + 1));
  331. VertexIndices.Add(i + FResolution * (j + 1));
  332. VertexIndices.Add((i + 1) + FResolution * j);
  333. VertexIndices.Add((i + 1) + FResolution * (j + 1));
  334. end;
  335. BuildNormals(fg.VertexIndices, momTriangles);
  336. end;
  337. procedure TMOParametricSurface.SetControlPoints(Value: TgxAffineVectorList);
  338. begin
  339. FControlPoints.Assign(Value);
  340. end;
  341. procedure TMOParametricSurface.SetKnotsU(Value: TgxSingleList);
  342. begin
  343. FKnotsU.Assign(Value);
  344. end;
  345. procedure TMOParametricSurface.SetKnotsV(Value: TgxSingleList);
  346. begin
  347. FKnotsV.Assign(Value);
  348. end;
  349. procedure TMOParametricSurface.SetWeights(Value: TgxSingleList);
  350. begin
  351. FWeights.Assign(Value);
  352. end;
  353. procedure TMOParametricSurface.SetRenderer(Value: TParametricSurfaceRenderer);
  354. begin
  355. if Value <> FRenderer then
  356. begin
  357. FRenderer := Value;
  358. Owner.Owner.StructureChanged;
  359. end;
  360. end;
  361. procedure TMOParametricSurface.SetBasis(Value: TParametricSurfaceBasis);
  362. begin
  363. if Value <> FBasis then
  364. begin
  365. FBasis := Value;
  366. Owner.Owner.StructureChanged;
  367. end;
  368. end;
  369. // ------------------
  370. // ------------------ TFGBezierSurface ------------------
  371. // ------------------
  372. constructor TFGBezierSurface.Create;
  373. begin
  374. inherited;
  375. FControlPointIndices := TgxIntegerList.Create;
  376. FTexCoordIndices := TgxIntegerList.Create;
  377. FTempControlPoints := TgxAffineVectorList.Create;
  378. FTempTexCoords := TgxAffineVectorList.Create;
  379. // Default values
  380. FCountU := 4;
  381. FCountV := 4;
  382. FResolution := 20;
  383. FMinU := 0;
  384. FMaxU := 1;
  385. FMinV := 0;
  386. FMaxV := 1;
  387. end;
  388. destructor TFGBezierSurface.Destroy;
  389. begin
  390. FControlPointIndices.Free;
  391. FTexCoordIndices.Free;
  392. FTempControlPoints.Free;
  393. FTempTexCoords.Free;
  394. inherited;
  395. end;
  396. procedure TFGBezierSurface.WriteToFiler(writer: TgxVirtualWriter);
  397. begin
  398. inherited WriteToFiler(writer);
  399. with writer do
  400. begin
  401. WriteInteger(0); // Archive Version 0
  402. FControlPointIndices.WriteToFiler(writer);
  403. FTexCoordIndices.WriteToFiler(writer);
  404. WriteInteger(FCountU);
  405. WriteInteger(FCountV);
  406. WriteInteger(FResolution);
  407. WriteFloat(FMinU);
  408. WriteFloat(FMaxU);
  409. WriteFloat(FMinV);
  410. WriteFloat(FMaxV);
  411. end;
  412. end;
  413. procedure TFGBezierSurface.ReadFromFiler(reader: TgxVirtualReader);
  414. var
  415. archiveVersion: Integer;
  416. begin
  417. inherited ReadFromFiler(reader);
  418. archiveVersion := reader.ReadInteger;
  419. if archiveVersion = 0 then
  420. with reader do
  421. begin
  422. FControlPointIndices.ReadFromFiler(reader);
  423. FTexCoordIndices.ReadFromFiler(reader);
  424. FCountU := ReadInteger;
  425. FCountV := ReadInteger;
  426. FResolution := ReadInteger;
  427. FMinU := ReadFloat;
  428. FMaxU := ReadFloat;
  429. FMinV := ReadFloat;
  430. FMaxV := ReadFloat;
  431. end
  432. else
  433. RaiseFilerException(archiveVersion);
  434. end;
  435. procedure TFGBezierSurface.BuildList(var mrci: TgxRenderContextInfo);
  436. begin
  437. if (FTempControlPoints.Count = 0) or (FTempControlPoints.Count <> FControlPointIndices.Count) then
  438. Exit;
  439. AttachOrDetachLightmap(mrci);
  440. mrci.gxStates.PushAttrib([sttEnable, sttEval]);
  441. mrci.gxStates.Enable(stAutoNormal);
  442. mrci.gxStates.Enable(stNormalize);
  443. glMapGrid2f(FResolution, MaxU, MinU, FResolution, MinV, MaxV);
  444. if FTempTexCoords.Count > 0 then
  445. begin
  446. glEnable(GL_MAP2_TEXTURE_COORD_3);
  447. glMap2f(GL_MAP2_TEXTURE_COORD_3, 0, 1, 3, FCountU, 0, 1, 3 * FCountU, FCountV, @FTempTexCoords.List[0]);
  448. end;
  449. glEnable(GL_MAP2_VERTEX_3);
  450. glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, FCountU, 0, 1, 3 * FCountU, FCountV, @FTempControlPoints.List[0]);
  451. glEvalMesh2(GL_FILL, 0, FResolution, 0, FResolution);
  452. mrci.gxStates.PopAttrib;
  453. end;
  454. procedure TFGBezierSurface.SetControlPointIndices(const Value: TgxIntegerList);
  455. begin
  456. FControlPointIndices.Assign(Value);
  457. end;
  458. procedure TFGBezierSurface.SetTexCoordIndices(const Value: TgxIntegerList);
  459. begin
  460. FTexCoordIndices.Assign(Value);
  461. end;
  462. procedure TFGBezierSurface.Prepare;
  463. var
  464. i, j: Integer;
  465. begin
  466. inherited;
  467. FTempControlPoints.Clear;
  468. FTempTexCoords.Clear;
  469. for j := 0 to CountV - 1 do
  470. for i := CountU - 1 downto 0 do
  471. begin
  472. FTempControlPoints.Add(Owner.Owner.Vertices[ControlPointIndices[i + CountU * j]]);
  473. if TexCoordIndices.Count = ControlPointIndices.Count then
  474. FTempTexCoords.Add(Owner.Owner.TexCoords[TexCoordIndices[i + CountU * j]]);
  475. end;
  476. end;
  477. end.