Stage.PipelineTransform.pas 9.2 KB

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