GLFile3DS.pas 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. {
  5. 3DStudio 3DS vector file format implementation.
  6. }
  7. unit GLFile3DS;
  8. interface
  9. {$I GLScene.inc}
  10. uses
  11. System.Classes,
  12. System.SysUtils,
  13. System.Math,
  14. OpenGLTokens,
  15. GLStrings,
  16. GLScene,
  17. GLObjects,
  18. GLVectorFileObjects,
  19. GLTexture,
  20. GLApplicationFileIO,
  21. GLVectorGeometry,
  22. File3DS,
  23. File3DSTypes,
  24. GLContext,
  25. GLPersistentClasses,
  26. GLFile3DSSceneObjects,
  27. GLVectorTypes,
  28. GLVectorLists,
  29. GLRenderContextInfo,
  30. GLMaterial;
  31. type
  32. EGLFile3DS = class(Exception);
  33. { A record that holds all the information that is used during 3ds animation. }
  34. TGLFile3DSAnimationData = packed record
  35. ModelMatrix: TMatrix;
  36. Color: TVector; // Omni Light.
  37. TargetPos: TAffineVector; // Spot Light.
  38. SpotLightCutOff: Single;
  39. HotSpot: Single;
  40. Roll: Single;
  41. end;
  42. { An abstract class that describes how to interpolate animation keys. }
  43. TGLFile3DSAnimationKeys = class(TPersistentObject)
  44. private
  45. FNumKeys: Integer;
  46. FKeys: array of TKeyHeader3DS;
  47. procedure InterpolateFrame(var I: Integer; var w: real; const AFrame: real);
  48. protected
  49. function InterpolateValue(const AValues: array of Single; const AFrame: real): Single; overload;
  50. function InterpolateValue(const AValues: array of TAffineVector; const AFrame: real): TAffineVector; overload;
  51. function InterpolateValue(const AValues: array of TKFRotKey3DS; const AFrame: real): TMatrix; overload;
  52. public
  53. procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); virtual;
  54. procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); virtual; abstract;
  55. procedure Assign(Source: TPersistent); override;
  56. procedure WriteToFiler(Writer: TVirtualWriter); override;
  57. procedure ReadFromFiler(Reader: TVirtualReader); override;
  58. end;
  59. TGLFile3DSScaleAnimationKeys = class(TGLFile3DSAnimationKeys)
  60. private
  61. FScale: array of TAffineVector;
  62. public
  63. procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
  64. procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
  65. procedure Assign(Source: TPersistent); override;
  66. procedure WriteToFiler(Writer: TVirtualWriter); override;
  67. procedure ReadFromFiler(Reader: TVirtualReader); override;
  68. end;
  69. TGLFile3DSRotationAnimationKeys = class(TGLFile3DSAnimationKeys)
  70. private
  71. FRot: array of TKFRotKey3DS;
  72. public
  73. procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
  74. procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
  75. procedure Assign(Source: TPersistent); override;
  76. procedure WriteToFiler(Writer: TVirtualWriter); override;
  77. procedure ReadFromFiler(Reader: TVirtualReader); override;
  78. end;
  79. TGLFile3DSPositionAnimationKeys = class(TGLFile3DSAnimationKeys)
  80. private
  81. FPos: array of TAffineVector;
  82. public
  83. procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
  84. procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
  85. procedure Assign(Source: TPersistent); override;
  86. procedure WriteToFiler(Writer: TVirtualWriter); override;
  87. procedure ReadFromFiler(Reader: TVirtualReader); override;
  88. end;
  89. TGLFile3DSColorAnimationKeys = class(TGLFile3DSAnimationKeys)
  90. private
  91. FCol: array of TAffineVector;
  92. public
  93. procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
  94. procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
  95. procedure Assign(Source: TPersistent); override;
  96. procedure WriteToFiler(Writer: TVirtualWriter); override;
  97. procedure ReadFromFiler(Reader: TVirtualReader); override;
  98. end;
  99. TTGLFile3DSPositionAnimationKeys = class(TGLFile3DSAnimationKeys)
  100. private
  101. FTPos: array of TAffineVector;
  102. public
  103. procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
  104. procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
  105. procedure Assign(Source: TPersistent); override;
  106. procedure WriteToFiler(Writer: TVirtualWriter); override;
  107. procedure ReadFromFiler(Reader: TVirtualReader); override;
  108. end;
  109. TGLFile3DSSpotLightCutOffAnimationKeys = class(TGLFile3DSAnimationKeys)
  110. private
  111. FFall: array of Single;
  112. public
  113. procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
  114. procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
  115. procedure Assign(Source: TPersistent); override;
  116. procedure WriteToFiler(Writer: TVirtualWriter); override;
  117. procedure ReadFromFiler(Reader: TVirtualReader); override;
  118. end;
  119. TGLFile3DSLightHotSpotAnimationKeys = class(TGLFile3DSAnimationKeys)
  120. private
  121. FHot: array of Single;
  122. public
  123. procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
  124. procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
  125. procedure Assign(Source: TPersistent); override;
  126. procedure WriteToFiler(Writer: TVirtualWriter); override;
  127. procedure ReadFromFiler(Reader: TVirtualReader); override;
  128. end;
  129. TGLFile3DSRollAnimationKeys = class(TGLFile3DSAnimationKeys)
  130. private
  131. FRoll: array of Single;
  132. public
  133. procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
  134. procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
  135. procedure Assign(Source: TPersistent); override;
  136. procedure WriteToFiler(Writer: TVirtualWriter); override;
  137. procedure ReadFromFiler(Reader: TVirtualReader); override;
  138. end;
  139. TGLFile3DSAnimationKeyList = class(TPersistentObject)
  140. private
  141. FAnimKeysList: array of TGLFile3DSAnimationKeys;
  142. protected
  143. procedure ApplyAnimKeys(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
  144. public
  145. procedure AddKeys(const AItem: TGLFile3DSAnimationKeys);
  146. procedure ClearKeys;
  147. procedure Assign(Source: TPersistent); override;
  148. procedure WriteToFiler(Writer: TVirtualWriter); override;
  149. procedure ReadFromFiler(Reader: TVirtualReader); override;
  150. destructor Destroy; override;
  151. end;
  152. { Used only for serialization. There probably is a more efficient way to do it. }
  153. TGLFile3DSAnimKeysClassType = (ctScale, ctRot, ctPos, ctCol, ctTPos, ctFall, ctHot, ctRoll);
  154. { A 3ds-specific TGLMorphableMeshObject. }
  155. TGLFile3DSDummyObject = class(TGLMorphableMeshObject)
  156. private
  157. FAnimList: TGLFile3DSAnimationKeyList;
  158. FAnimData: Pointer;
  159. FRefTranf, FAnimTransf: TGLFile3DSAnimationData;
  160. FParent: TGLFile3DSDummyObject;
  161. FParentName: String64;
  162. FStatic: Boolean; // Static tag used in BuildList to not apply animation matrix
  163. public
  164. procedure LoadAnimation(const AData: Pointer); virtual;
  165. procedure SetFrame(const AFrame: real); virtual;
  166. procedure MorphTo(morphTargetIndex: Integer); override;
  167. procedure Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single); override;
  168. procedure GetExtents(out min, max: TAffineVector); override;
  169. function ExtractTriangles(texCoords: TAffineVectorList = nil; normals: TAffineVectorList = nil): TAffineVectorList;
  170. override;
  171. procedure WriteToFiler(Writer: TVirtualWriter); override;
  172. procedure ReadFromFiler(Reader: TVirtualReader); override;
  173. procedure Assign(Source: TPersistent); override;
  174. constructor Create; override;
  175. destructor Destroy; override;
  176. property AnimList: TGLFile3DSAnimationKeyList read FAnimList;
  177. property Parent: TGLFile3DSDummyObject read FParent write FParent;
  178. property RefrenceTransf: TGLFile3DSAnimationData read FRefTranf write FRefTranf;
  179. end;
  180. { A 3ds-specific mesh object. }
  181. TGLFile3DSMeshObject = class(TGLFile3DSDummyObject)
  182. public
  183. procedure LoadAnimation(const AData: Pointer); override;
  184. procedure BuildList(var ARci: TGLRenderContextInfo); override;
  185. end;
  186. { A 3ds-specific omni light. }
  187. TGLFile3DSOmniLightObject = class(TGLFile3DSDummyObject)
  188. private
  189. FLightSrc: TGLFile3DSLight;
  190. FLightSrcName: String64;
  191. public
  192. constructor Create; override;
  193. procedure LoadData(const AOwner: TGLBaseMesh; const AData: PLight3DS); virtual;
  194. procedure LoadAnimation(const AData: Pointer); override;
  195. procedure SetFrame(const AFrame: real); override;
  196. procedure Assign(Source: TPersistent); override;
  197. procedure WriteToFiler(Writer: TVirtualWriter); override;
  198. procedure ReadFromFiler(Reader: TVirtualReader); override;
  199. destructor Destroy; override;
  200. end;
  201. { TGLFile3DSSpotLightObject. A 3ds-specific spot light. }
  202. TGLFile3DSSpotLightObject = class(TGLFile3DSOmniLightObject)
  203. public
  204. procedure LoadData(const AOwner: TGLBaseMesh; const AData: PLight3DS); override;
  205. procedure LoadAnimation(const AData: Pointer); override;
  206. procedure SetFrame(const AFrame: real); override;
  207. end;
  208. { A 3ds-specific camera. }
  209. TGLFile3DSCameraObject = class(TGLFile3DSDummyObject)
  210. private
  211. FTargetObj: TGLDummyCube;
  212. FCameraSrc: TGLFile3DSCamera;
  213. FCameraSrcName: String64;
  214. public
  215. constructor Create; override;
  216. procedure LoadData(Owner: TGLBaseMesh; AData: PCamera3DS);
  217. procedure LoadAnimation(const AData: Pointer); override;
  218. procedure SetFrame(const AFrame: real); override;
  219. procedure WriteToFiler(Writer: TVirtualWriter); override;
  220. procedure ReadFromFiler(Reader: TVirtualReader); override;
  221. destructor Destroy; override;
  222. end;
  223. { The 3DStudio vector file.
  224. Uses an upgraded version if a 3DS import library by Mike Lischke.
  225. (http://www.lishcke-online.de). A 3DS file may contain material
  226. information and require textures when loading. }
  227. TGL3DSVectorFile = class(TGLVectorFile)
  228. public
  229. class function Capabilities: TGLDataFileCapabilities; override;
  230. procedure LoadFromStream(aStream: TStream); override;
  231. end;
  232. var
  233. { If enabled, advanced parameters will be loaded from a 3ds file
  234. (TextureScale, TextureOffset), but it might break backwards compatibility.
  235. If disabled, it won't break anything, but some parameters will not be
  236. loaded correctly from a 3ds file.
  237. Also there is a significant drop in FPS when this option is on
  238. (for unknown reasons), so it is off by default. }
  239. vGLFile3DS_UseTextureEx: Boolean = False;
  240. { If enabled, allows 3ds animation and fixes loading of some 3ds models,
  241. but has a few bugs:
  242. - TGLFreeForm.AutoCentering does now work correctly.
  243. - TMeshObject.vertices return values different from
  244. TMeshObject.ExtractTriangles()
  245. }
  246. vGLFile3DS_EnableAnimation: Boolean = False;
  247. { If enabled, a -90 degrees (-PI/2) rotation will occured on X Axis.
  248. By design 3dsmax has a Z Up-Axis, after the rotation the Up axis will
  249. be Y. (Note: you need vGLFile3DS_EnableAnimation = true)
  250. }
  251. vGLFile3DS_FixDefaultUpAxisY: Boolean = False;
  252. { If >= 0, then the vertices list will be updated with selected frame
  253. animation data. (Note: you need vGLFile3DS_EnableAnimation = true).
  254. Be aware that in that case animation will not be usable, it is made
  255. to be used with a static mesh like GLFreeForm.
  256. }
  257. vGLFile3DS_LoadedStaticFrame: Integer = -1;
  258. // ------------------------------------------------------------------
  259. implementation
  260. // ------------------------------------------------------------------
  261. const
  262. cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE = PI / 2;
  263. CGLFILE3DS_DEFAULT_FRAME = 0;
  264. function AnimKeysClassTypeToClass(const AAnimKeysClassType: TGLFile3DSAnimKeysClassType): TClass;
  265. begin
  266. case AAnimKeysClassType of
  267. ctScale: Result := TGLFile3DSScaleAnimationKeys;
  268. ctRot: Result := TGLFile3DSRotationAnimationKeys;
  269. ctPos: Result := TGLFile3DSPositionAnimationKeys;
  270. ctCol: Result := TGLFile3DSColorAnimationKeys;
  271. ctTPos: Result := TTGLFile3DSPositionAnimationKeys;
  272. ctFall: Result := TGLFile3DSSpotLightCutOffAnimationKeys;
  273. ctHot: Result := TGLFile3DSLightHotSpotAnimationKeys;
  274. ctRoll: Result := TGLFile3DSRollAnimationKeys;
  275. else
  276. begin
  277. Result := nil;
  278. Assert(False, strErrorEx + strUnknownType);
  279. end;
  280. end;
  281. end;
  282. function ClassToAnimKeysClassType(const AAnimKeysClass: TClass): TGLFile3DSAnimKeysClassType;
  283. begin
  284. if AAnimKeysClass.InheritsFrom(TGLFile3DSScaleAnimationKeys) then
  285. Result := ctScale
  286. else if AAnimKeysClass.InheritsFrom(TGLFile3DSRotationAnimationKeys) then
  287. Result := ctRot
  288. else if AAnimKeysClass.InheritsFrom(TGLFile3DSPositionAnimationKeys) then
  289. Result := ctPos
  290. else if AAnimKeysClass.InheritsFrom(TGLFile3DSColorAnimationKeys) then
  291. Result := ctCol
  292. else if AAnimKeysClass.InheritsFrom(TTGLFile3DSPositionAnimationKeys) then
  293. Result := ctTPos
  294. else if AAnimKeysClass.InheritsFrom(TGLFile3DSSpotLightCutOffAnimationKeys) then
  295. Result := ctFall
  296. else if AAnimKeysClass.InheritsFrom(TGLFile3DSLightHotSpotAnimationKeys) then
  297. Result := ctHot
  298. else if AAnimKeysClass.InheritsFrom(TGLFile3DSRollAnimationKeys) then
  299. Result := ctRoll
  300. else
  301. begin
  302. Result := ctScale;
  303. Assert(False, strErrorEx + strUnknownType);
  304. end;
  305. end;
  306. function MakeRotationQuaternion(const axis: TAffineVector; angle: Single): TQuaternion;
  307. var
  308. v: TVector;
  309. halfAngle, invAxisLengthMult: Single;
  310. begin
  311. halfAngle := (angle) / 2;
  312. invAxisLengthMult := 1 / VectorLength(axis) * sin(halfAngle);
  313. v.X := axis.X * invAxisLengthMult;
  314. v.Y := axis.Y * invAxisLengthMult;
  315. v.Z := axis.Z * invAxisLengthMult;
  316. v.W := cos(halfAngle);
  317. Result.ImagPart := AffineVectorMake(v);
  318. Result.RealPart := v.W;
  319. end;
  320. function QuaternionToRotateMatrix(const Quaternion: TQuaternion): TMatrix;
  321. var
  322. wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2: Single;
  323. quat: TVector;
  324. m: TMatrix;
  325. begin
  326. quat := VectorMake(Quaternion.ImagPart);
  327. quat.W := Quaternion.RealPart;
  328. x2 := quat.X + quat.X;
  329. y2 := quat.Y + quat.Y;
  330. z2 := quat.Z + quat.Z;
  331. xx := quat.X * x2;
  332. xy := quat.X * y2;
  333. xz := quat.X * z2;
  334. yy := quat.Y * y2;
  335. yz := quat.Y * z2;
  336. zz := quat.Z * z2;
  337. wx := quat.W * x2;
  338. wy := quat.W * y2;
  339. wz := quat.W * z2;
  340. m.X.X := 1.0 - (yy + zz);
  341. m.X.Y := xy - wz;
  342. m.X.Z := xz + wy;
  343. m.Y.X := xy + wz;
  344. m.Y.Y := 1.0 - (xx + zz);
  345. m.Y.Z := yz - wx;
  346. m.Z.X := xz - wy;
  347. m.Z.Y := yz + wx;
  348. m.Z.Z := 1.0 - (xx + yy);
  349. m.X.W := 0;
  350. m.Y.W := 0;
  351. m.Z.W := 0;
  352. m.W.X := 0;
  353. m.W.Y := 0;
  354. m.W.Z := 0;
  355. m.W.W := 1;
  356. Result := m;
  357. end;
  358. // ------------------
  359. // ------------------ Support classes ------------------
  360. // ------------------
  361. procedure TGLFile3DSAnimationKeys.InterpolateFrame(var I: Integer; var w: real; const AFrame: real);
  362. begin
  363. w := 1;
  364. I := 0;
  365. if FNumKeys > 1 then
  366. begin
  367. while (FNumKeys > I) and ((FKeys[I].Time) <= AFrame) do
  368. Inc(I);
  369. if (FNumKeys > I) and ((FKeys[I - 1].Time) <= AFrame) then
  370. w := (AFrame - FKeys[I - 1].Time) / (FKeys[I].Time - FKeys[I - 1].Time);
  371. // Don't allow keys to go our of range.
  372. if I = FNumKeys then
  373. I := FNumKeys - 1;
  374. end;
  375. end;
  376. function TGLFile3DSAnimationKeys.InterpolateValue(const AValues: array of Single; const AFrame: real): Single;
  377. var
  378. I: Integer;
  379. w: real;
  380. start, stop: Single;
  381. begin
  382. InterpolateFrame(I, w, AFrame);
  383. if I > 0 then
  384. start := AValues[I - 1]
  385. else
  386. start := 0;
  387. if FNumKeys > I then
  388. stop := AValues[I]
  389. else
  390. stop := 0;
  391. Result := Lerp(start, stop, w);
  392. end;
  393. function TGLFile3DSAnimationKeys.InterpolateValue(const AValues: array of TAffineVector; const AFrame: real): TAffineVector;
  394. var
  395. I: Integer;
  396. w: real;
  397. start, stop: TAffineVector;
  398. begin
  399. InterpolateFrame(I, w, AFrame);
  400. if I > 0 then
  401. start := AValues[I - 1]
  402. else
  403. start := NullVector;
  404. if FNumKeys > I then
  405. stop := AValues[I]
  406. else
  407. stop := NullVector;
  408. Result := VectorLerp(start, stop, w);
  409. end;
  410. function TGLFile3DSAnimationKeys.InterpolateValue(const AValues: array of TKFRotKey3DS; const AFrame: real): TMatrix;
  411. var
  412. I: Integer;
  413. w: real;
  414. begin
  415. Result := IdentityHmgMatrix;
  416. // First find the final matrix for this frame.
  417. I := 0;
  418. while (FNumKeys > I) and ((FKeys[I].Time) <= AFrame) do
  419. begin
  420. with AValues[I] do
  421. Result := MatrixMultiply(Result, CreateRotationMatrix(AffineVectorMake(X, Y, Z), angle));
  422. Inc(I);
  423. end;
  424. InterpolateFrame(I, w, AFrame);
  425. // Then interpolate this matrix
  426. if (FNumKeys > I) and ((FKeys[I].Time) > AFrame) and ((FKeys[I - 1].Time) < AFrame) then
  427. begin
  428. with AValues[I] do
  429. Result := MatrixMultiply(Result, CreateRotationMatrix(AffineVectorMake(X, Y, Z), AngleLerp(0, angle, w)));
  430. end;
  431. end;
  432. procedure TGLFile3DSAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
  433. var
  434. I: Integer;
  435. begin
  436. FNumKeys := ANumKeys;
  437. SetLength(FKeys, FNumKeys);
  438. for I := 0 to FNumKeys - 1 do
  439. FKeys[I] := Keys[I];
  440. end;
  441. procedure TGLFile3DSAnimationKeys.Assign(Source: TPersistent);
  442. var
  443. I: Integer;
  444. begin
  445. if Source is TGLFile3DSAnimationKeys then
  446. begin
  447. FNumKeys := TGLFile3DSAnimationKeys(Source).FNumKeys;
  448. SetLength(FKeys, FNumKeys);
  449. for I := 0 to FNumKeys - 1 do
  450. FKeys[I] := TGLFile3DSAnimationKeys(Source).FKeys[I];
  451. end
  452. else
  453. inherited Assign(Source);
  454. end;
  455. procedure TGLFile3DSAnimationKeys.WriteToFiler(Writer: TVirtualWriter);
  456. begin
  457. Writer.WriteInteger(FNumKeys);
  458. if FNumKeys > 0 then
  459. Writer.Write(FKeys[0], FNumKeys * SizeOf(TKeyHeader3DS));
  460. end;
  461. procedure TGLFile3DSAnimationKeys.ReadFromFiler(Reader: TVirtualReader);
  462. begin
  463. FNumKeys := Reader.ReadInteger;
  464. SetLength(FKeys, FNumKeys);
  465. if FNumKeys > 0 then
  466. Reader.Read(FKeys[0], FNumKeys * SizeOf(TKeyHeader3DS));
  467. end;
  468. procedure TGLFile3DSScaleAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
  469. var
  470. I: Integer;
  471. AffVect: TAffineVector;
  472. Sign: ShortInt;
  473. begin
  474. inherited;
  475. SetLength(FScale, FNumKeys);
  476. for I := 0 to FNumKeys - 1 do
  477. begin
  478. FScale[I] := TAffineVector(PPointList(AData)[I]);
  479. if vGLFile3DS_FixDefaultUpAxisY then
  480. begin
  481. AffVect := FScale[I];
  482. if (AffVect.X < 0) or (AffVect.Y < 0) or (AffVect.Z < 0) then
  483. Sign := -1
  484. else
  485. Sign := 1;
  486. AffVect := VectorRotateAroundX(AffVect, cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
  487. FScale[I].X := Sign * Abs(AffVect.X);
  488. FScale[I].Y := Sign * Abs(AffVect.Y);
  489. FScale[I].Z := Sign * Abs(AffVect.Z);
  490. end;
  491. end;
  492. end;
  493. procedure TGLFile3DSScaleAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
  494. begin
  495. if FNumKeys > 0 then
  496. DataTransf.ModelMatrix := MatrixMultiply(DataTransf.ModelMatrix, CreateScaleMatrix(InterpolateValue(FScale, AFrame)));
  497. end;
  498. procedure TGLFile3DSScaleAnimationKeys.Assign(Source: TPersistent);
  499. var
  500. I: Integer;
  501. begin
  502. inherited;
  503. SetLength(FScale, FNumKeys);
  504. for I := 0 to FNumKeys - 1 do
  505. FScale[I] := (Source as TGLFile3DSScaleAnimationKeys).FScale[I];
  506. end;
  507. procedure TGLFile3DSScaleAnimationKeys.WriteToFiler(Writer: TVirtualWriter);
  508. begin
  509. inherited;
  510. if FNumKeys > 0 then
  511. Writer.Write(FScale[0], FNumKeys * SizeOf(TPoint3DS));
  512. end;
  513. procedure TGLFile3DSScaleAnimationKeys.ReadFromFiler(Reader: TVirtualReader);
  514. begin
  515. inherited;
  516. SetLength(FScale, FNumKeys);
  517. if FNumKeys > 0 then
  518. Reader.Read(FScale[0], FNumKeys * SizeOf(TPoint3DS));
  519. end;
  520. procedure TGLFile3DSRotationAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
  521. var
  522. I: Integer;
  523. Rot: PKFRotKeyList;
  524. AffVect: TAffineVector;
  525. begin
  526. inherited;
  527. SetLength(FRot, FNumKeys);
  528. Rot := PKFRotKeyList(AData);
  529. for I := 0 to FNumKeys - 1 do
  530. begin
  531. // The initial values do not contain any turns, that's why we have to make one.
  532. if (Rot[I].X = 0) and (Rot[I].Y = 0) and (Rot[I].Z = 0) then
  533. Rot[I].X := 1;
  534. // One quartalion can't describe a big angle (>180), that's why we have to subtract it from 2*pi
  535. if Rot[I].Angle > pi then
  536. begin
  537. Rot[I].Angle := 2 * PI - Rot[I].Angle;
  538. Rot[I].X := -Rot[I].X;
  539. Rot[I].Y := -Rot[I].Y;
  540. Rot[I].Z := -Rot[I].Z;
  541. end;
  542. FRot[I] := Rot[I];
  543. if vGLFile3DS_FixDefaultUpAxisY then
  544. begin
  545. AffVect.X := FRot[I].X;
  546. AffVect.Y := FRot[I].Y;
  547. AffVect.Z := FRot[I].Z;
  548. AffVect := VectorRotateAroundX(AffVect, cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
  549. FRot[I].X := AffVect.X;
  550. FRot[I].Y := AffVect.Y;
  551. FRot[I].Z := AffVect.Z;
  552. end;
  553. end;
  554. end;
  555. procedure TGLFile3DSRotationAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
  556. begin
  557. if FNumKeys > 0 then
  558. DataTransf.ModelMatrix := MatrixMultiply(DataTransf.ModelMatrix, InterpolateValue(FRot, AFrame));
  559. end;
  560. procedure TGLFile3DSRotationAnimationKeys.Assign(Source: TPersistent);
  561. var
  562. I: Integer;
  563. begin
  564. inherited;
  565. SetLength(FRot, FNumKeys);
  566. for I := 0 to FNumKeys - 1 do
  567. FRot[I] := (Source as TGLFile3DSRotationAnimationKeys).FRot[I];
  568. end;
  569. procedure TGLFile3DSRotationAnimationKeys.WriteToFiler(Writer: TVirtualWriter);
  570. begin
  571. inherited;
  572. if FNumKeys > 0 then
  573. Writer.Write(FRot[0], FNumKeys * SizeOf(TKFRotKey3DS));
  574. end;
  575. procedure TGLFile3DSRotationAnimationKeys.ReadFromFiler(Reader: TVirtualReader);
  576. begin
  577. inherited;
  578. SetLength(FRot, FNumKeys);
  579. if FNumKeys > 0 then
  580. Reader.Read(FRot[0], FNumKeys * SizeOf(TKFRotKey3DS));
  581. end;
  582. procedure TGLFile3DSPositionAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
  583. var
  584. I: Integer;
  585. begin
  586. inherited;
  587. SetLength(FPos, FNumKeys);
  588. for I := 0 to FNumKeys - 1 do
  589. begin
  590. FPos[I] := TAffineVector(PPointList(AData)[I]);
  591. if vGLFile3DS_FixDefaultUpAxisY then
  592. begin
  593. FPos[I] := VectorRotateAroundX(FPos[I], cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
  594. end;
  595. end;
  596. end;
  597. procedure TGLFile3DSPositionAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
  598. begin
  599. if FNumKeys > 0 then
  600. DataTransf.ModelMatrix.V[3] :=
  601. VectorAdd(DataTransf.ModelMatrix.V[3], VectorMake(InterpolateValue(FPos, AFrame)));
  602. end;
  603. procedure TGLFile3DSPositionAnimationKeys.Assign(Source: TPersistent);
  604. var
  605. I: Integer;
  606. begin
  607. inherited;
  608. SetLength(FPos, FNumKeys);
  609. for I := 0 to FNumKeys - 1 do
  610. FPos[I] := (Source as TGLFile3DSPositionAnimationKeys).FPos[I];
  611. end;
  612. procedure TGLFile3DSPositionAnimationKeys.WriteToFiler(Writer: TVirtualWriter);
  613. begin
  614. inherited;
  615. if FNumKeys > 0 then
  616. Writer.Write(FPos[0], FNumKeys * SizeOf(TPoint3DS));
  617. end;
  618. procedure TGLFile3DSPositionAnimationKeys.ReadFromFiler(Reader: TVirtualReader);
  619. begin
  620. inherited;
  621. SetLength(FPos, FNumKeys);
  622. if FNumKeys > 0 then
  623. Reader.Read(FPos[0], FNumKeys * SizeOf(TPoint3DS));
  624. end;
  625. procedure TGLFile3DSColorAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
  626. var
  627. I: Integer;
  628. begin
  629. inherited;
  630. SetLength(FCol, FNumKeys);
  631. for I := 0 to FNumKeys - 1 do
  632. FCol[I] := TAffineVector(PFColorList(AData)[I]);
  633. end;
  634. procedure TGLFile3DSColorAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
  635. begin
  636. if FNumKeys > 0 then
  637. DataTransf.Color := VectorAdd(DataTransf.Color, VectorMake(InterpolateValue(FCol, AFrame)));
  638. end;
  639. procedure TGLFile3DSColorAnimationKeys.Assign(Source: TPersistent);
  640. var
  641. I: Integer;
  642. begin
  643. inherited;
  644. SetLength(FCol, FNumKeys);
  645. for I := 0 to FNumKeys - 1 do
  646. FCol[I] := (Source as TGLFile3DSColorAnimationKeys).FCol[I];
  647. end;
  648. procedure TGLFile3DSColorAnimationKeys.WriteToFiler(Writer: TVirtualWriter);
  649. begin
  650. inherited;
  651. if FNumKeys > 0 then
  652. Writer.Write(FCol[0], FNumKeys * SizeOf(TFColor3DS));
  653. end;
  654. procedure TGLFile3DSColorAnimationKeys.ReadFromFiler(Reader: TVirtualReader);
  655. begin
  656. inherited;
  657. SetLength(FCol, FNumKeys);
  658. if FNumKeys > 0 then
  659. Reader.Read(FCol[0], FNumKeys * SizeOf(TFColor3DS));
  660. end;
  661. procedure TTGLFile3DSPositionAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
  662. var
  663. I: Integer;
  664. begin
  665. inherited;
  666. SetLength(FTPos, FNumKeys);
  667. for I := 0 to FNumKeys - 1 do
  668. begin
  669. FTPos[I] := TAffineVector(PPointList(AData)[I]);
  670. if vGLFile3DS_FixDefaultUpAxisY then
  671. begin
  672. FTPos[I] := VectorRotateAroundX(FTPos[I], cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
  673. end;
  674. end;
  675. end;
  676. procedure TTGLFile3DSPositionAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
  677. begin
  678. if FNumKeys > 0 then
  679. DataTransf.TargetPos := VectorAdd(DataTransf.TargetPos, InterpolateValue(FTPos, AFrame));
  680. end;
  681. procedure TTGLFile3DSPositionAnimationKeys.Assign(Source: TPersistent);
  682. var
  683. I: Integer;
  684. begin
  685. inherited;
  686. SetLength(FTPos, FNumKeys);
  687. for I := 0 to FNumKeys - 1 do
  688. FTPos[I] := (Source as TTGLFile3DSPositionAnimationKeys).FTPos[I];
  689. end;
  690. procedure TTGLFile3DSPositionAnimationKeys.WriteToFiler(Writer: TVirtualWriter);
  691. begin
  692. inherited;
  693. if FNumKeys > 0 then
  694. Writer.Write(FTPos[0], FNumKeys * SizeOf(TPoint3DS));
  695. end;
  696. procedure TTGLFile3DSPositionAnimationKeys.ReadFromFiler(Reader: TVirtualReader);
  697. begin
  698. inherited;
  699. SetLength(FTPos, FNumKeys);
  700. if FNumKeys > 0 then
  701. Reader.Read(FTPos[0], FNumKeys * SizeOf(TPoint3DS));
  702. end;
  703. procedure TGLFile3DSSpotLightCutOffAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList;
  704. const AData: Pointer);
  705. var
  706. I: Integer;
  707. begin
  708. inherited;
  709. SetLength(FFall, FNumKeys);
  710. for I := 0 to FNumKeys - 1 do
  711. FFall[I] := PSingleList(AData)[I];
  712. end;
  713. procedure TGLFile3DSSpotLightCutOffAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
  714. begin
  715. if FNumKeys > 0 then
  716. DataTransf.SpotLightCutOff := DataTransf.SpotLightCutOff + InterpolateValue(FFall, AFrame);
  717. end;
  718. procedure TGLFile3DSSpotLightCutOffAnimationKeys.Assign(Source: TPersistent);
  719. var
  720. I: Integer;
  721. begin
  722. inherited;
  723. SetLength(FFall, FNumKeys);
  724. for I := 0 to FNumKeys - 1 do
  725. FFall[I] := (Source as TGLFile3DSSpotLightCutOffAnimationKeys).FFall[I];
  726. end;
  727. procedure TGLFile3DSSpotLightCutOffAnimationKeys.WriteToFiler(Writer: TVirtualWriter);
  728. begin
  729. inherited;
  730. if FNumKeys > 0 then
  731. Writer.Write(FFall[0], FNumKeys * SizeOf(Single));
  732. end;
  733. procedure TGLFile3DSSpotLightCutOffAnimationKeys.ReadFromFiler(Reader: TVirtualReader);
  734. begin
  735. inherited;
  736. SetLength(FFall, FNumKeys);
  737. if FNumKeys > 0 then
  738. Reader.Read(FFall[0], FNumKeys * SizeOf(Single));
  739. end;
  740. procedure TGLFile3DSLightHotSpotAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList;
  741. const AData: Pointer);
  742. var
  743. I: Integer;
  744. begin
  745. inherited;
  746. SetLength(FHot, FNumKeys);
  747. for I := 0 to FNumKeys - 1 do
  748. FHot[I] := PSingleList(AData)[I];
  749. end;
  750. procedure TGLFile3DSLightHotSpotAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
  751. begin
  752. if FNumKeys > 0 then
  753. DataTransf.HotSpot := DataTransf.HotSpot + InterpolateValue(FHot, AFrame);
  754. end;
  755. procedure TGLFile3DSLightHotSpotAnimationKeys.Assign(Source: TPersistent);
  756. var
  757. I: Integer;
  758. begin
  759. inherited;
  760. SetLength(FHot, FNumKeys);
  761. for I := 0 to FNumKeys - 1 do
  762. FHot[I] := (Source as TGLFile3DSLightHotSpotAnimationKeys).FHot[I];
  763. end;
  764. procedure TGLFile3DSLightHotSpotAnimationKeys.WriteToFiler(Writer: TVirtualWriter);
  765. begin
  766. inherited;
  767. if FNumKeys > 0 then
  768. Writer.Write(FHot[0], FNumKeys * SizeOf(Single));
  769. end;
  770. procedure TGLFile3DSLightHotSpotAnimationKeys.ReadFromFiler(Reader: TVirtualReader);
  771. begin
  772. inherited;
  773. SetLength(FHot, FNumKeys);
  774. if FNumKeys > 0 then
  775. Reader.Read(FHot[0], FNumKeys * SizeOf(Single));
  776. end;
  777. procedure TGLFile3DSRollAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
  778. var
  779. I: Integer;
  780. begin
  781. inherited;
  782. SetLength(FRoll, FNumKeys);
  783. for I := 0 to FNumKeys - 1 do
  784. FRoll[I] := PSingleList(AData)[I];
  785. end;
  786. procedure TGLFile3DSRollAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
  787. begin
  788. if FNumKeys > 0 then
  789. DataTransf.Roll := DataTransf.Roll + InterpolateValue(FRoll, AFrame);
  790. end;
  791. procedure TGLFile3DSRollAnimationKeys.Assign(Source: TPersistent);
  792. var
  793. I: Integer;
  794. begin
  795. inherited;
  796. SetLength(FRoll, FNumKeys);
  797. for I := 0 to FNumKeys - 1 do
  798. FRoll[I] := (Source as TGLFile3DSRollAnimationKeys).FRoll[I];
  799. end;
  800. procedure TGLFile3DSRollAnimationKeys.WriteToFiler(Writer: TVirtualWriter);
  801. begin
  802. inherited;
  803. if FNumKeys > 0 then
  804. Writer.Write(FRoll[0], FNumKeys * SizeOf(Single));
  805. end;
  806. procedure TGLFile3DSRollAnimationKeys.ReadFromFiler(Reader: TVirtualReader);
  807. begin
  808. inherited;
  809. SetLength(FRoll, FNumKeys);
  810. if FNumKeys > 0 then
  811. Reader.Read(FRoll[0], FNumKeys * SizeOf(Single));
  812. end;
  813. procedure TGLFile3DSAnimationKeyList.AddKeys(const AItem: TGLFile3DSAnimationKeys);
  814. var
  815. ind: Integer;
  816. begin
  817. if AItem = nil then
  818. Exit;
  819. ind := Length(FAnimKeysList);
  820. SetLength(FAnimKeysList, ind + 1);
  821. FAnimKeysList[ind] := AItem;
  822. end;
  823. procedure TGLFile3DSAnimationKeyList.ApplyAnimKeys(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
  824. var
  825. I: Integer;
  826. begin
  827. for I := 0 to Length(FAnimKeysList) - 1 do
  828. FAnimKeysList[I].Apply(DataTransf, AFrame);
  829. end;
  830. procedure TGLFile3DSAnimationKeyList.ClearKeys;
  831. var
  832. I: Integer;
  833. begin
  834. for I := 0 to Length(FAnimKeysList) - 1 do
  835. FAnimKeysList[I].Free;
  836. SetLength(FAnimKeysList, 0);
  837. end;
  838. procedure TGLFile3DSAnimationKeyList.Assign(Source: TPersistent);
  839. var
  840. I: Integer;
  841. item: TGLFile3DSAnimationKeys;
  842. begin
  843. if Source is TGLFile3DSAnimationKeyList then
  844. begin
  845. ClearKeys;
  846. for I := 0 to Length(TGLFile3DSAnimationKeyList(Source).FAnimKeysList) - 1 do
  847. begin
  848. item := (TGLFile3DSAnimationKeyList(Source).FAnimKeysList[I].ClassType.Create as TGLFile3DSAnimationKeys);
  849. item.Assign(TGLFile3DSAnimationKeyList(Source).FAnimKeysList[I]);
  850. AddKeys(item);
  851. end;
  852. end
  853. else
  854. inherited Assign(Source);
  855. end;
  856. procedure TGLFile3DSAnimationKeyList.WriteToFiler(Writer: TVirtualWriter);
  857. var
  858. I: Integer;
  859. Val: TGLFile3DSAnimKeysClassType;
  860. begin
  861. Writer.WriteInteger(Length(FAnimKeysList));
  862. for I := 0 to Length(FAnimKeysList) - 1 do
  863. begin
  864. Val := ClassToAnimKeysClassType(FAnimKeysList[I].ClassType);
  865. Writer.Write(Val, SizeOf(Val));
  866. FAnimKeysList[I].WriteToFiler(Writer);
  867. end;
  868. end;
  869. procedure TGLFile3DSAnimationKeyList.ReadFromFiler(Reader: TVirtualReader);
  870. var
  871. I, cnt: Integer;
  872. Val: TGLFile3DSAnimKeysClassType;
  873. begin
  874. ClearKeys;
  875. cnt := Reader.ReadInteger;
  876. SetLength(FAnimKeysList, cnt);
  877. for I := 0 to Length(FAnimKeysList) - 1 do
  878. begin
  879. Reader.Read(Val, SizeOf(Val));
  880. FAnimKeysList[I] := AnimKeysClassTypeToClass(Val).Create as TGLFile3DSAnimationKeys;
  881. FAnimKeysList[I].ReadFromFiler(Reader);
  882. end;
  883. end;
  884. destructor TGLFile3DSAnimationKeyList.Destroy;
  885. begin
  886. ClearKeys;
  887. inherited Destroy;
  888. end;
  889. constructor TGLFile3DSDummyObject.Create;
  890. begin
  891. inherited;
  892. FAnimList := TGLFile3DSAnimationKeyList.Create;
  893. FRefTranf.ModelMatrix := IdentityHmgMatrix;
  894. FAnimTransf.ModelMatrix := IdentityHmgMatrix;
  895. FStatic := False;
  896. end;
  897. procedure TGLFile3DSDummyObject.LoadAnimation(const AData: Pointer);
  898. begin
  899. FAnimList.ClearKeys;
  900. FAnimData := AData;
  901. end;
  902. procedure TGLFile3DSDummyObject.SetFrame(const AFrame: real);
  903. var
  904. p: TGLFile3DSDummyObject;
  905. lAnimationData: TGLFile3DSAnimationData;
  906. begin
  907. if not vGLFile3DS_EnableAnimation then
  908. Exit;
  909. if (FParentName <> '') then
  910. begin
  911. FParent := Owner.FindMeshByName(string(FParentName)) as TGLFile3DSDummyObject;
  912. FParentName := '';
  913. end;
  914. lAnimationData := FRefTranf;
  915. p := self;
  916. while p <> nil do
  917. begin
  918. p.FAnimList.ApplyAnimKeys(lAnimationData, AFrame);
  919. p := p.FParent;
  920. end;
  921. FAnimTransf := lAnimationData;
  922. end;
  923. procedure TGLFile3DSDummyObject.MorphTo(morphTargetIndex: Integer);
  924. begin
  925. SetFrame(morphTargetIndex);
  926. end;
  927. procedure TGLFile3DSDummyObject.Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single);
  928. begin
  929. if (Owner.Owner is TGLActor) and ((Owner.Owner as TGLActor).AnimationMode in [aamBounceBackward, aamLoopBackward]) then
  930. SetFrame(morphTargetIndex1 - lerpFactor)
  931. else
  932. SetFrame(morphTargetIndex1 + lerpFactor);
  933. end;
  934. procedure TGLFile3DSDummyObject.Assign(Source: TPersistent);
  935. begin
  936. inherited; // Assign all published properties here.
  937. if Source is TGLFile3DSDummyObject then
  938. begin
  939. FRefTranf := (Source as TGLFile3DSDummyObject).FRefTranf;
  940. FParent := (Source as TGLFile3DSDummyObject).FParent;
  941. FAnimList.Assign((Source as TGLFile3DSDummyObject).FAnimList);
  942. SetFrame(0);
  943. end;
  944. end;
  945. procedure TGLFile3DSDummyObject.GetExtents(out min, max: TAffineVector);
  946. begin
  947. inherited GetExtents(min, max);
  948. if not FStatic then
  949. begin
  950. if not IsInfinite(min.X) then
  951. min := VectorTransform(min, FAnimTransf.ModelMatrix);
  952. if not IsInfinite(max.X) then
  953. max := VectorTransform(max, FAnimTransf.ModelMatrix);
  954. end;
  955. end;
  956. function TGLFile3DSDummyObject.ExtractTriangles(texCoords, normals: TAffineVectorList): TAffineVectorList;
  957. var
  958. I: Integer;
  959. begin
  960. Result := inherited ExtractTriangles(texCoords, normals);
  961. if not FStatic then
  962. begin
  963. if (Result.Count <> 0) and not MatrixEquals(FAnimTransf.ModelMatrix, IdentityHmgMatrix) then
  964. for I := 0 to Result.Count - 1 do
  965. Result[I] := VectorTransform(Result[I], FAnimTransf.ModelMatrix);
  966. end;
  967. end;
  968. procedure TGLFile3DSDummyObject.WriteToFiler(Writer: TVirtualWriter);
  969. var
  970. str: string;
  971. begin
  972. inherited;
  973. Writer.Write(FRefTranf, SizeOf(FRefTranf));
  974. if FParent <> nil then
  975. str := Copy(FParent.Name, 1, 32)
  976. else
  977. str := 'nil';
  978. Writer.WriteString(str);
  979. FAnimList.WriteToFiler(Writer);
  980. end;
  981. procedure TGLFile3DSDummyObject.ReadFromFiler(Reader: TVirtualReader);
  982. begin
  983. inherited;
  984. Reader.Read(FRefTranf, SizeOf(FRefTranf));
  985. FParentName := String64(Copy(Reader.ReadString, 1, 64));
  986. if FParentName = 'nil' then
  987. FParentName := '';
  988. FAnimList.ReadFromFiler(Reader);
  989. end;
  990. destructor TGLFile3DSDummyObject.Destroy;
  991. begin
  992. FAnimList.Free;
  993. inherited;
  994. end;
  995. procedure TGLFile3DSMeshObject.LoadAnimation(const AData: Pointer);
  996. var
  997. aScale: TGLFile3DSScaleAnimationKeys;
  998. aRot: TGLFile3DSRotationAnimationKeys;
  999. aPos: TGLFile3DSPositionAnimationKeys;
  1000. Mat : TMatrix;
  1001. RotMat : TMatrix;
  1002. AffVect : TAffineVector;
  1003. begin
  1004. inherited;
  1005. with PKFMesh3DS(AData)^, FAnimList do
  1006. begin
  1007. aScale := TGLFile3DSScaleAnimationKeys.Create;
  1008. aScale.LoadData(NSKeys, SKeys, Scale);
  1009. AddKeys(aScale);
  1010. aRot := TGLFile3DSRotationAnimationKeys.Create;
  1011. aRot.LoadData(NRKeys, RKeys, Rot);
  1012. AddKeys(aRot);
  1013. aPos := TGLFile3DSPositionAnimationKeys.Create;
  1014. aPos.LoadData(NPKeys, PKeys, Pos);
  1015. AddKeys(aPos);
  1016. if ParentStr <> '' then
  1017. FParent := TGLFile3DSDummyObject(Owner.FindMeshByName(string(ParentStr)));
  1018. with FRefTranf do
  1019. begin
  1020. if vGLFile3DS_FixDefaultUpAxisY then
  1021. begin
  1022. RotMat := CreateRotationMatrixX(cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
  1023. InvertMatrix(RotMat);
  1024. Mat := ModelMatrix;
  1025. ModelMatrix := MatrixMultiply(Mat, RotMat);
  1026. AffVect.X := Pivot.X;
  1027. AffVect.Y := Pivot.Y;
  1028. AffVect.Z := Pivot.Z;
  1029. AffVect := VectorRotateAroundX(AffVect, cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
  1030. Pivot.X := AffVect.X;
  1031. Pivot.Y := AffVect.Y;
  1032. Pivot.Z := AffVect.Z;
  1033. end;
  1034. ModelMatrix.W.X := ModelMatrix.W.X - Pivot.X;
  1035. ModelMatrix.W.Y := ModelMatrix.W.Y - Pivot.Y;
  1036. ModelMatrix.W.Z := ModelMatrix.W.Z - Pivot.Z;
  1037. end;
  1038. end;
  1039. if vGLFile3DS_LoadedStaticFrame = -1 then
  1040. SetFrame(CGLFILE3DS_DEFAULT_FRAME)
  1041. else
  1042. SetFrame(vGLFile3DS_LoadedStaticFrame);
  1043. end;
  1044. procedure TGLFile3DSMeshObject.BuildList(var ARci: TGLRenderContextInfo);
  1045. begin
  1046. gl.PushMatrix;
  1047. if not FStatic then
  1048. gl.MultMatrixf(@FAnimTransf.ModelMatrix);
  1049. inherited;
  1050. gl.PopMatrix;
  1051. end;
  1052. constructor TGLFile3DSOmniLightObject.Create;
  1053. begin
  1054. inherited;
  1055. FLightSrc := TGLFile3DSLight.Create(nil);
  1056. end;
  1057. procedure TGLFile3DSOmniLightObject.LoadData(const AOwner: TGLBaseMesh; const AData: PLight3DS);
  1058. begin
  1059. FLightSrc.Parent := AOwner;
  1060. FLightSrc.LightStyle := lsOmni;
  1061. FLightSrc.Name := string(AData.NameStr);
  1062. Name := string(AData.NameStr);
  1063. FLightSrc.Position.SetPoint(PAffineVector(@AData.Pos)^);
  1064. FLightSrc.Diffuse.Color := VectorMake(AData.Color.R, AData.Color.G, AData.Color.B);
  1065. FLightSrc.Specular.Color := VectorMake(AData.Color.R, AData.Color.G, AData.Color.B);
  1066. FLightSrc.Diffuse.Color := VectorScale(FLightSrc.Diffuse.Color, AData.Multiplier);
  1067. FLightSrc.Shining := not AData.DLOff;
  1068. FLightSrc.Multipler := AData.Multiplier;
  1069. FLightSrc.ConstAttenuation := 1;
  1070. FLightSrc.LinearAttenuation := 0;
  1071. FLightSrc.QuadraticAttenuation := 0;
  1072. end;
  1073. procedure TGLFile3DSOmniLightObject.LoadAnimation(const AData: Pointer);
  1074. var
  1075. aPos: TGLFile3DSPositionAnimationKeys;
  1076. aCol: TGLFile3DSColorAnimationKeys;
  1077. begin
  1078. inherited;
  1079. with PKFOmni3DS(AData)^, FAnimList do
  1080. begin
  1081. aPos := TGLFile3DSPositionAnimationKeys.Create;
  1082. aPos.LoadData(NPKeys, PKeys, Pos);
  1083. AddKeys(aPos);
  1084. aCol := TGLFile3DSColorAnimationKeys.Create;
  1085. aCol.LoadData(NCKeys, CKeys, Color);
  1086. AddKeys(aCol);
  1087. if Parent <> '' then
  1088. FParent := TGLFile3DSDummyObject(Owner.FindMeshByName(string(Parent)));
  1089. end;
  1090. if vGLFile3DS_LoadedStaticFrame = -1 then
  1091. SetFrame(CGLFILE3DS_DEFAULT_FRAME)
  1092. else
  1093. SetFrame(vGLFile3DS_LoadedStaticFrame);
  1094. end;
  1095. procedure TGLFile3DSOmniLightObject.SetFrame(const AFrame: real);
  1096. var
  1097. obj: TComponent;
  1098. begin
  1099. if FLightSrcName <> '' then
  1100. begin
  1101. obj := Owner.Owner.FindChild(string(FLightSrcName), True);
  1102. if obj is TGLFile3DSLight then
  1103. begin
  1104. FLightSrc.Free;
  1105. FLightSrc := obj as TGLFile3DSLight;
  1106. end;
  1107. FLightSrcName := '';
  1108. end;
  1109. inherited;
  1110. FLightSrc.Position.SetPoint(FAnimTransf.ModelMatrix.V[3]);
  1111. FLightSrc.Diffuse.Color := FAnimTransf.Color;
  1112. end;
  1113. procedure TGLFile3DSOmniLightObject.Assign(Source: TPersistent);
  1114. begin
  1115. inherited;
  1116. if Source is TGLFile3DSOmniLightObject then
  1117. FLightSrc.Assign((Source as TGLFile3DSOmniLightObject).FLightSrc);
  1118. end;
  1119. procedure TGLFile3DSOmniLightObject.WriteToFiler(Writer: TVirtualWriter);
  1120. var
  1121. str: string;
  1122. begin
  1123. inherited;
  1124. if FLightSrc.Name = '' then
  1125. str := 'nil'
  1126. else
  1127. str := Copy(FLightSrc.Name, 1, 64);
  1128. Writer.WriteString(str);
  1129. end;
  1130. procedure TGLFile3DSOmniLightObject.ReadFromFiler(Reader: TVirtualReader);
  1131. begin
  1132. inherited;
  1133. FLightSrcName := String64(Copy(Reader.ReadString, 1, 64));
  1134. if FLightSrcName = 'nil' then
  1135. FLightSrcName := '';
  1136. end;
  1137. destructor TGLFile3DSOmniLightObject.Destroy;
  1138. begin
  1139. FLightSrc.Free;
  1140. inherited;
  1141. end;
  1142. procedure TGLFile3DSSpotLightObject.LoadData(const AOwner: TGLBaseMesh; const AData: PLight3DS);
  1143. begin
  1144. inherited;
  1145. FLightSrc.LightStyle := lsSpot;
  1146. FLightSrc.SpotTargetPos.SetPoint(TAffineVector(AData.Spot.Target));
  1147. FLightSrc.SpotCutOff := AData.Spot.FallOff / 2;
  1148. FLightSrc.HotSpot := AData.Spot.HotSpot / 2;
  1149. end;
  1150. procedure TGLFile3DSSpotLightObject.LoadAnimation(const AData: Pointer);
  1151. var
  1152. aTPos: TTGLFile3DSPositionAnimationKeys;
  1153. aFall: TGLFile3DSSpotLightCutOffAnimationKeys;
  1154. aHot: TGLFile3DSLightHotSpotAnimationKeys;
  1155. begin
  1156. inherited;
  1157. with PKFSpot3DS(AData)^, FAnimList do
  1158. begin
  1159. aTPos := TTGLFile3DSPositionAnimationKeys.Create;
  1160. aTPos.LoadData(NTKeys, TKeys, TPos);
  1161. AddKeys(aTPos);
  1162. aFall := TGLFile3DSSpotLightCutOffAnimationKeys.Create;
  1163. aFall.LoadData(NFKeys, FKeys, Fall);
  1164. AddKeys(aFall);
  1165. aHot := TGLFile3DSLightHotSpotAnimationKeys.Create;
  1166. aHot.LoadData(NHKeys, HKeys, Hot);
  1167. AddKeys(aHot);
  1168. if Parent <> '' then
  1169. FParent := TGLFile3DSDummyObject(Owner.FindMeshByName(string(Parent)));
  1170. end;
  1171. if vGLFile3DS_LoadedStaticFrame = -1 then
  1172. SetFrame(CGLFILE3DS_DEFAULT_FRAME)
  1173. else
  1174. SetFrame(vGLFile3DS_LoadedStaticFrame);
  1175. end;
  1176. procedure TGLFile3DSSpotLightObject.SetFrame(const AFrame: real);
  1177. begin
  1178. inherited;
  1179. FLightSrc.SpotTargetPos.SetPoint(FAnimTransf.TargetPos);
  1180. FLightSrc.SpotCutOff := FAnimTransf.SpotLightCutOff / 2;
  1181. FLightSrc.HotSpot := FAnimTransf.HotSpot / 2;
  1182. end;
  1183. constructor TGLFile3DSCameraObject.Create;
  1184. begin
  1185. inherited;
  1186. FCameraSrc := TGLFile3DSCamera.Create(nil);
  1187. FTargetObj := TGLDummyCube.Create(nil);
  1188. FCameraSrc.TargetObject := FTargetObj;
  1189. end;
  1190. procedure TGLFile3DSCameraObject.LoadData(Owner: TGLBaseMesh; AData: PCamera3DS);
  1191. begin
  1192. FCameraSrc.Parent := Owner;
  1193. FTargetObj.Parent := Owner;
  1194. FCameraSrc.Name := string(AData.NameStr);
  1195. Name := string(AData.NameStr);
  1196. FCameraSrc.Position.AsAffineVector := TAffineVector(AData.Position);
  1197. FTargetObj.Position.SetPoint(TAffineVector(AData.Target));
  1198. FCameraSrc.RollAngle := AData.Roll;
  1199. FCameraSrc.FocalLength := AData.FOV;
  1200. end;
  1201. procedure TGLFile3DSCameraObject.LoadAnimation(const AData: Pointer);
  1202. var
  1203. aPos: TGLFile3DSPositionAnimationKeys;
  1204. aRoll: TGLFile3DSRollAnimationKeys;
  1205. aTPos: TTGLFile3DSPositionAnimationKeys;
  1206. begin
  1207. inherited;
  1208. with PKFCamera3DS(AData)^, FAnimList do
  1209. begin
  1210. aPos := TGLFile3DSPositionAnimationKeys.Create;
  1211. aPos.LoadData(NPKeys, PKeys, Pos);
  1212. AddKeys(aPos);
  1213. aRoll := TGLFile3DSRollAnimationKeys.Create;
  1214. aRoll.LoadData(NRKeys, RKeys, Roll);
  1215. AddKeys(aRoll);
  1216. aTPos := TTGLFile3DSPositionAnimationKeys.Create;
  1217. aTPos.LoadData(NTKeys, TKeys, TPos);
  1218. AddKeys(aTPos);
  1219. end;
  1220. if vGLFile3DS_LoadedStaticFrame = -1 then
  1221. SetFrame(CGLFILE3DS_DEFAULT_FRAME)
  1222. else
  1223. SetFrame(vGLFile3DS_LoadedStaticFrame);
  1224. end;
  1225. procedure TGLFile3DSCameraObject.SetFrame(const AFrame: real);
  1226. var
  1227. obj: TComponent;
  1228. begin
  1229. inherited;
  1230. if FCameraSrcName <> '' then
  1231. begin
  1232. obj := Owner.Owner.FindChild(string(FCameraSrcName), True);
  1233. if obj is TGLFile3DSCamera then
  1234. begin
  1235. FCameraSrc.Free;
  1236. FCameraSrc := obj as TGLFile3DSCamera;
  1237. end;
  1238. FCameraSrcName := '';
  1239. end;
  1240. FCameraSrc.Position.SetPoint(FAnimTransf.ModelMatrix.W);
  1241. FCameraSrc.RollAngle := FAnimTransf.Roll;
  1242. FTargetObj.Position.SetPoint(FAnimTransf.TargetPos);
  1243. end;
  1244. procedure TGLFile3DSCameraObject.WriteToFiler(Writer: TVirtualWriter);
  1245. var
  1246. str: string;
  1247. begin
  1248. inherited;
  1249. if FCameraSrc.Name = '' then
  1250. str := 'nil'
  1251. else
  1252. str := Copy(FCameraSrc.Name, 1, 64);
  1253. Writer.WriteString(str);
  1254. end;
  1255. procedure TGLFile3DSCameraObject.ReadFromFiler(Reader: TVirtualReader);
  1256. begin
  1257. inherited;
  1258. FCameraSrcName := String64(Copy(Reader.ReadString, 1, 64));
  1259. if FCameraSrcName = 'nil' then
  1260. FCameraSrcName := '';
  1261. end;
  1262. destructor TGLFile3DSCameraObject.Destroy;
  1263. begin
  1264. FCameraSrc.Free;
  1265. FTargetObj.Free;
  1266. inherited;
  1267. end;
  1268. // ------------------
  1269. // ------------------ TGL3DSVectorFile ------------------
  1270. // ------------------
  1271. class function TGL3DSVectorFile.Capabilities: TGLDataFileCapabilities;
  1272. begin
  1273. Result := [dfcRead];
  1274. end;
  1275. procedure TGL3DSVectorFile.LoadFromStream(aStream: TStream);
  1276. type
  1277. TSmoothIndexEntry = array[0..31] of cardinal;
  1278. PSmoothIndexArray = ^TSmoothIndexArray;
  1279. TSmoothIndexArray = array[0..MaxInt shr 8] of TSmoothIndexEntry;
  1280. var
  1281. Marker: PByteArray;
  1282. CurrentVertexCount: Integer;
  1283. SmoothIndices: PSmoothIndexArray;
  1284. mesh: TGLFile3DSMeshObject;
  1285. hasLightmap: Boolean;
  1286. // --------------- local functions -------------------------------------------
  1287. function GetOrAllocateMaterial(materials: TMaterialList; const Name: string): string;
  1288. var
  1289. material: PMaterial3DS;
  1290. specColor: TVector;
  1291. matLib: TGLMaterialLibrary;
  1292. libMat, SecondMaterial: TGLLibMaterial;
  1293. begin
  1294. material := Materials.MaterialByName[Name];
  1295. Assert(Assigned(material));
  1296. if GetOwner is TGLBaseMesh then
  1297. begin
  1298. matLib := TGLBaseMesh(GetOwner).MaterialLibrary;
  1299. if Assigned(matLib) then
  1300. begin
  1301. Result := Name;
  1302. libMat := matLib.Materials.GetLibMaterialByName(Name);
  1303. if not Assigned(libMat) then
  1304. begin
  1305. libMat := matLib.Materials.Add;
  1306. libMat.Name := Name;
  1307. with libMat.Material.FrontProperties do
  1308. begin
  1309. Ambient.Color := VectorMake(material.Ambient.R, material.Ambient.G, material.Ambient.B, 1);
  1310. // Material transparency can be stored as a positive or negative value.
  1311. Diffuse.Color := VectorMake(material.Diffuse.R, material.Diffuse.G, material.Diffuse.B,
  1312. 1 - Abs(material.Transparency));
  1313. specColor := VectorMake(material.Specular.R, material.Specular.G, material.Specular.B, 1);
  1314. Specular.Color := VectorScale(specColor, material.ShinStrength);
  1315. Shininess := MaxInteger(0, Integer(round((material.Shininess) * 128)));
  1316. if material.Transparency <> 0 then
  1317. libMat.material.BlendingMode := bmTransparency;
  1318. end;
  1319. if Trim(string(material.Texture.Map.NameStr)) <> '' then
  1320. try
  1321. if vGLFile3DS_UseTextureEx then
  1322. with libMat.material.TextureEx.Add do
  1323. begin
  1324. Texture.Image.LoadFromFile(string(material.Texture.Map.NameStr));
  1325. Texture.Disabled := False;
  1326. Texture.TextureMode := tmModulate;
  1327. TextureIndex := 0;
  1328. with material.Texture.Map do
  1329. begin
  1330. TextureScale.SetPoint(UScale, VScale, 0);
  1331. TextureOffset.SetPoint((1 - frac(UOffset)) * UScale, (frac(VOffset)) * VScale, 0);
  1332. end;
  1333. end
  1334. else
  1335. with libMat.Material.Texture do
  1336. begin
  1337. Image.LoadFromFile(string(material.Texture.Map.NameStr));
  1338. Disabled := False;
  1339. TextureMode := tmModulate;
  1340. end
  1341. except
  1342. on E: ETexture do
  1343. begin
  1344. if not Owner.IgnoreMissingTextures then
  1345. raise EGLFile3DS.CreateFmt(str3DSMapNotFound, ['diffuse', E.Message, matLib.TexturePaths]);
  1346. end
  1347. else
  1348. raise;
  1349. end;
  1350. if Trim(string(material.Opacity.Map.NameStr)) <> '' then
  1351. try
  1352. if vGLFile3DS_UseTextureEx then
  1353. with libMat.Material.TextureEx.Add do
  1354. begin
  1355. libMat.Material.BlendingMode := bmTransparency;
  1356. Texture.ImageAlpha := tiaAlphaFromIntensity;
  1357. Texture.TextureMode := tmModulate;
  1358. Texture.Image.LoadFromFile(string(material.Opacity.Map.NameStr));
  1359. Texture.Disabled := False;
  1360. TextureIndex := 1;
  1361. with material.Opacity.Map do
  1362. begin
  1363. TextureScale.SetPoint(UScale, VScale, 0);
  1364. TextureOffset.SetPoint((1 - frac(UOffset)) * UScale, (frac(VOffset)) * VScale, 0);
  1365. end;
  1366. end
  1367. else
  1368. with libMat.Material.Texture do
  1369. begin
  1370. SecondMaterial := matLib.Materials.Add;
  1371. SecondMaterial.material.Texture.Image.LoadFromFile(string(material.Opacity.Map.NameStr));
  1372. SecondMaterial.Material.Texture.Disabled := False;
  1373. SecondMaterial.Material.Texture.ImageAlpha := tiaAlphaFromIntensity;
  1374. SecondMaterial.Material.Texture.TextureMode := tmModulate;
  1375. SecondMaterial.Name := string(material.Opacity.Map.NameStr);
  1376. LibMat.Texture2Name := SecondMaterial.Name;
  1377. Disabled := False;
  1378. end;
  1379. except
  1380. on E: ETexture do
  1381. begin
  1382. if not Owner.IgnoreMissingTextures then
  1383. raise EGLFile3DS.CreateFmt(str3DSMapNotFound, ['opacity', E.Message, matLib.TexturePaths]);
  1384. end
  1385. else
  1386. raise;
  1387. end;
  1388. if Trim(string(material.Bump.Map.NameStr)) <> '' then
  1389. try
  1390. if vGLFile3DS_UseTextureEx then
  1391. with libMat.Material.TextureEx.Add do
  1392. begin
  1393. Texture.Image.LoadFromFile(string(material.Bump.Map.NameStr));
  1394. Texture.Disabled := False;
  1395. Texture.TextureMode := tmModulate;
  1396. // You need a hight map for this parameter (like in 3d Max).
  1397. // Texture.TextureFormat := tfNormalMap;
  1398. TextureIndex := 2;
  1399. with material.Bump.Map do
  1400. begin
  1401. TextureScale.SetPoint(UScale, VScale, 0);
  1402. TextureOffset.SetPoint((1 - frac(UOffset)) * UScale, (frac(VOffset)) * VScale, 0);
  1403. end;
  1404. end
  1405. else
  1406. with libMat.Material.Texture do
  1407. begin
  1408. SecondMaterial := matLib.materials.Add;
  1409. SecondMaterial.material.Texture.Image.LoadFromFile(string(material.Bump.Map.NameStr));
  1410. SecondMaterial.material.Texture.Disabled := False;
  1411. SecondMaterial.material.Texture.ImageAlpha := tiaAlphaFromIntensity;
  1412. SecondMaterial.material.Texture.TextureMode := tmModulate;
  1413. SecondMaterial.Name := string(material.Opacity.Map.NameStr);
  1414. Disabled := False;
  1415. end;
  1416. except
  1417. on E: ETexture do
  1418. begin
  1419. if not Owner.IgnoreMissingTextures then
  1420. raise EGLFile3DS.CreateFmt(str3DSMapNotFound, ['bump', E.Message, matLib.TexturePaths]);
  1421. end
  1422. else
  1423. raise;
  1424. end;
  1425. end;
  1426. end
  1427. else
  1428. Result := '';
  1429. end
  1430. else
  1431. Result := '';
  1432. end;
  1433. function GetOrAllocateLightMap(materials: TMaterialList; const Name: string): Integer;
  1434. var
  1435. material: PMaterial3DS;
  1436. matLib: TGLMaterialLibrary;
  1437. libMat: TGLLibMaterial;
  1438. begin
  1439. Result := -1;
  1440. material := Materials.MaterialByName[Name];
  1441. Assert(Assigned(material));
  1442. if GetOwner is TGLBaseMesh then
  1443. begin
  1444. matLib := TGLBaseMesh(GetOwner).LightmapLibrary;
  1445. if Assigned(matLib) then
  1446. begin
  1447. if Trim(string(material.IllumMap.Map.NameStr)) <> '' then
  1448. begin
  1449. libMat := matLib.materials.GetLibMaterialByName(string(material.IllumMap.Map.NameStr));
  1450. if not Assigned(libMat) then
  1451. begin
  1452. libMat := matLib.Materials.Add;
  1453. libMat.Name := string(material.IllumMap.Map.NameStr);
  1454. try
  1455. with libMat.Material.Texture do
  1456. begin
  1457. Image.LoadFromFile(string(material.IllumMap.Map.NameStr));
  1458. Disabled := False;
  1459. TextureMode := tmModulate;
  1460. end;
  1461. except
  1462. on E: ETexture do
  1463. begin
  1464. if not Owner.IgnoreMissingTextures then
  1465. raise EGLFile3DS.CreateFmt(str3DSMapNotFound, ['light', E.Message, matLib.TexturePaths]);
  1466. end
  1467. else
  1468. raise;
  1469. end;
  1470. end;
  1471. Result := libMat.Index;
  1472. hasLightMap := True;
  1473. end;
  1474. end;
  1475. end;
  1476. end;
  1477. // ----------------------------------------------------------------------
  1478. function InvertMeshMatrix(Objects: TObjectList; const Name: string): TMatrix;
  1479. // constructs a 4x4 matrix from 3x4 local mesh matrix given by Name and
  1480. // inverts it so it can be used for the keyframer stuff
  1481. var
  1482. I, Index: Integer;
  1483. boolY: Boolean;
  1484. m: TMatrix;
  1485. v4: TVector;
  1486. factor: Single;
  1487. begin
  1488. with Objects do
  1489. begin
  1490. Index := -1;
  1491. for I := 0 to MeshCount - 1 do
  1492. if CompareText(string(Mesh[I].NameStr), Name) = 0 then
  1493. begin
  1494. Index := I;
  1495. Break;
  1496. end;
  1497. if Index > -1 then
  1498. begin
  1499. with Mesh[Index]^ do
  1500. begin
  1501. Result.X.X := LocMatrix[0];
  1502. Result.X.Y := LocMatrix[1];
  1503. Result.X.Z := LocMatrix[2];
  1504. Result.X.W := 0;
  1505. Result.Y.X := LocMatrix[3];
  1506. Result.Y.Y := LocMatrix[4];
  1507. Result.Y.Z := LocMatrix[5];
  1508. Result.Y.W := 0;
  1509. Result.Z.X := LocMatrix[6];
  1510. Result.Z.Y := LocMatrix[7];
  1511. Result.Z.Z := LocMatrix[8];
  1512. Result.Z.W := 0;
  1513. Result.W.X := LocMatrix[9];
  1514. Result.W.Y := LocMatrix[10];
  1515. Result.W.Z := LocMatrix[11];
  1516. Result.W.W := 1;
  1517. end;
  1518. InvertMatrix(Result);
  1519. // If the matrix is not normalized, ie the third column is not equal to the vector product of the first two columns,
  1520. // it means that it is necessary to turn to-pi around the axis Y.
  1521. m := Result;
  1522. v4 := m.W;
  1523. factor := VectorLength(m.X);
  1524. NormalizeMatrix(m);
  1525. ScaleMatrix(m, factor);
  1526. m.W := v4;
  1527. v4 := VectorAbs(VectorSubtract(Result.Z, m.Z));
  1528. boolY := (v4.X > abs(Result.Z.X)) and
  1529. (v4.Y > abs(Result.Z.Y)) and
  1530. (v4.Z > abs(Result.Z.Z));
  1531. if boolY then
  1532. Result := MatrixMultiply(Result, CreateRotationMatrix(AffineVectorMake(0, 1, 0), -PI));
  1533. end
  1534. else
  1535. Result := IdentityHmgMatrix;
  1536. end;
  1537. end;
  1538. // ----------------------------------------------------------------------
  1539. function IsVertexMarked(p: PByteArray; Index: word): Boolean; inline;
  1540. // tests the Index-th bit, returns True if set else False
  1541. var
  1542. mi: word;
  1543. begin
  1544. DivMod(index, 8, mi, index);
  1545. Result := (((p^[mi] shr Index) and 1) = 1);
  1546. end;
  1547. // ---------------------------------------------------------------------------
  1548. function MarkVertex(p: PByteArray; Index: word): Boolean; inline;
  1549. // sets the Index-th bit and return True if it was already set else False
  1550. var
  1551. mi: word;
  1552. begin
  1553. DivMod(index, 8, mi, index);
  1554. Result := (((p^[mi] shr Index) and 1) = 1);
  1555. if not(Result) then
  1556. p^[mi] := p^[mi] or (1 shl index);
  1557. end;
  1558. // ---------------------------------------------------------------------------
  1559. // Stores new vertex index (NewIndex) into the smooth index array of vertex ThisIndex
  1560. // using field SmoothingGroup, which must not be 0.
  1561. // For each vertex in the vertex array (also for duplicated vertices) an array of 32 cardinals
  1562. // is maintained (each for one possible smoothing group. If a vertex must be duplicated because
  1563. // it has no smoothing group or a different one then the index of the newly created vertex is
  1564. // stored in the SmoothIndices to avoid loosing the conjunction between not yet processed vertices
  1565. // and duplicated vertices.
  1566. // Note: Only one smoothing must be assigned per vertex. Some available models break this rule and
  1567. // have more than one group assigned to a face. To make the code fail safe the group ID
  1568. // is scanned for the lowest bit set.
  1569. procedure StoreSmoothIndex(ThisIndex, SmoothingGroup, NewIndex: cardinal; p: PSmoothIndexArray);
  1570. var
  1571. I: word;
  1572. begin
  1573. I := 0;
  1574. while SmoothingGroup and (1 shl I) = 0 do
  1575. Inc(I);
  1576. p^[ThisIndex, I] := NewIndex;
  1577. end;
  1578. // ---------------------------------------------------------------------------
  1579. function GetSmoothIndex(ThisIndex, SmoothingGroup: cardinal; p: PSmoothIndexArray): Integer; inline;
  1580. // Retrieves the vertex index for the given index and smoothing group.
  1581. // This redirection is necessary because a vertex might have been duplicated.
  1582. var
  1583. I: word;
  1584. begin
  1585. I := 0;
  1586. while SmoothingGroup and (1 shl I) = 0 do
  1587. Inc(I);
  1588. Result := Integer(p^[ThisIndex, I]);
  1589. end;
  1590. // ---------------------------------------------------------------------------
  1591. procedure DuplicateVertex(Index: Integer);
  1592. // extends the vector and normal array by one entry and duplicates the vertex AData given by Index
  1593. // the marker and texture arrays will be extended too, if necessary
  1594. begin
  1595. // enhance vertex array
  1596. with mesh.Vertices do
  1597. Add(Items[index]);
  1598. mesh.Normals.Add(NullVector);
  1599. // enhance smooth index array
  1600. ReallocMem(SmoothIndices, (CurrentVertexCount + 1) * SizeOf(TSmoothIndexEntry));
  1601. FillChar(SmoothIndices[CurrentVertexCount], SizeOf(TSmoothIndexEntry), $FF);
  1602. // enhance marker array
  1603. if (CurrentVertexCount div 8) <> ((CurrentVertexCount + 1) div 8) then
  1604. begin
  1605. ReallocMem(Marker, ((CurrentVertexCount + 1) div 8) + 1);
  1606. Marker[(CurrentVertexCount div 8) + 1] := 0;
  1607. end;
  1608. with mesh.texCoords do
  1609. if Count > 0 then
  1610. Add(Items[index]);
  1611. Inc(CurrentVertexCount);
  1612. end;
  1613. // ---------------------------------------------------------------------------
  1614. function FindMotionIndex(KeyFramer: TKeyFramer; const ObjectName: AnsiString): Integer;
  1615. // Looks through the motion list for the object "ObjectName" and returns its index
  1616. // or -1 if the name is not it the list
  1617. var
  1618. I: Integer;
  1619. begin
  1620. Result := -1;
  1621. with KeyFramer do
  1622. for I := 0 to MeshMotionCount - 1 do
  1623. if CompareText(string(MeshMotion[I].NameStr), string(ObjectName)) = 0 then
  1624. begin
  1625. Result := I;
  1626. Break;
  1627. end;
  1628. end;
  1629. // --------------- end local functions ---------------------------------------
  1630. var
  1631. CurrentMotionIndex, iMaterial, I, j, X: Integer;
  1632. aFaceGroup: TFGVertexIndexList;
  1633. Face, Vertex, TargetVertex: Integer;
  1634. SmoothingGroup: cardinal;
  1635. CurrentIndex: word;
  1636. Vector1, Vector2, Normal: TAffineVector;
  1637. standardNormalsOrientation: Boolean;
  1638. lights_mesh: TGLFile3DSOmniLightObject;
  1639. camera_mesh: TGLFile3DSCameraObject;
  1640. basemesh: TGLBaseMesh;
  1641. begin
  1642. with TFile3DS.Create do
  1643. try
  1644. LoadFromStream(aStream);
  1645. // determine front face winding
  1646. { TODO : better face winding }
  1647. standardNormalsOrientation := not(NormalsOrientation = mnoDefault);
  1648. for i := 0 to Objects.MeshCount - 1 do
  1649. with PMesh3DS(Objects.Mesh[I])^ do
  1650. begin
  1651. hasLightMap := False;
  1652. mesh := TGLFile3DSMeshObject.CreateOwned(Owner.MeshObjects);
  1653. mesh.Name := string(PMesh3DS(Objects.Mesh[I])^.NameStr);
  1654. //dummy targets
  1655. for x := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
  1656. TGLMeshMorphTarget.CreateOwned(mesh.MorphTargets);
  1657. with mesh do
  1658. begin
  1659. Mode := momFaceGroups;
  1660. // make a copy of the vertex data, this must always be available
  1661. Vertices.Capacity := NVertices;
  1662. Normals.AddNulls(NVertices);
  1663. if NTextVerts > 0 then
  1664. begin
  1665. TexCoords.Capacity := NVertices;
  1666. for j := 0 to NVertices - 1 do
  1667. begin
  1668. Vertices.Add(PAffineVector(@VertexArray[j])^);
  1669. TexCoords.Add(PTexPoint(@TextArray[j])^);
  1670. end;
  1671. end
  1672. else
  1673. begin
  1674. for j := 0 to NVertices - 1 do
  1675. Vertices.Add(PAffineVector(@VertexArray[j])^);
  1676. end;
  1677. end;
  1678. // allocate memory for the smoothindices and the marker array
  1679. CurrentVertexCount := NVertices;
  1680. Marker := AllocMem((NVertices div 8) + 1); // one bit for each vertex
  1681. GetMem(SmoothIndices, NVertices * SizeOf(TSmoothIndexEntry));
  1682. if SmoothArray = nil then
  1683. begin
  1684. // no smoothing groups to consider
  1685. for Face := 0 to NFaces - 1 do
  1686. with FaceArray^[Face] do
  1687. begin
  1688. // normal vector for the face
  1689. with mesh.Vertices do
  1690. begin
  1691. VectorSubtract(Items[V1], Items[V2], Vector1);
  1692. VectorSubtract(Items[V3], Items[V2], Vector2);
  1693. end;
  1694. if standardNormalsOrientation then
  1695. Normal := VectorCrossProduct(Vector1, Vector2)
  1696. else
  1697. Normal := VectorCrossProduct(Vector2, Vector1);
  1698. // go for each vertex in the current face
  1699. for Vertex := 0 to 2 do
  1700. begin
  1701. // copy current index for faster access
  1702. CurrentIndex := FaceRec[Vertex];
  1703. // already been touched?
  1704. if IsVertexMarked(Marker, CurrentIndex) and (CurrentVertexCount < High(FaceRec[Vertex])) then
  1705. begin
  1706. // already touched vertex must be duplicated
  1707. DuplicateVertex(CurrentIndex);
  1708. FaceRec[Vertex] := CurrentVertexCount - 1;
  1709. mesh.Normals[CurrentVertexCount - 1] := Normal;
  1710. end
  1711. else
  1712. begin
  1713. // not yet touched, so just store the normal
  1714. mesh.Normals[CurrentIndex] := Normal;
  1715. MarkVertex(Marker, CurrentIndex);
  1716. end;
  1717. end;
  1718. end;
  1719. end
  1720. else
  1721. begin
  1722. // smoothing groups are to be considered
  1723. for Face := 0 to NFaces - 1 do
  1724. with FaceArray^[Face] do
  1725. begin
  1726. // normal vector for the face
  1727. with mesh.Vertices do
  1728. begin
  1729. VectorSubtract(Items[V1], Items[V2], Vector1);
  1730. VectorSubtract(Items[V3], Items[V2], Vector2);
  1731. end;
  1732. if standardNormalsOrientation then
  1733. Normal := VectorCrossProduct(Vector1, Vector2)
  1734. else
  1735. Normal := VectorCrossProduct(Vector2, Vector1);
  1736. SmoothingGroup := SmoothArray^[Face];
  1737. // go for each vertex in the current face
  1738. for Vertex := 0 to 2 do
  1739. begin
  1740. // copy current index for faster access
  1741. CurrentIndex := FaceRec[Vertex];
  1742. // Has vertex already been touched?
  1743. if IsVertexMarked(Marker, CurrentIndex) then
  1744. begin
  1745. // check smoothing group
  1746. if (SmoothingGroup = 0) then
  1747. begin
  1748. if (CurrentVertexCount < High(FaceRec[Vertex])) then
  1749. begin
  1750. // no smoothing then just duplicate vertex
  1751. DuplicateVertex(CurrentIndex);
  1752. FaceRec[Vertex] := CurrentVertexCount - 1;
  1753. mesh.Normals[CurrentVertexCount - 1] := Normal;
  1754. // mark new vertex also as touched
  1755. MarkVertex(Marker, CurrentVertexCount - 1);
  1756. end;
  1757. end
  1758. else
  1759. begin
  1760. // this vertex must be smoothed, check if there's already
  1761. // a (duplicated) vertex for this smoothing group
  1762. TargetVertex := GetSmoothIndex(CurrentIndex, SmoothingGroup, SmoothIndices);
  1763. if (TargetVertex < 0) then
  1764. begin
  1765. if (CurrentVertexCount < High(FaceRec[Vertex])) then
  1766. begin
  1767. // vertex has not yet been duplicated for this smoothing
  1768. // group, so do it now
  1769. DuplicateVertex(CurrentIndex);
  1770. FaceRec[Vertex] := CurrentVertexCount - 1;
  1771. mesh.Normals[CurrentVertexCount - 1] := Normal;
  1772. StoreSmoothIndex(CurrentIndex, SmoothingGroup, CurrentVertexCount - 1, SmoothIndices);
  1773. StoreSmoothIndex(CurrentVertexCount - 1, SmoothingGroup, CurrentVertexCount - 1, SmoothIndices);
  1774. // mark new vertex also as touched
  1775. MarkVertex(Marker, CurrentVertexCount - 1);
  1776. end;
  1777. end
  1778. else
  1779. begin
  1780. // vertex has already been duplicated,
  1781. // so just add normal vector to other vertex...
  1782. mesh.Normals[TargetVertex] := VectorAdd(mesh.Normals[TargetVertex], Normal);
  1783. // ...and tell which new vertex has to be used from now on
  1784. FaceRec[Vertex] := TargetVertex;
  1785. end;
  1786. end;
  1787. end
  1788. else
  1789. begin
  1790. // vertex not yet touched, so just store the normal
  1791. mesh.Normals[CurrentIndex] := Normal;
  1792. // initialize smooth indices for this vertex
  1793. FillChar(SmoothIndices[CurrentIndex], SizeOf(TSmoothIndexEntry), $FF);
  1794. if SmoothingGroup <> 0 then
  1795. StoreSmoothIndex(CurrentIndex, SmoothingGroup, CurrentIndex, SmoothIndices);
  1796. MarkVertex(Marker, CurrentIndex);
  1797. end;
  1798. end;
  1799. end;
  1800. end;
  1801. FreeMem(Marker);
  1802. FreeMem(SmoothIndices);
  1803. Assert(mesh.Vertices.Count = CurrentVertexCount);
  1804. // and normalize the Normals array
  1805. mesh.Normals.Normalize;
  1806. // now go for each material group
  1807. // if there's no face to material assignment then just copy the
  1808. // face definitions and rely on the default texture of the scene object
  1809. if (NMats = 0) or (not vGLVectorFileObjectsAllocateMaterials) then
  1810. begin
  1811. aFaceGroup := TFGVertexIndexList.CreateOwned(mesh.FaceGroups);
  1812. with aFaceGroup do
  1813. begin
  1814. basemesh := TGLBaseMesh(Self.GetOwner);
  1815. if basemesh.MaterialLibrary <> nil then
  1816. MaterialName := basemesh.MaterialLibrary.Materials.Add.Name;
  1817. // copy the face list
  1818. for j := 0 to NFaces - 1 do
  1819. begin
  1820. Add(FaceArray[J].V1);
  1821. Add(FaceArray[J].V2);
  1822. Add(FaceArray[J].V3);
  1823. end;
  1824. end;
  1825. end
  1826. else
  1827. begin
  1828. for iMaterial := 0 to NMats - 1 do
  1829. begin
  1830. aFaceGroup := TFGVertexIndexList.CreateOwned(mesh.FaceGroups);
  1831. with aFaceGroup do
  1832. begin
  1833. MaterialName := GetOrAllocateMaterial(Materials, string(MatArray[iMaterial].NameStr));
  1834. LightMapIndex := GetOrAllocateLightMap(Materials, string(MatArray[iMaterial].NameStr));
  1835. // copy all vertices belonging to the current face into our index array,
  1836. // there won't be redundant vertices since this would mean a face has more than one
  1837. // material
  1838. // NFaces is the one from FaceGroup
  1839. with MatArray[iMaterial] do
  1840. for j := 0 to NFaces - 1 do
  1841. begin
  1842. Add(FaceArray[FaceIndex[J]].V1);
  1843. Add(FaceArray[FaceIndex[J]].V2);
  1844. Add(FaceArray[FaceIndex[J]].V3);
  1845. end;
  1846. end;
  1847. end;
  1848. end;
  1849. if hasLightMap then
  1850. for j := 0 to mesh.TexCoords.Count - 1 do
  1851. mesh.LightMapTexCoords.Add(mesh.TexCoords[j].X, mesh.TexCoords[j].Y);
  1852. end;
  1853. // Adding non-mesh objects (for example, dummies).
  1854. for I := 0 to KeyFramer.MeshMotionCount - 1 do
  1855. if (Owner.MeshObjects.FindMeshByName(string(KeyFramer.MeshMotion[I].NameStr)) = nil) then
  1856. begin
  1857. mesh := TGLFile3DSMeshObject.CreateOwned(Owner.MeshObjects);
  1858. mesh.Name := string(KeyFramer.MeshMotion[I].NameStr);
  1859. // dummy targets
  1860. for X := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
  1861. TGLMeshMorphTarget.CreateOwned(mesh.MorphTargets);
  1862. mesh.LoadAnimation(KeyFramer.MeshMotion[I]);
  1863. end;
  1864. for I := 0 to Objects.MeshCount - 1 do
  1865. with PMesh3DS(Objects.Mesh[I])^ do
  1866. begin
  1867. mesh := Owner.MeshObjects.FindMeshByName(string(NameStr)) as TGLFile3DSMeshObject;
  1868. with mesh, KeyFramer do
  1869. begin
  1870. CurrentMotionIndex := FindMotionIndex(KeyFramer, NameStr);
  1871. FRefTranf.ModelMatrix := InvertMeshMatrix(Objects, string(NameStr));
  1872. if MeshMotionCount > 0 then
  1873. LoadAnimation(MeshMotion[CurrentMotionIndex]);
  1874. end;
  1875. end;
  1876. // Lights Omni.
  1877. for I := 0 to Objects.OmniLightCount - 1 do
  1878. begin
  1879. lights_mesh := TGLFile3DSOmniLightObject.CreateOwned(Owner.MeshObjects);
  1880. // Dummy targets for it.
  1881. for X := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
  1882. TGLMeshMorphTarget.CreateOwned(lights_mesh.MorphTargets);
  1883. lights_mesh.LoadData(Owner, Objects.OmniLight[I]);
  1884. lights_mesh.LoadAnimation(KeyFramer.OmniLightMotion[I]);
  1885. end;
  1886. // Lights Spot.
  1887. for I := 0 to Objects.SpotLightCount - 1 do
  1888. begin
  1889. lights_mesh := TGLFile3DSSpotLightObject.CreateOwned(Owner.MeshObjects);
  1890. // Dummy targets for it.
  1891. for X := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
  1892. TGLMeshMorphTarget.CreateOwned(lights_mesh.MorphTargets);
  1893. lights_mesh.LoadData(Owner, Objects.SpotLight[I]);
  1894. lights_mesh.LoadAnimation(KeyFramer.SpotLightMotion[I]);
  1895. end;
  1896. // Camera Objects.
  1897. for I := 0 to Objects.CameraCount - 1 do
  1898. begin
  1899. camera_mesh := TGLFile3DSCameraObject.CreateOwned(Owner.MeshObjects);
  1900. // Dummy targets for it.
  1901. for X := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
  1902. TGLMeshMorphTarget.CreateOwned(camera_mesh.MorphTargets);
  1903. camera_mesh.LoadData(Owner, Objects.Camera[I]);
  1904. camera_mesh.LoadAnimation(KeyFramer.CameraMotion[I]);
  1905. end;
  1906. // Apply animation matrix to static data
  1907. if vGLFile3DS_LoadedStaticFrame >= 0 then
  1908. begin
  1909. for I := 0 to Owner.MeshObjects.Count - 1 do
  1910. begin
  1911. if Owner.MeshObjects[I] is TGLFile3DSMeshObject then
  1912. begin
  1913. mesh := Owner.MeshObjects[I] as TGLFile3DSMeshObject;
  1914. mesh.FStatic := True;
  1915. for j := 0 to mesh.Vertices.Count - 1 do
  1916. mesh.Vertices[j] := VectorTransform(mesh.Vertices[j], mesh.FAnimTransf.ModelMatrix);
  1917. end;
  1918. end;
  1919. end;
  1920. finally
  1921. Free;
  1922. end;
  1923. end;
  1924. // ------------------------------------------------------------------
  1925. initialization
  1926. // ------------------------------------------------------------------
  1927. RegisterClasses([TGLFile3DSDummyObject, TGLFile3DSMeshObject, TGLFile3DSOmniLightObject, TGLFile3DSSpotLightObject,
  1928. TGLFile3DSCameraObject]);
  1929. RegisterVectorFileFormat('3ds', '3D Studio files', TGL3DSVectorFile);
  1930. RegisterVectorFileFormat('prj', '3D Studio project files', TGL3DSVectorFile);
  1931. end.