GLS.PipelineTransformation.pas 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. //
  2. // The graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.PipelineTransformation;
  5. (* Pipeline transformations *)
  6. interface
  7. {$I Scena.inc}
  8. uses
  9. Winapi.OpenGL,
  10. Scena.VectorTypes,
  11. Scena.VectorGeometry,
  12. Scena.Logger;
  13. const
  14. MAX_MATRIX_STACK_DEPTH = 128;
  15. type
  16. TGLPipelineTransformationState =
  17. (
  18. trsModelViewChanged,
  19. trsInvModelViewChanged,
  20. trsInvModelChanged,
  21. trsNormalModelChanged,
  22. trsViewProjChanged,
  23. trsFrustum
  24. );
  25. TGLPipelineTransformationStates = set of TGLPipelineTransformationState;
  26. const
  27. cAllStatesChanged = [trsModelViewChanged, trsInvModelViewChanged, trsInvModelChanged, trsViewProjChanged, trsNormalModelChanged, trsFrustum];
  28. type
  29. PTransformationRec = ^TTransformationRec;
  30. TTransformationRec = record
  31. FStates: TGLPipelineTransformationStates;
  32. FModelMatrix: TGLMatrix;
  33. FViewMatrix: TGLMatrix;
  34. FProjectionMatrix: TGLMatrix;
  35. FInvModelMatrix: TGLMatrix;
  36. FNormalModelMatrix: TAffineMatrix;
  37. FModelViewMatrix: TGLMatrix;
  38. FInvModelViewMatrix: TGLMatrix;
  39. FViewProjectionMatrix: TGLMatrix;
  40. FFrustum: TFrustum;
  41. end;
  42. type
  43. TOnMatricesPush = procedure() of object;
  44. TGLTransformation = class(TObject)
  45. private
  46. FStackPos: Integer;
  47. FStack: array of TTransformationRec;
  48. FLoadMatricesEnabled: Boolean;
  49. FOnPush: TOnMatricesPush;
  50. function GetModelMatrix: PGLMatrix; inline;
  51. function GetViewMatrix: PGLMatrix; inline;
  52. function GetProjectionMatrix: PGLMatrix; inline;
  53. function GetModelViewMatrix: PGLMatrix; inline;
  54. function GetInvModelViewMatrix: PGLMatrix; inline;
  55. function GetInvModelMatrix: PGLMatrix; inline;
  56. function GetNormalModelMatrix: PAffineMatrix; inline;
  57. function GetViewProjectionMatrix: PGLMatrix; inline;
  58. function GetFrustum: TFrustum; inline;
  59. protected
  60. procedure LoadModelViewMatrix; inline;
  61. procedure LoadProjectionMatrix; inline;
  62. procedure DoMatricesLoaded; inline;
  63. property OnPush: TOnMatricesPush read FOnPush write FOnPush;
  64. public
  65. constructor Create;
  66. procedure SetModelMatrix(const AMatrix: TGLMatrix); inline;
  67. procedure SetViewMatrix(const AMatrix: TGLMatrix); inline;
  68. procedure SetProjectionMatrix(const AMatrix: TGLMatrix); inline;
  69. procedure IdentityAll; inline;
  70. procedure Push(AValue: PTransformationRec); overload;
  71. procedure Push(); overload; inline;
  72. procedure Pop;
  73. procedure ReplaceFromStack;
  74. function StackTop: TTransformationRec; inline;
  75. property ModelMatrix: PGLMatrix read GetModelMatrix;
  76. property ViewMatrix: PGLMatrix read GetViewMatrix;
  77. property ProjectionMatrix: PGLMatrix read GetProjectionMatrix;
  78. property InvModelMatrix: PGLMatrix read GetInvModelMatrix;
  79. property ModelViewMatrix: PGLMatrix read GetModelViewMatrix;
  80. property NormalModelMatrix: PAffineMatrix read GetNormalModelMatrix;
  81. property InvModelViewMatrix: PGLMatrix read GetInvModelViewMatrix;
  82. property ViewProjectionMatrix: PGLMatrix read GetViewProjectionMatrix;
  83. property Frustum: TFrustum read GetFrustum;
  84. property LoadMatricesEnabled: Boolean read FLoadMatricesEnabled write FLoadMatricesEnabled;
  85. end;
  86. //=====================================================================
  87. implementation
  88. //=====================================================================
  89. constructor TGLTransformation.Create;
  90. begin
  91. FStackPos := 0;
  92. SetLength(FStack, MAX_MATRIX_STACK_DEPTH);
  93. IdentityAll;
  94. end;
  95. procedure TGLTransformation.LoadProjectionMatrix;
  96. begin
  97. glMatrixMode(GL_PROJECTION);
  98. glLoadMatrixf(@FStack[FStackPos].FProjectionMatrix);
  99. glMatrixMode(GL_MODELVIEW);
  100. end;
  101. function TGLTransformation.GetModelViewMatrix: PGLMatrix;
  102. begin
  103. if trsModelViewChanged in FStack[FStackPos].FStates then
  104. begin
  105. FStack[FStackPos].FModelViewMatrix :=
  106. MatrixMultiply(FStack[FStackPos].FModelMatrix, FStack[FStackPos].FViewMatrix);
  107. Exclude(FStack[FStackPos].FStates, trsModelViewChanged);
  108. end;
  109. Result := @FStack[FStackPos].FModelViewMatrix;
  110. end;
  111. procedure TGLTransformation.LoadModelViewMatrix;
  112. begin
  113. glLoadMatrixf(PGLFloat(GetModelViewMatrix));
  114. end;
  115. procedure TGLTransformation.IdentityAll;
  116. begin
  117. with FStack[FStackPos] do
  118. begin
  119. FModelMatrix := IdentityHmgMatrix;
  120. FViewMatrix := IdentityHmgMatrix;
  121. FProjectionMatrix := IdentityHmgMatrix;
  122. FStates := cAllStatesChanged;
  123. end;
  124. if LoadMatricesEnabled then
  125. begin
  126. LoadModelViewMatrix;
  127. LoadProjectionMatrix;
  128. end;
  129. end;
  130. procedure TGLTransformation.DoMatricesLoaded;
  131. begin
  132. if Assigned(FOnPush) then
  133. FOnPush();
  134. end;
  135. procedure TGLTransformation.Push;
  136. var
  137. prevPos: Integer;
  138. begin
  139. prevPos := FStackPos;
  140. Inc(FStackPos);
  141. FStack[FStackPos] := FStack[prevPos];
  142. end;
  143. procedure TGLTransformation.Push(AValue: PTransformationRec);
  144. var
  145. prevPos: Integer;
  146. begin
  147. {$IFDEF USE_LOGGING}
  148. if FStackPos > MAX_MATRIX_STACK_DEPTH then
  149. begin
  150. GLSLogger.LogWarningFmt('Transformation stack overflow, more then %d values',
  151. [MAX_MATRIX_STACK_DEPTH]);
  152. end;
  153. {$ENDIF}
  154. prevPos := FStackPos;
  155. Inc(FStackPos);
  156. if Assigned(AValue) then
  157. begin
  158. FStack[FStackPos] := AValue^;
  159. if LoadMatricesEnabled then
  160. begin
  161. LoadModelViewMatrix;
  162. LoadProjectionMatrix;
  163. end;
  164. DoMatricesLoaded;
  165. end
  166. else
  167. FStack[FStackPos] := FStack[prevPos];
  168. end;
  169. procedure TGLTransformation.Pop;
  170. begin
  171. {$IFDEF USE_LOGGING}
  172. if FStackPos = 0 then
  173. begin
  174. GLSLogger.LogError('Transformation stack underflow');
  175. exit;
  176. end;
  177. {$ENDIF}
  178. Dec(FStackPos);
  179. if LoadMatricesEnabled then
  180. begin
  181. LoadModelViewMatrix;
  182. LoadProjectionMatrix;
  183. end;
  184. end;
  185. procedure TGLTransformation.ReplaceFromStack;
  186. var
  187. prevPos: Integer;
  188. begin
  189. {$IFDEF USE_LOGGING}
  190. if FStackPos = 0 then
  191. begin
  192. GLSLogger.LogError('Transformation stack underflow');
  193. exit;
  194. end;
  195. {$ENDIF}
  196. prevPos := FStackPos - 1;
  197. FStack[FStackPos].FModelMatrix := FStack[prevPos].FModelMatrix;
  198. FStack[FStackPos].FViewMatrix:= FStack[prevPos].FViewMatrix;
  199. FStack[FStackPos].FProjectionMatrix:= FStack[prevPos].FProjectionMatrix;
  200. FStack[FStackPos].FStates := FStack[prevPos].FStates;
  201. if LoadMatricesEnabled then
  202. begin
  203. LoadModelViewMatrix;
  204. LoadProjectionMatrix;
  205. end;
  206. end;
  207. function TGLTransformation.GetModelMatrix: PGLMatrix;
  208. begin
  209. Result := @FStack[FStackPos].FModelMatrix;
  210. end;
  211. function TGLTransformation.GetViewMatrix: PGLMatrix;
  212. begin
  213. Result := @FStack[FStackPos].FViewMatrix;
  214. end;
  215. function TGLTransformation.GetProjectionMatrix: PGLMatrix;
  216. begin
  217. Result := @FStack[FStackPos].FProjectionMatrix;
  218. end;
  219. procedure TGLTransformation.SetModelMatrix(const AMatrix: TGLMatrix);
  220. begin
  221. FStack[FStackPos].FModelMatrix := AMatrix;
  222. FStack[FStackPos].FStates := FStack[FStackPos].FStates +
  223. [trsModelViewChanged, trsInvModelViewChanged, trsInvModelChanged, trsNormalModelChanged];
  224. if LoadMatricesEnabled then
  225. LoadModelViewMatrix;
  226. end;
  227. procedure TGLTransformation.SetViewMatrix(const AMatrix: TGLMatrix);
  228. begin
  229. FStack[FStackPos].FViewMatrix:= AMatrix;
  230. FStack[FStackPos].FStates := FStack[FStackPos].FStates +
  231. [trsModelViewChanged, trsInvModelViewChanged, trsViewProjChanged, trsFrustum];
  232. if LoadMatricesEnabled then
  233. LoadModelViewMatrix;
  234. end;
  235. function TGLTransformation.StackTop: TTransformationRec;
  236. begin
  237. Result := FStack[FStackPos];
  238. end;
  239. procedure TGLTransformation.SetProjectionMatrix(const AMatrix: TGLMatrix);
  240. begin
  241. FStack[FStackPos].FProjectionMatrix := AMatrix;
  242. FStack[FStackPos].FStates := FStack[FStackPos].FStates +
  243. [trsViewProjChanged, trsFrustum];
  244. if LoadMatricesEnabled then
  245. LoadProjectionMatrix;
  246. end;
  247. function TGLTransformation.GetInvModelViewMatrix: PGLMatrix;
  248. begin
  249. if trsInvModelViewChanged in FStack[FStackPos].FStates then
  250. begin
  251. FStack[FStackPos].FInvModelViewMatrix := GetModelViewMatrix^;
  252. InvertMatrix(FStack[FStackPos].FInvModelViewMatrix);
  253. Exclude(FStack[FStackPos].FStates, trsInvModelViewChanged);
  254. end;
  255. Result := @FStack[FStackPos].FInvModelViewMatrix;
  256. end;
  257. function TGLTransformation.GetInvModelMatrix: PGLMatrix;
  258. begin
  259. if trsInvModelChanged in FStack[FStackPos].FStates then
  260. begin
  261. FStack[FStackPos].FInvModelMatrix := MatrixInvert(FStack[FStackPos].FModelMatrix);
  262. Exclude(FStack[FStackPos].FStates, trsInvModelChanged);
  263. end;
  264. Result := @FStack[FStackPos].FInvModelMatrix;
  265. end;
  266. function TGLTransformation.GetNormalModelMatrix: PAffineMatrix;
  267. var
  268. M: TGLMatrix;
  269. begin
  270. if trsNormalModelChanged in FStack[FStackPos].FStates then
  271. begin
  272. M := FStack[FStackPos].FModelMatrix;
  273. NormalizeMatrix(M);
  274. SetMatrix(FStack[FStackPos].FNormalModelMatrix, M);
  275. Exclude(FStack[FStackPos].FStates, trsNormalModelChanged);
  276. end;
  277. Result := @FStack[FStackPos].FNormalModelMatrix;
  278. end;
  279. function TGLTransformation.GetViewProjectionMatrix: PGLMatrix;
  280. begin
  281. if trsViewProjChanged in FStack[FStackPos].FStates then
  282. begin
  283. FStack[FStackPos].FViewProjectionMatrix :=
  284. MatrixMultiply(FStack[FStackPos].FViewMatrix, FStack[FStackPos].FProjectionMatrix);
  285. Exclude(FStack[FStackPos].FStates, trsViewProjChanged);
  286. end;
  287. Result := @FStack[FStackPos].FViewProjectionMatrix;
  288. end;
  289. function TGLTransformation.GetFrustum: TFrustum;
  290. begin
  291. if trsFrustum in FStack[FStackPos].FStates then
  292. begin
  293. FStack[FStackPos].FFrustum := ExtractFrustumFromModelViewProjection(GetViewProjectionMatrix^);
  294. Exclude(FStack[FStackPos].FStates, trsFrustum);
  295. end;
  296. Result := FStack[FStackPos].FFrustum;
  297. end;
  298. end.