FileLWObjects.pas 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. (*-------------------------------------------------------------------------------
  5. Unit Name: Lightwave
  6. Author: Brian Johns [email protected]
  7. Purpose: Lightwave object support unit for Delphi.
  8. Notes: For the Lightwave Object File Format documentation please refer to
  9. http://www.lightwave3d.com/developer.
  10. License: This unit is distributed under the Mozilla Public License.
  11. For license details, refer to http://www.mozilla.org
  12. Lightwave3D is a registered trademark of Newtek Incorporated.
  13. -------------------------------------------------------------------------------*)
  14. unit FileLWObjects;
  15. interface
  16. {$I GLScene.inc}
  17. uses
  18. System.Classes,
  19. System.SysUtils,
  20. System.Math,
  21. GLVectorGeometry;
  22. type
  23. TID4 = array[0..3] of AnsiChar;
  24. PID4 = ^TID4;
  25. TID4DynArray = array of TID4;
  26. const
  27. ID_NULL = '#0#0#0#0'; // NULL ID
  28. ID_LWSC: TID4 = 'LWSC'; // Lightwave scene file
  29. ID_FORM: TID4 = 'FORM'; // IFF Form
  30. ID_LWOB: TID4 = 'LWOB'; // Lightwave Object version 1.0 - 5.x
  31. ID_LWLO: TID4 = 'LWLO'; // Lightwave Layered Object
  32. ID_LAYR: TID4 = 'LAYR'; // LAYER
  33. ID_PNTS: TID4 = 'PNTS'; // Points chunk
  34. ID_SRFS: TID4 = 'SRFS'; // Surface Names chunk
  35. ID_POLS: TID4 = 'POLS'; // Polygons chunk
  36. ID_CRVS: TID4 = 'CRVS'; // Curves chunk
  37. ID_PCHS: TID4 = 'PCHS'; // Patches chunk
  38. ID_SURF: TID4 = 'SURF'; // Surfaces chunk
  39. ID_COLR: TID4 = 'COLR'; // Color chunk
  40. ID_FLAG: TID4 = 'FLAG'; // Surface Flags
  41. ID_LUMI: TID4 = 'LUMI'; // Luminosity
  42. ID_DIFF: TID4 = 'DIFF'; // Diffuse
  43. ID_SPEC: TID4 = 'SPEC'; // Specular
  44. ID_REFL: TID4 = 'REFL'; // Reflective
  45. ID_TRAN: TID4 = 'TRAN'; // Transparency
  46. ID_VLUM: TID4 = 'VLUM'; // Luminosity
  47. ID_VDIF: TID4 = 'VDIF'; // Diffuse
  48. ID_VSPC: TID4 = 'VSPC'; // Specularity
  49. ID_VRFL: TID4 = 'VRFL'; // Reflective
  50. ID_VTRN: TID4 = 'VTRN'; // Transparency
  51. ID_GLOS: TID4 = 'GLOS'; // Glossiness SmallInt
  52. ID_SIDE: TID4 = 'SIDE'; // Sidedness
  53. ID_RFLT: TID4 = 'RFLT'; // REFLECTION MODE (PRE 6.0)
  54. ID_RFOP: TID4 = 'RFOP'; // REFLECTION OPTIONS
  55. ID_RIMG: TID4 = 'RIMG'; // REFLECTION IMAGE
  56. ID_RSAN: TID4 = 'RSAN'; // REFLECTION MAP SEAM ANGLE
  57. ID_RIND: TID4 = 'RIND'; // REFRACTIVE INDEX
  58. ID_EDGE: TID4 = 'EDGE'; // EDGE TRANSPARENCY THRESHOLD
  59. ID_SMAN: TID4 = 'SMAN'; // SMOOTHING ANGLE RADIANS
  60. ID_ALPH: TID4 = 'ALPH'; // ALPHA MODE
  61. ID_CTEX: TID4 = 'CTEX'; // COLOR TEXTURE
  62. ID_DTEX: TID4 = 'DTEX'; // DIFFUSE TEXTURE
  63. ID_STEX: TID4 = 'STEX'; // SPECULAR TEXTURE
  64. ID_RTEX: TID4 = 'RTEX'; // REFLECTIION TEXTURE
  65. ID_TTEX: TID4 = 'TTEX'; // TRANSPARENCY TEXTURE
  66. ID_LTEX: TID4 = 'LTEX'; // LUMINANCE TEXTURE
  67. ID_BTEX: TID4 = 'BTEX'; // BUMP TEXTURE
  68. ID_TFLG: TID4 = 'TFLG'; // TEXTURE FLAGS
  69. ID_TSIZ: TID4 = 'TSIZ'; // TEXTURE SIZE
  70. ID_TCTR: TID4 = 'TCTR'; // TEXTURE CENTER
  71. ID_TFAL: TID4 = 'TFAL'; // TEXTURE FALLOFF
  72. ID_TVEL: TID4 = 'TVAL'; // TEXTURE VALUE
  73. ID_TREF: TID4 = 'TREF'; // TEXTURE REFERENCE
  74. ID_TCLR: TID4 = 'TCLR'; // TEXTURE COLOR
  75. ID_TVAL: TID4 = 'TVAL'; // TEXTURE VALUE
  76. ID_TAMP: TID4 = 'TAMP'; // TEXTURE AMPLITUDE
  77. ID_TFP0: TID4 = 'TFP0'; // TEXTURE PARAMETERS
  78. ID_TFP1: TID4 = 'TFP1'; //
  79. ID_TFP2: TID4 = 'TFP2'; //
  80. ID_TIP0: TID4 = 'TIP0'; //
  81. ID_TIP1: TID4 = 'TIP1'; //
  82. ID_TIP2: TID4 = 'TIP2'; //
  83. ID_TSP0: TID4 = 'TSP0'; //
  84. ID_TSP1: TID4 = 'TSP1'; //
  85. ID_TSP2: TID4 = 'TSP2'; //
  86. ID_TFRQ: TID4 = 'TFRQ'; //
  87. ID_TIMG: TID4 = 'TIMG'; // TEXTURE IMG
  88. ID_TALP: TID4 = 'TALP'; //
  89. ID_TWRP: TID4 = 'TWRP'; // TEXTURE WRAP
  90. ID_TAAS: TID4 = 'TAAS'; //
  91. ID_TOPC: TID4 = 'TOPC'; //
  92. ID_SHDR: TID4 = 'SHDR'; //
  93. ID_SDAT: TID4 = 'SDAT'; //
  94. ID_IMSQ: TID4 = 'IMSQ'; // IMAGE SEQUENCE
  95. ID_FLYR: TID4 = 'FLYR'; // FLYER SEQUENCE
  96. ID_IMCC: TID4 = 'IMCC'; //
  97. SURF_FLAG_LUMINOUS = 1;
  98. SURF_FLAG_OUTLINE = 2;
  99. SURF_FLAG_SMOOTHING = 4;
  100. SURF_FLAG_COLORHIGHLIGHTS = 8;
  101. SURF_FLAG_COLORFILTER = 16;
  102. SURF_FLAG_OPAQUEEDGE = 32;
  103. SURF_FLAG_TRANSPARENTEDGE = 64;
  104. SURF_FLAG_SHARPTERMINATOR = 128;
  105. SURF_FLAG_DOUBLESIDED = 256;
  106. SURF_FLAG_ADDITIVE = 512;
  107. SURF_FLAG_SHADOWALPHA = 1024;
  108. CURV_CONTINUITY_FIRST = 1;
  109. CURV_CONTINUITY_LAST = 2;
  110. IMSQ_FLAG_LOOP = 1;
  111. IMSQ_FLAG_INTERLACE = 2;
  112. ID_LWO2: TID4 = 'LWO2'; // OBJECT
  113. ID_VMAP: TID4 = 'VMAP'; // VERTEX MAP
  114. ID_TAGS: TID4 = 'TAGS'; // TAGS?
  115. ID_PTAG: TID4 = 'PTAG'; // POLYGON TAG MAP
  116. ID_VMAD: TID4 = 'VMAD'; // DISCONTINUOUS VERTEX MAP
  117. ID_ENVL: TID4 = 'ENVL'; // ENVELOPE
  118. ID_CLIP: TID4 = 'CLIP'; // CLIP
  119. ID_BBOX: TID4 = 'BBOX'; // BOUNDING BOX
  120. ID_DESC: TID4 = 'DESC'; // DESCRIPTION
  121. ID_TEXT: TID4 = 'TEXT'; // TEXT
  122. ID_ICON: TID4 = 'ICON'; // ICON
  123. ENVL_PRE: TID4 = 'PRE'#0; // PRE-BEHAVIOUR
  124. ENVL_POST: TID4 = 'POST'; // POST
  125. ENVL_KEY: TID4 = 'KEY'#0; // KEY
  126. ENVL_SPAN: TID4 = 'SPAN'; // SPAN
  127. ENVL_CHAN: TID4 = 'CHAN'; // CHAN
  128. ENVL_NAME: TID4 = 'NAME'; // NAME
  129. ID_STIL: TID4 = 'STIL'; // STILL IMAGE FILENAME
  130. ID_ISEQ: TID4 = 'ISEQ'; // IMAGE SEQUENCE
  131. ID_ANIM: TID4 = 'ANIM'; // PLUGIN ANIMATION
  132. ID_STCC: TID4 = 'STCC'; // COLOR CYCLING STILL
  133. ID_CONT: TID4 = 'CONT'; // CONTRAST
  134. ID_BRIT: TID4 = 'BRIT'; // BRIGHTNESS
  135. ID_SATR: TID4 = 'SATR'; // SATURATION
  136. ID_HUE: TID4 = 'HUE'#0; // HUE
  137. ID_GAMMA: TID4 = 'GAMM'; // GAMMA
  138. ID_NEGA: TID4 = 'NEGA'; // NEGATIVE IMAGE
  139. ID_IFLT: TID4 = 'IFLT'; // IMAGE PLUG-IN FILTER
  140. ID_PFLT: TID4 = 'PFLT'; // PIXEL PLUG-IN FILTER
  141. POLS_TYPE_FACE: TID4 = 'FACE'; // FACES
  142. POLS_TYPE_CURV: TID4 = 'CURV'; // CURVE
  143. POLS_TYPE_PTCH: TID4 = 'PTCH'; // PATCH
  144. POLS_TYPE_MBAL: TID4 = 'MBAL'; // METABALL
  145. POLS_TYPE_BONE: TID4 = 'BONE'; // SKELEGON?
  146. VMAP_TYPE_PICK: TID4 = 'PICK'; // SELECTION SET
  147. VMAP_TYPE_WGHT: TID4 = 'WGHT'; // WEIGHT MAP
  148. VMAP_TYPE_MNVW: TID4 = 'MNVW'; // SUBPATCH WEIGHT MAP
  149. VMAP_TYPE_TXUV: TID4 = 'TXUV'; // UV MAP
  150. VMAP_TYPE_RGB: TID4 = 'RGB'#0; // RGB MAP
  151. VMAP_TYPE_RGBA: TID4 = 'RGBA'; // RGBA MAP
  152. VMAP_TYPE_MORF: TID4 = 'MORF'; // MORPH MAP: RELATIVE VERTEX DISPLACEMENT
  153. VMAP_TYPE_SPOT: TID4 = 'SPOT'; // SPOT MAP: ABSOLUTE VERTEX POSITIONS
  154. PTAG_TYPE_SURF: TID4 = 'SURF'; // SURFACE
  155. PTAG_TYPE_PART: TID4 = 'PART'; // PARENT PART
  156. PTAG_TYPE_SMGP: TID4 = 'SMGP'; // SMOOTH GROUP
  157. PRE_POST_RESET = 0; // RESET
  158. PRE_POST_CONSTANT = 1; // CONSTANT
  159. PRE_POST_REPEAT = 2; // REPEAT
  160. PRE_POST_OSCILLATE = 3; // OSCILLATE
  161. PRE_POST_OFFSET = 4; // OFFSET REPEAT
  162. PRE_POST_LINEAR = 5; // LINEAR
  163. POLS_VCOUNT_MASK = $3FF;
  164. POLS_FLAGS_MASK = $FC00;
  165. SIDE_FRONT = 1;
  166. SIDE_BACK = 2;
  167. SIDE_FRONT_AND_BACK = SIDE_FRONT and SIDE_BACK;
  168. RFOP_BACKDROP = 0;
  169. RFOP_RAYTRACEANDBACKDROP = 1;
  170. RFOP_SPHERICALMAP = 2;
  171. RFOP_RAYTRACEANDSPHERICALMAP = 3;
  172. type
  173. TI1 = ShortInt;
  174. PI1 = ^TI1;
  175. TI2 = SmallInt;
  176. PI2 = ^TI2;
  177. TI4 = LongInt;
  178. PI4 = ^TI4;
  179. TU1 = Byte;
  180. PU1 = ^TU1;
  181. TU1DynArray = array of TU1;
  182. TU2 = Word;
  183. PU2 = ^TU2;
  184. TU2Array = array [0..65534] of TU2;
  185. PU2Array = ^TU2Array;
  186. TU2DynArray = array of TU2;
  187. TU4 = LongWord;
  188. PU4 = ^TU4;
  189. TU4Array = array [0..65534] of TU4;
  190. PU4Array = ^TU4Array;
  191. TU4DynArray = array of TU4;
  192. TF4 = Single;
  193. PF4 = ^TF4;
  194. TF4Array = array [0..65534] of TF4;
  195. PF4Array = ^TF4Array;
  196. TF4DynArray = array of TF4;
  197. TANG4 = TF4;
  198. PANG4 = ^TANG4;
  199. // TS0 = PAnsiChar;
  200. TVec12 = array[0..2] of TF4;
  201. PVec12 = ^TVec12;
  202. TVec12Array = array [0..65534] of TVec12;
  203. PVec12Array = ^TVec12Array;
  204. TVec12DynArray = array of TVec12;
  205. TColr12 = TVec12;
  206. PColr12 = ^TColr12;
  207. TColr12DynArray = array of TColr12;
  208. TColr4 = array[0..3] of TU1;
  209. PColr4 = ^TColr4;
  210. { Lightwave Chunk Struct - Used in TLWOReadCallback }
  211. PLWChunkRec = ^TLWChunkRec;
  212. TLWChunkRec = record
  213. id: TID4;
  214. size: TU4;
  215. data: Pointer;
  216. end;
  217. { Lightwave SubChunk Struct - Used in TLWOReadCallback }
  218. PLWSubChunkRec = ^TLWSubChunkRec;
  219. TLWSubChunkRec = record
  220. id: TID4;
  221. size: TU2;
  222. data: Pointer;
  223. end;
  224. TLWPolsInfo = record
  225. norm: TVec12;
  226. vnorms: TVec12DynArray;
  227. surfid: TU2;
  228. end;
  229. TLWPolsInfoDynArray = array of TLWPolsInfo;
  230. TLWPntsInfo = record
  231. npols: TU2;
  232. pols: TU2DynArray;
  233. end;
  234. TLWPntsInfoDynArray = array of TLWPntsInfo;
  235. TLWPolsDynArray = TU2DynArray;
  236. TLWPolyTagMapDynArray = TU2DynArray;
  237. TLWPolyTagMap = record
  238. poly: TU2;
  239. tag: TU2;
  240. end;
  241. PLWPolyTagMap = ^TLWPolyTagMap;
  242. { Value Map }
  243. TLWVertexMap = record
  244. vert: TU2;
  245. values: TF4DynArray;
  246. end;
  247. TLWVertexMapDynArray = array of TLWVertexMap;
  248. TLWChunkList = class;
  249. TLWParentChunk = class;
  250. TLWChunk = class (TPersistent)
  251. private
  252. FData: Pointer;
  253. FID: TID4;
  254. FSize: TU4;
  255. FParentChunk: TLWParentChunk;
  256. FOwner: TLWChunkList;
  257. function GetRootChunks: TLWChunkList;
  258. function GetIndex: Integer;
  259. protected
  260. procedure Clear; virtual;
  261. procedure LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  262. virtual;
  263. procedure Loaded; virtual;
  264. public
  265. destructor Destroy; override;
  266. class function GetID: TID4; virtual;
  267. procedure LoadFromStream(AStream: TStream); virtual;
  268. property Data: Pointer read FData;
  269. property ID: TID4 read FID;
  270. property Size: TU4 read FSize;
  271. { ParentChunk may be nil indicating this is a root chunk. ie. TLWLayr }
  272. property ParentChunk: TLWParentChunk read FParentChunk;
  273. property RootChunks: TLWChunkList read GetRootChunks;
  274. property Index: Integer read GetIndex;
  275. property Owner: TLWChunkList read FOwner;
  276. end;
  277. TLWChunkClass = class of TLWChunk;
  278. TLWSubChunk = class (TLWChunk)
  279. public
  280. procedure LoadFromStream(AStream: TStream); override;
  281. end;
  282. TLWChunkFind = procedure(AChunk: TLWChunk; Criteria: Pointer; var Found: boolean);
  283. TLWChunkList = class (TList)
  284. private
  285. FOwnsItems: Boolean;
  286. FOwner: TObject;
  287. function GetItem(Index: Integer): TLWChunk;
  288. protected
  289. procedure Loaded; virtual;
  290. public
  291. constructor Create(AOwnsItems: boolean; AOwner: TObject);
  292. destructor Destroy; override;
  293. function Add(AChunk: TLWChunk): Integer;
  294. procedure Clear; override;
  295. procedure Delete(Index: Integer);
  296. function FindChunk(ChunkFind: TLWChunkFind; Criteria: Pointer; StartIndex: Integer = 0): Integer;
  297. property Items[Index: Integer]: TLWChunk read GetItem; default;
  298. property OwnsItems: Boolean read FOwnsItems;
  299. property Owner: TObject read FOwner;
  300. end;
  301. TLWParentChunk = class (TLWChunk)
  302. private
  303. FItems: TLWChunkList;
  304. function GetItems: TLWChunkList;
  305. function GetFloatParam(Param: TID4): Single;
  306. function GetWordParam(Param: TID4): Word;
  307. function GetVec3Param(Param: TID4): TVec12;
  308. function GetLongParam(Param: TID4): LongWord;
  309. function GetVXParam(Param: TID4): Word;
  310. protected
  311. function GetParamAddr(Param: TID4): Pointer; virtual;
  312. procedure Clear; override;
  313. procedure Loaded; override;
  314. public
  315. property Items: TLWChunkList read GetItems;
  316. property ParamAddr[Param: TID4]: Pointer read GetParamAddr;
  317. property FloatParam[Param: TID4]: Single read GetFloatParam;
  318. property WordParam[Param: TID4]: Word read GetWordParam;
  319. property LongParam[Param: TID4]: LongWord read GetLongParam;
  320. property Vec3Param[Param: TID4]: TVec12 read GetVec3Param;
  321. property VXParam[Param: TID4]: Word read GetVXParam;
  322. end;
  323. TLWVMap = class;
  324. TLWPnts = class (TLWParentChunk)
  325. private
  326. FPnts: TVEC12DynArray;
  327. FPntsInfo: TLWPntsInfoDynArray;
  328. function GetPntsCount: LongWord;
  329. function AddPoly(PntIdx, PolyIdx: Integer): Integer;
  330. protected
  331. procedure Clear; override;
  332. procedure LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  333. override;
  334. public
  335. class function GetID: TID4; override;
  336. function GetVMap(VMapID: TID4; out VMap: TLWVMap): Boolean;
  337. property PntsCount: LongWord read GetPntsCount;
  338. property Pnts: TVEC12DynArray read FPnts;
  339. property PntsInfo: TLWPntsInfoDynArray read FPntsInfo;
  340. end;
  341. TLWPols = class (TLWParentChunk)
  342. private
  343. FPolsType: TID4;
  344. FPols: TLWPolsDynArray;
  345. FPolsInfo: TLWPolsInfoDynArray;
  346. FPolsCount: Integer;
  347. function GetPolsByIndex(AIndex: TU2): Integer;
  348. function GetIndiceCount: TU4;
  349. function GetIndice(AIndex: Integer): TU2;
  350. function GetPolsCount: Integer;
  351. procedure CalcPolsNormals;
  352. procedure CalcPntsNormals;
  353. protected
  354. procedure Clear; override;
  355. procedure LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  356. override;
  357. procedure Loaded; override;
  358. public
  359. class function GetID: TID4; override;
  360. function GetPolsByPntIdx(VertIdx: TU2; var VertPolys: TU2DynArray): Integer;
  361. property PolsByIndex[AIndex: TU2]: Integer read GetPolsByIndex;
  362. property IndiceCount: TU4 read GetIndiceCount;
  363. property Indices[AIndex: Integer]: TU2 read GetIndice;
  364. property PolsType: TID4 read FPolsType;
  365. property PolsCount: Integer read GetPolsCount;
  366. property PolsInfo: TLWPolsInfoDynArray read FPolsInfo;
  367. end;
  368. TLWVMap = class (TLWChunk)
  369. private
  370. FDimensions: TU2;
  371. FName: string;
  372. FValues: TLWVertexMapDynArray;
  373. FVMapType: TID4;
  374. function GetValue(AIndex: TU2): TLWVertexMap;
  375. function GetValueCount: Integer;
  376. protected
  377. procedure Clear; override;
  378. procedure LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  379. override;
  380. public
  381. class function GetID: TID4; override;
  382. property Dimensions: TU2 read FDimensions;
  383. property Name: string read FName;
  384. property Value[AIndex: TU2]: TLWVertexMap read GetValue;
  385. property ValueCount: Integer read GetValueCount;
  386. property VMapType: TID4 read FVMapType;
  387. end;
  388. TLWTags = class (TLWChunk)
  389. private
  390. FTags: TStrings;
  391. function GetTags: TStrings;
  392. protected
  393. procedure Clear; override;
  394. procedure LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  395. override;
  396. public
  397. destructor Destroy; override;
  398. class function GetID: TID4; override;
  399. function TagToName(Tag: TU2): string;
  400. property Tags: TStrings read GetTags;
  401. end;
  402. TLWSurf = class (TLWParentChunk)
  403. private
  404. FName: string;
  405. FSource: string;
  406. function GetSurfId: Integer;
  407. protected
  408. function GetParamAddr(Param: TID4): Pointer; override;
  409. procedure LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  410. override;
  411. public
  412. destructor Destroy; override;
  413. class function GetID: TID4; override;
  414. property SurfId: Integer read GetSurfId;
  415. property Name: string read FName;
  416. property Source: string read FSource;
  417. end;
  418. TLWLayr = class (TLWParentChunk)
  419. private
  420. FFlags: TU2;
  421. FName: string;
  422. FNumber: TU2;
  423. FParent: TU2;
  424. FPivot: TVec12;
  425. protected
  426. procedure LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  427. override;
  428. public
  429. destructor Destroy; override;
  430. class function GetID: TID4; override;
  431. property Flags: TU2 read FFlags;
  432. property Name: string read FName;
  433. property Number: TU2 read FNumber;
  434. property Parent: TU2 read FParent;
  435. property Pivot: TVec12 read FPivot;
  436. end;
  437. TLWPTag = class (TLWChunk)
  438. private
  439. FMapType: TID4;
  440. FTagMaps: TLWPolyTagMapDynArray;
  441. FTags: TU2DynArray;
  442. function AddTag(Value: TU2): Integer;
  443. function GetTag(AIndex: Integer): TU2;
  444. function GetTagCount: Integer;
  445. function GetTagMapCount: Integer;
  446. function GetTagMaps(AIndex: Integer): TLWPolyTagMap;
  447. procedure ValidateTagInfo;
  448. protected
  449. procedure Clear; override;
  450. procedure LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  451. override;
  452. public
  453. constructor Create;
  454. function GetPolsByTag(Tag: TU2; var PolyIndices: TU2DynArray): Integer;
  455. class function GetID: TID4; override;
  456. property MapType: TID4 read FMapType;
  457. property TagCount: Integer read GetTagCount;
  458. property TagMapCount: Integer read GetTagMapCount;
  459. property TagMaps[AIndex: Integer]: TLWPolyTagMap read GetTagMaps; default;
  460. property Tags[AIndex: Integer]: TU2 read GetTag;
  461. end;
  462. TLWObjectFile = class (TObject)
  463. private
  464. FChunks: TLWChunkList;
  465. FFileName: string;
  466. function GetChunks: TLWChunkList;
  467. function GetCount: Integer;
  468. function GetSurfaceByName(Index: string): TLWSurf;
  469. function GetSurfaceByTag(Index: TU2): TLWSurf;
  470. public
  471. constructor Create;
  472. destructor Destroy; override;
  473. function TagToName(Tag: TU2): string;
  474. procedure LoadFromFile(const AFilename: string);
  475. procedure LoadFromStream(AStream: TStream);
  476. property ChunkCount: Integer read GetCount;
  477. property Chunks: TLWChunkList read GetChunks;
  478. property FileName: string read FFileName;
  479. property SurfaceByName[Index: string]: TLWSurf read GetSurfaceByName;
  480. property SurfaceByTag[Index: TU2]: TLWSurf read GetSurfaceByTag;
  481. end;
  482. TLWClip = class(TLWParentChunk)
  483. private
  484. FClipIndex: TU4;
  485. protected
  486. procedure LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  487. override;
  488. public
  489. class function GetID: TID4; override;
  490. property ClipIndex: TU4 read FClipIndex;
  491. end;
  492. TLWContentNotify = procedure(Sender: TObject; var Content: string) of object;
  493. TLWContentDir = class
  494. private
  495. FSubDirs: TStrings;
  496. FRoot: string;
  497. function GetSubDirs: TStrings;
  498. procedure SetRoot(const Value: string);
  499. procedure SetSubDirs(const Value: TStrings);
  500. // function ContentSearch(AFilename: string): string;
  501. public
  502. destructor Destroy; override;
  503. function FindContent(AFilename: string): string;
  504. property Root: string read FRoot write SetRoot;
  505. property SubDirs: TStrings read GetSubDirs write SetSubDirs;
  506. end;
  507. TLWOReadCallback = procedure(Chunk: TLWChunkRec; Data: Pointer); cdecl;
  508. procedure RegisterChunkClass(ChunkClass: TLWChunkClass);
  509. function LoadLW0FromStream(Stream: TStream; ReadCallback: TLWOReadCallback; UserData: Pointer): LongWord; cdecl;
  510. function LoadLWOFromFile(const AFilename: string; ReadCallback: TLWOReadCallback; UserData: Pointer): LongWord;
  511. procedure ReadMotorolaNumber(Stream: TStream; Data: Pointer; ElementSize:
  512. Integer; Count: Integer = 1);
  513. function WriteMotorolaNumber(Stream: TStream; Data: Pointer; ElementSize:
  514. Integer; Count: Integer = 1): Integer;
  515. function ReadS0(Stream: TStream; out Str: string): Integer;
  516. procedure WriteS0(Stream: TStream; Data: string);
  517. procedure WriteU4AsVX(Stream:TStream; Data: Pointer; Count: Integer);
  518. function ReadVXAsU4(Stream: TStream; Data: Pointer; Count: Integer = 1): Integer;
  519. procedure ReverseByteOrder(ValueIn: Pointer; Size: Integer; Count: Integer = 1);
  520. function ToDosPath(const Path: string): string;
  521. function ToUnixPath(const Path: string): string;
  522. function ID4ToInt(const Id: TID4): Integer;
  523. // ChunkFind procedures
  524. procedure FindChunkById(AChunk: TLWChunk; Data: Pointer; var Found: boolean);
  525. procedure FindSurfaceByName(AChunk: TLWChunk; AName: Pointer; var Found: boolean);
  526. procedure FindSurfaceByTag(AChunk: TLWChunk; ATag: Pointer; var Found: boolean);
  527. procedure FindVMapByName(AChunk: TLWChunk; AName: Pointer; var Found: boolean);
  528. procedure FindClipByClipIndex(AChunk: TLWChunk; AIndex: Pointer; var Found: boolean);
  529. function GetContentDir: TLWContentDir;
  530. //--------------------------------------------------------------------
  531. //--------------------------------------------------------------------
  532. //--------------------------------------------------------------------
  533. implementation
  534. //--------------------------------------------------------------------
  535. //--------------------------------------------------------------------
  536. //--------------------------------------------------------------------
  537. uses
  538. GLApplicationFileIO;
  539. type
  540. PWord = ^Word;
  541. PLongWord = ^LongWord;
  542. var
  543. ChunkClasses: TList;
  544. ContentDir: TLWContentDir;
  545. function ToDosPath(const Path: string): string;
  546. var
  547. i: Integer;
  548. begin
  549. result := Path;
  550. for i := 1 to Length(result) do
  551. if result[i] = '/' then
  552. result[i] := '\';
  553. end;
  554. function ToUnixPath(const Path: string): string;
  555. var
  556. i: Integer;
  557. begin
  558. result := Path;
  559. for i := 1 to Length(result) do
  560. if result[i] = '\' then
  561. result[i] := '/';
  562. end;
  563. function GetContentDir: TLWContentDir;
  564. begin
  565. if ContentDir = nil then
  566. ContentDir := TLWContentDir.Create;
  567. result := ContentDir;
  568. end;
  569. procedure FindChunkById(AChunk: TLWChunk; Data: Pointer; var Found: boolean);
  570. begin
  571. if AChunk.FID = PID4(Data)^ then
  572. Found := true
  573. else
  574. Found := false;
  575. end;
  576. procedure FindClipByClipIndex(AChunk: TLWChunk; AIndex: Pointer; var Found: boolean);
  577. begin
  578. if (AChunk is TLWClip) and
  579. (TLWClip(AChunk).ClipIndex = PU2(AIndex)^) then
  580. Found := true;
  581. end;
  582. procedure FindSurfaceByName(AChunk: TLWChunk; AName: Pointer; var Found: boolean);
  583. begin
  584. if (AChunk is TLWSurf) and
  585. (TLWSurf(AChunk).Name = PString(AName)^) then
  586. Found := true;
  587. end;
  588. procedure FindSurfaceByTag(AChunk: TLWChunk; ATag: Pointer; var Found: boolean);
  589. begin
  590. if (AChunk is TLWSurf) and
  591. (TLWSurf(AChunk).SurfId = PU2(ATag)^) then
  592. Found := true;
  593. end;
  594. procedure FindVMapByName(AChunk: TLWChunk; AName: Pointer; var Found: boolean);
  595. begin
  596. if (AChunk is TLWVMap) and
  597. (TLWVMap(AChunk).Name = PString(AName)^) then
  598. Found := true;
  599. end;
  600. function VecAdd(v1,v2: TVec12):TVec12;
  601. begin
  602. result[0]:=v1[0]+v2[0];
  603. result[1]:=v1[1]+v2[1];
  604. result[2]:=v1[2]+v2[2];
  605. end;
  606. function VecSub(v1,v2: TVec12): TVec12;
  607. begin
  608. result[0]:=v1[0]-v2[0];
  609. result[1]:=v1[1]-v2[1];
  610. result[2]:=v1[2]-v2[2];
  611. end;
  612. function VecCross(v1,v2: TVec12): TVec12;
  613. begin
  614. result[0]:=v1[1]*v2[2]-v1[2]*v2[1];
  615. result[1]:=v1[2]*v2[0]-v1[0]*v2[2];
  616. result[2]:=v1[0]*v2[1]-v1[1]*v2[0];
  617. end;
  618. function VecDot(v1, v2: TVec12): TF4;
  619. begin
  620. result:=v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2];
  621. end;
  622. function VecNorm(v: TVec12) : TVec12;
  623. var
  624. mag: TF4;
  625. begin
  626. mag := Sqrt(VecDot(v,v));
  627. if mag >0 then mag := 1/mag;
  628. result[0]:=v[0]*mag;
  629. result[1]:=v[1]*mag;
  630. result[2]:=v[2]*mag;
  631. end;
  632. function CalcPlaneNormal(v1,v2,v3: TVec12): TVec12;
  633. var
  634. e1, e2: TVec12;
  635. begin
  636. e1:=VecSub(v2,v1);
  637. e2:=VecSub(v3,v1);
  638. result:=VecCross(e1,e2);
  639. result:=VecNorm(result);
  640. end;
  641. procedure FindSurfByName(Chunk: TLWChunk; var Found: boolean);
  642. begin
  643. end;
  644. {-----------------------------------------------------------------------------
  645. Procedure: GetChunkClasses
  646. Date: 08-Aug-2002
  647. Arguments: None
  648. Result: TClassList
  649. Singleton access for the chunk class list.
  650. -----------------------------------------------------------------------------}
  651. function GetChunkClasses: TList;
  652. begin
  653. if ChunkClasses=nil then
  654. ChunkClasses:=TList.Create;
  655. result:=ChunkClasses;
  656. end;
  657. procedure UnRegisterChunkClasses;
  658. var
  659. i: Integer;
  660. begin
  661. with GetChunkClasses do
  662. for i:=0 to Count-1 do
  663. UnregisterClass(TPersistentClass(Items[i]));
  664. end;
  665. {-----------------------------------------------------------------------------
  666. Procedure: RegisterChunkClass
  667. Date: 08-Aug-2002
  668. Arguments: ChunkClass: TLWChunkClass
  669. Result: None
  670. Adds a user defined chunk class to the chunk class list.
  671. -----------------------------------------------------------------------------}
  672. procedure RegisterChunkClass(ChunkClass: TLWChunkClass);
  673. begin
  674. GetChunkClasses.Add(ChunkClass);
  675. // if FindClass(ChunkClass.ClassName) <> nil then
  676. // UnRegisterClass(ChunkClass);
  677. // RegisterClass(ChunkClass);
  678. end;
  679. {-----------------------------------------------------------------------------
  680. Procedure: GetChunkClass
  681. Date: 08-Aug-2002
  682. Arguments: ChunkID: TID4
  683. Result: TLWChunkClass
  684. Returns the chunk class associated with ChunkID.
  685. -----------------------------------------------------------------------------}
  686. function GetChunkClass(ChunkID: TID4; ADefault: TLWChunkClass): TLWChunkClass;
  687. var
  688. i: Integer;
  689. begin
  690. if ADefault = nil then
  691. result:=TLWChunk
  692. else
  693. result:=ADefault;
  694. for i:=0 to ChunkClasses.Count-1 do
  695. begin
  696. if TLWChunkClass(ChunkClasses.Items[i]).GetID=ChunkID then
  697. begin
  698. result:=TLWChunkClass(ChunkClasses.Items[i]);
  699. Exit;
  700. end;
  701. end;
  702. end;
  703. {-----------------------------------------------------------------------------
  704. Procedure: Tokenize
  705. Date: 08-Aug-2002
  706. Arguments: const Src: string; Delimiter: Char; Dst: TStrings
  707. Result: None
  708. Breaks up a string into TStrings items when the Delimiter character is
  709. encountered.
  710. -----------------------------------------------------------------------------}
  711. procedure Tokenize(const Src: string; Delimiter: Char; Dst: TStrings);
  712. var
  713. i,L,SL: Integer;
  714. SubStr: string;
  715. begin
  716. if Dst=nil then Exit;
  717. L:=Length(Src);
  718. if (L=0) or (Dst=nil) then Exit;
  719. SubStr:='';
  720. for i:=1 to L do
  721. begin
  722. if (Src[i]<>Delimiter) then SubStr:=SubStr+Src[i] else
  723. begin
  724. SL:=Length(SubStr);
  725. if SL>0 then
  726. begin
  727. Dst.Add(SubStr);
  728. SubStr:='';
  729. end;
  730. end;
  731. end;
  732. if Length(SubStr)>0 then Dst.Add(SubStr);
  733. end;
  734. {-----------------------------------------------------------------------------
  735. Procedure: LoadLW0FromStream
  736. Date: 08-Aug-2002
  737. Arguments: Stream: TStream; ReadCallback: TLWOReadCallback; UserData: Pointer
  738. Result: LongWord
  739. -----------------------------------------------------------------------------}
  740. function LoadLW0FromStream(Stream: TStream; ReadCallback: TLWOReadCallback; UserData: Pointer): LongWord;
  741. var
  742. Chunk: TLWChunkRec;
  743. CurId: TID4;
  744. StartPos, CurSize: TU4;
  745. begin
  746. try
  747. Stream.Read(CurId,4);
  748. ReadMotorolaNumber(Stream,@CurSize,4);
  749. if UpperCase(string(CurId)) = 'FORM' then
  750. begin
  751. Stream.Read(CurId,4);
  752. end else raise Exception.Create('Invalid magic number. Not a valid Lightwave Object');
  753. with Stream do while Position < Size do
  754. begin
  755. Read(Chunk,8);
  756. ReverseByteOrder(@Chunk.size,4);
  757. StartPos:=Position;
  758. GetMem(Chunk.data,Chunk.size);
  759. Stream.Read(Chunk.data^,Chunk.size);
  760. if Assigned(ReadCallback) then ReadCallback(Chunk,UserData);
  761. FreeMem(Chunk.data,Chunk.size);
  762. Position:=StartPos+Chunk.size+(StartPos+Chunk.size) mod 2;
  763. end;
  764. Stream.Free;
  765. result:=High(LongWord);
  766. except
  767. On E: Exception do
  768. begin
  769. Stream.Free;
  770. result := 0;
  771. end;
  772. end;
  773. end;
  774. // LoadLWOFromFile
  775. //
  776. function LoadLWOFromFile(const aFilename : String; readCallback : TLWOReadCallback; userData : Pointer) : LongWord;
  777. var
  778. stream : TStream;
  779. begin
  780. stream:=CreateFileStream(aFilename, fmOpenRead);
  781. try
  782. Result:=LoadLW0FromStream(stream, readCallback, userData);
  783. finally
  784. stream.Free;
  785. end;
  786. end;
  787. procedure ReverseByteOrder(ValueIn: Pointer; Size: Integer; Count: Integer = 1);
  788. var
  789. W: Word;
  790. pB: PByte;
  791. Blo, Bhi: Byte;
  792. L: LongWord;
  793. i: Integer;
  794. begin
  795. i:=0;
  796. case Size of
  797. 2: begin
  798. while i < Count do
  799. begin
  800. W := PU2Array(ValueIn)^[i];
  801. pB := @W;
  802. Blo := pB^;
  803. Inc(pB);
  804. Bhi := pB^;
  805. pB^ := Blo;
  806. Dec(pB);
  807. pB^ := Bhi;
  808. PU2Array(ValueIn)^[i] := w;
  809. Inc(i);
  810. end;
  811. end;
  812. 4: begin
  813. while i < Count do
  814. begin
  815. L := PU4Array(ValueIn)^[i];
  816. pB := @W;
  817. Blo := pB^;
  818. Inc(pB);
  819. Bhi := pB^;
  820. pB^ := Blo;
  821. Dec(pB);
  822. pB^ := Bhi;
  823. PU4Array(ValueIn)^[i] := l;
  824. Inc(i);
  825. end;
  826. end;
  827. else
  828. raise Exception.Create('Lightwave.ReverseByteOrder: Invalid Size = ' + IntToStr(Size));
  829. end;
  830. end;
  831. procedure ReadMotorolaNumber(Stream: TStream; Data: Pointer; ElementSize:
  832. Integer; Count: Integer = 1);
  833. begin
  834. Stream.Read(Data^,Count * ElementSize);
  835. if (ElementSize = 2) or (ElementSize = 4) then
  836. ReverseByteOrder(Data,ElementSize,Count);
  837. end;
  838. function WriteMotorolaNumber(Stream: TStream; Data: Pointer; ElementSize:
  839. Integer; Count: Integer = 1): Integer;
  840. var
  841. TempData: Pointer;
  842. begin
  843. result := 0;
  844. if Data <> nil then
  845. begin
  846. TempData := AllocMem(ElementSize * Count);
  847. try
  848. if (ElementSize = 2) or (ElementSize = 4) then
  849. ReverseByteOrder(TempData,ElementSize,Count);
  850. result := Stream.Write(Data,Count * ElementSize);
  851. except
  852. on E: Exception do
  853. begin
  854. FreeMem(TempData,Count * ElementSize);
  855. raise;
  856. end;
  857. end;
  858. end;
  859. end;
  860. function ReadS0(Stream: TStream; out Str: string): Integer;
  861. var
  862. Buf: array[0..1] of AnsiChar;
  863. StrBuf: string;
  864. begin
  865. Stream.Read(Buf,2);
  866. StrBuf:='';
  867. while Buf[1] <> #0 do
  868. begin
  869. StrBuf := StrBuf + string(Buf);
  870. Stream.Read(Buf,2);
  871. end;
  872. if Buf[0] <> #0 then StrBuf := StrBuf + Char(Buf[0]);
  873. Str := Copy(StrBuf,1,Length(StrBuf));
  874. result := Length(Str) + 1;
  875. result := result + (result mod 2);
  876. end;
  877. function ValueOfVX(VX: Pointer): TU4;
  878. var
  879. TmpU2: TU2;
  880. TmpU4: TU4;
  881. begin
  882. if PU1(VX)^ = $FF then
  883. begin
  884. TmpU4 := TU4(PU1(VX)^) and $FFFFFFF0;
  885. ReverseByteOrder(@TmpU4,4);
  886. end else
  887. begin
  888. TmpU2 := TU2(PU2(VX)^);
  889. ReverseByteOrder(@TmpU2,2);
  890. TmpU4 := TmpU2;
  891. end;
  892. result := TmpU4;
  893. end;
  894. function ReadVXAsU4(Stream: TStream; Data: Pointer; Count: Integer = 1): Integer;
  895. var
  896. i, ReadCount: Integer;
  897. BufByte: byte;
  898. TempU2: TU2;
  899. begin
  900. ReadCount := 0;
  901. for i := 0 to Count -1 do
  902. begin
  903. Stream.Read(BufByte,1);
  904. Stream.Position := Stream.Position - 1;
  905. if BufByte = 255 then
  906. begin
  907. Stream.Read(Data^,SizeOf(TU4));
  908. PU4Array(Data)^[i] := PU4Array(Data)^[i] and $FFFFFFF0;
  909. ReverseByteOrder(Data,SizeOf(TU4));
  910. Inc(ReadCount,4);
  911. end else
  912. begin
  913. Stream.Read(TempU2,SizeOf(TU2));
  914. ReverseByteOrder(@TempU2,SizeOf(TU2));
  915. PU4Array(Data)^[i] := TempU2;
  916. Inc(ReadCount,2);
  917. end;
  918. end;
  919. result := ReadCount;
  920. end;
  921. function ReadVXAsU2(Stream: TStream; Data: Pointer; Count: Integer = 1): Integer;
  922. var
  923. i, ReadCount: Integer;
  924. BufByte: byte;
  925. TempU2: TU2;
  926. begin
  927. ReadCount := 0;
  928. for i := 0 to Count -1 do
  929. begin
  930. Stream.Read(BufByte,1);
  931. Stream.Position := Stream.Position - 1;
  932. if BufByte = 255 then
  933. begin
  934. Stream.Position := Stream.Position + 4;
  935. PU2Array(Data)^[i] := 0;
  936. Inc(ReadCount,4);
  937. end else
  938. begin
  939. Stream.Read(TempU2,SizeOf(TU2));
  940. ReverseByteOrder(@TempU2,SizeOf(TU2));
  941. PU2Array(Data)^[i] := TempU2;
  942. Inc(ReadCount,2);
  943. end;
  944. end;
  945. result := ReadCount;
  946. end;
  947. procedure WriteS0(Stream: TStream; Data: string);
  948. begin
  949. {ToDo: WriteS0}
  950. end;
  951. procedure WriteU4AsVX(Stream:TStream; Data: Pointer; Count: Integer);
  952. var
  953. i: Integer;
  954. TempU2: TU2;
  955. begin
  956. for i := 0 to Count - 1 do
  957. begin
  958. if PU4Array(Data)^[i] < 65280 then
  959. begin
  960. TempU2 := PU4Array(Data)^[i];
  961. WriteMotorolaNumber(Stream,@TempU2,SizeOf(TU2));
  962. end else
  963. WriteMotorolaNumber(Stream,Data,SizeOf(TU4));
  964. end;
  965. end;
  966. type
  967. PInteger = ^Integer;
  968. function ID4ToInt(const Id: TId4): Integer;
  969. var
  970. TmpId: AnsiString;
  971. begin
  972. TmpId := Id;
  973. TmpId := AnsiString(UpperCase(string(Id)));
  974. result := PInteger(@TmpId)^;
  975. end;
  976. { TLWChunk }
  977. {
  978. *********************************** TLWChunk ***********************************
  979. }
  980. destructor TLWChunk.Destroy;
  981. begin
  982. Clear;
  983. inherited;
  984. end;
  985. procedure TLWChunk.Clear;
  986. begin
  987. FreeMem(FData,FSize);
  988. FSize := 0;
  989. FData := nil;
  990. end;
  991. class function TLWChunk.GetID: TID4;
  992. begin
  993. result := #0#0#0#0;
  994. end;
  995. procedure TLWChunk.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  996. begin
  997. GetMem(FData,DataSize);
  998. AStream.Read(PByteArray(FData)^[0],DataSize);
  999. end;
  1000. procedure TLWChunk.LoadFromStream(AStream: TStream);
  1001. var
  1002. DataStart: Integer;
  1003. DataSize: TU4;
  1004. begin
  1005. with AStream do
  1006. begin
  1007. ReadMotorolaNumber(AStream,@DataSize,4);
  1008. DataStart := Position;
  1009. FSize := DataSize;
  1010. LoadData(AStream, DataStart,DataSize);
  1011. Position := Cardinal(DataStart) + DataSize + (Cardinal(DataStart) + DataSize) mod 2;
  1012. end;
  1013. end;
  1014. { TLWChunks }
  1015. {
  1016. ********************************* TLWChunkList *********************************
  1017. }
  1018. constructor TLWChunkList.Create(AOwnsItems: boolean; AOwner: TObject);
  1019. begin
  1020. inherited Create;
  1021. FOwnsItems := AOwnsItems;
  1022. FOwner := AOwner;
  1023. end;
  1024. destructor TLWChunkList.Destroy;
  1025. begin
  1026. Clear;
  1027. inherited;
  1028. end;
  1029. procedure TLWChunkList.Clear;
  1030. begin
  1031. while Count > 0 do
  1032. Delete(Count - 1);
  1033. inherited;
  1034. end;
  1035. procedure TLWChunkList.Delete(Index: Integer);
  1036. begin
  1037. if FOwnsItems then
  1038. Items[Index].Free;
  1039. inherited Delete(Index);
  1040. end;
  1041. function TLWChunkList.GetItem(Index: Integer): TLWChunk;
  1042. begin
  1043. result := TLWChunk(inherited Items[Index]);
  1044. end;
  1045. { TLWObjectFile }
  1046. {
  1047. ******************************** TLWObjectFile *********************************
  1048. }
  1049. constructor TLWObjectFile.Create;
  1050. begin
  1051. inherited;
  1052. end;
  1053. destructor TLWObjectFile.Destroy;
  1054. begin
  1055. FreeAndNil(FChunks);
  1056. inherited;
  1057. end;
  1058. function TLWObjectFile.GetChunks: TLWChunkList;
  1059. begin
  1060. if FChunks = nil then
  1061. FChunks := TLWChunkList.Create(true,Self);
  1062. result := FChunks;
  1063. end;
  1064. function TLWObjectFile.GetCount: Integer;
  1065. begin
  1066. result := Chunks.Count;
  1067. end;
  1068. function TLWObjectFile.GetSurfaceByName(Index: string): TLWSurf;
  1069. var
  1070. SurfIdx: Integer;
  1071. begin
  1072. SurfIdx := Chunks.FindChunk(@FindSurfaceByName,@Index,0);
  1073. if SurfIdx <> -1 then
  1074. result := TLWSurf(Chunks[SurfIdx])
  1075. else
  1076. result := nil;
  1077. end;
  1078. function TLWObjectFile.GetSurfaceByTag(Index: TU2): TLWSurf;
  1079. var
  1080. TagName: string;
  1081. begin
  1082. TagName := TagToName(Index);
  1083. result := SurfaceByName[TagName];
  1084. end;
  1085. procedure TLWObjectFile.LoadFromFile(const AFilename: string);
  1086. var
  1087. Stream: TMemoryStream;
  1088. begin
  1089. Stream := TMemoryStream.Create;
  1090. try
  1091. Stream.LoadFromFile(AFilename);
  1092. LoadFromStream(Stream);
  1093. Stream.Free;
  1094. FFileName := AFilename;
  1095. except
  1096. on E: Exception do
  1097. begin
  1098. Stream.Free;
  1099. raise;
  1100. end;
  1101. end;
  1102. end;
  1103. procedure TLWObjectFile.LoadFromStream(AStream: TStream);
  1104. var
  1105. CurId: TID4;
  1106. CurSize: LongWord;
  1107. CurPnts, CurPols, CurItems: TLWChunkList;
  1108. begin
  1109. CurPols:=nil;
  1110. CurPnts:=nil;
  1111. AStream.Read(CurId,4);
  1112. ReadMotorolaNumber(AStream,@CurSize,4);
  1113. if UpperCase(string(CurId)) = 'FORM' then
  1114. begin
  1115. AStream.Read(CurId,4);
  1116. if CurId <> 'LWO2' then
  1117. raise Exception.Create('Only Version 6.0+ version objects are supported.');
  1118. end else raise Exception.Create('Invalid magic number. Not a valid Lightwave Object');
  1119. CurItems := Chunks;
  1120. while AStream.Position < AStream.Size do
  1121. begin
  1122. AStream.Read(CurId,4);
  1123. if (CurId = ID_PTAG) then
  1124. begin
  1125. CurPols.Add(GetChunkClass(CurId, TLWChunk).Create);
  1126. with CurPols[CurPols.Count - 1] do
  1127. begin
  1128. FID := CurId;
  1129. LoadFromStream(AStream);
  1130. end;
  1131. end else
  1132. if (CurId = ID_VMAP) or (CurId = ID_VMAD) then
  1133. begin
  1134. CurPnts.Add(GetChunkClass(CurId, TLWChunk).Create);
  1135. with CurPnts[CurPnts.Count - 1] do
  1136. begin
  1137. FID := CurId;
  1138. LoadFromStream(AStream);
  1139. end;
  1140. end else
  1141. begin
  1142. if (CurId = ID_LAYR) or (CurId = ID_SURF) or
  1143. (CurId = ID_TAGS) or (CurId = ID_CLIP) then CurItems := Chunks;
  1144. CurItems.Add(GetChunkClass(CurId, TLWChunk).Create);
  1145. with CurItems[CurItems.Count - 1] do
  1146. begin
  1147. FID := CurId;
  1148. LoadFromStream(AStream);
  1149. end;
  1150. end;
  1151. if CurId = ID_LAYR then
  1152. CurItems := TLWParentChunk(CurItems[CurItems.Count - 1]).Items
  1153. else if CurId = ID_POLS then
  1154. CurPols := TLWParentChunk(CurItems[CurItems.Count - 1]).Items
  1155. else if CurId = ID_PNTS then
  1156. CurPnts := TLWParentChunk(CurItems[CurItems.Count - 1]).Items;
  1157. end;
  1158. Chunks.Loaded;
  1159. end;
  1160. { TLWPnts }
  1161. {
  1162. *********************************** TLWPnts ************************************
  1163. }
  1164. function TLWPnts.AddPoly(PntIdx, PolyIdx: Integer): Integer;
  1165. var
  1166. i,L: Integer;
  1167. begin
  1168. {DONE: Pnts.AddPoly}
  1169. for i := 0 to FPntsInfo[PntIdx].npols -1 do
  1170. begin
  1171. if FPntsInfo[PntIdx].pols[i] = PolyIdx then
  1172. begin
  1173. result := i;
  1174. Exit;
  1175. end;
  1176. end;
  1177. L := Length(FPntsInfo[PntIdx].pols);
  1178. SetLength(FPntsInfo[PntIdx].pols,L + 1);
  1179. FPntsInfo[PntIdx].npols := L + 1;
  1180. FPntsInfo[PntIdx].pols[L] := PolyIdx;
  1181. result := L;
  1182. end;
  1183. procedure TLWPnts.Clear;
  1184. var
  1185. i: Integer;
  1186. begin
  1187. for i := 0 to PntsCount -1 do
  1188. SetLength(FPntsInfo[i].pols,0);
  1189. SetLength(FPntsInfo,0);
  1190. SetLength(FPnts,0);
  1191. end;
  1192. function TLWPnts.GetPntsCount: LongWord;
  1193. begin
  1194. result := Length(FPnts);
  1195. end;
  1196. class function TLWPnts.GetID: TID4;
  1197. begin
  1198. result := ID_PNTS;
  1199. end;
  1200. function TLWPnts.GetVMap(VMapID: TID4; out VMap: TLWVMap): Boolean;
  1201. var
  1202. i: Integer;
  1203. begin
  1204. result := false;
  1205. for i := 0 to Items.Count - 1 do
  1206. begin
  1207. if (Items[i] is TLWVMap) and (TLWVMap(Items[i]).VMapType = VMapID) then
  1208. begin
  1209. result := true;
  1210. VMap := TLWVMap(Items[i]);
  1211. Exit;
  1212. end;
  1213. end;
  1214. end;
  1215. procedure TLWPnts.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  1216. begin
  1217. SetLength(FPnts,DataSize div 12); // allocate storage for DataSize div 12 points
  1218. SetLength(FPntsInfo,DataSize div 12); // Point info
  1219. ReadMotorolaNumber(AStream,@FPnts[0],4,DataSize div 4); // read the point data
  1220. end;
  1221. { TLWPols }
  1222. {
  1223. *********************************** TLWPols ************************************
  1224. }
  1225. procedure TLWPols.CalcPolsNormals;
  1226. var
  1227. i,j,PolyIdx: Integer;
  1228. Pnts: TLWPnts;
  1229. begin
  1230. if IndiceCount = 0 then Exit;
  1231. with ParentChunk as TLWLayr do
  1232. Pnts := TLWPnts(Items[Items.FindChunk(@FindChunkById,@ID_PNTS,0)]);
  1233. for PolyIdx := 0 to FPolsCount - 1 do
  1234. begin
  1235. {DONE: call Pnts.AddPoly}
  1236. i := PolsByIndex[PolyIdx];
  1237. with Pnts do
  1238. begin
  1239. for j := 1 to Indices[i] do
  1240. AddPoly(Indices[i + j],PolyIdx);
  1241. SetLength(FPolsInfo[PolyIdx].vnorms,Indices[i]);
  1242. if Indices[PolyIdx]>2 then
  1243. FPolsInfo[PolyIdx].norm:=CalcPlaneNormal(Pnts[Indices[i+1]],Pnts[Indices[i+2]],Pnts[Indices[i+3]])
  1244. else
  1245. FPolsInfo[PolyIdx].norm := VecNorm(Pnts[Indices[i+1]]);
  1246. end;
  1247. end;
  1248. end;
  1249. procedure TLWPols.Clear;
  1250. var
  1251. i: Integer;
  1252. begin
  1253. for i := 0 to FPolsCount-1 do
  1254. SetLength(FPolsInfo[i].vnorms,0);
  1255. SetLength(FPolsInfo,0);
  1256. SetLength(FPols,0);
  1257. end;
  1258. function TLWPols.GetPolsByIndex(AIndex: TU2): Integer;
  1259. var
  1260. i, cnt: Cardinal;
  1261. begin
  1262. result := -1;
  1263. i := 0;
  1264. cnt := 0;
  1265. if AIndex = 0 then
  1266. begin
  1267. result := 0;
  1268. Exit;
  1269. end;
  1270. while (i < IndiceCount - 1) and (cnt <> AIndex) do
  1271. begin
  1272. Inc(i,Indices[i]+1);
  1273. Inc(cnt);
  1274. end;
  1275. if cnt = AIndex then
  1276. result := i;
  1277. end;
  1278. class function TLWPols.GetID: TID4;
  1279. begin
  1280. result := ID_POLS;
  1281. end;
  1282. function TLWPols.GetIndiceCount: TU4;
  1283. begin
  1284. result := Length(FPols);
  1285. end;
  1286. function TLWPols.GetIndice(AIndex: Integer): TU2;
  1287. begin
  1288. result := FPols[AIndex];
  1289. end;
  1290. function TLWPols.GetPolsCount: Integer;
  1291. begin
  1292. result := FPolsCount;
  1293. end;
  1294. procedure TLWPols.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  1295. var
  1296. EndPos: Integer;
  1297. Idx: TU4;
  1298. TmpU2: TU2;
  1299. begin
  1300. Idx := 0;
  1301. EndPos := DataStart + DataSize;
  1302. with AStream do
  1303. begin
  1304. Read(FPolsType,4);
  1305. // To avoid memory manager hits, set an estimate length of indices
  1306. SetLength(FPols,(DataSize - 4) div 2);
  1307. while Position < EndPos do
  1308. begin
  1309. ReadMotorolaNumber(AStream,@FPols[Idx],2);
  1310. TmpU2 := FPols[Idx] and POLS_VCOUNT_MASK;
  1311. ReadVXAsU2(AStream,@FPols[Idx + 1],TmpU2);
  1312. Inc(Idx,FPols[Idx] + 1);
  1313. Inc(FPolsCount);
  1314. end;
  1315. // correct length estimate errors if any
  1316. if (Idx + 1) < Cardinal(Length(FPols)) then
  1317. SetLength(FPols,Idx + 1);
  1318. end;
  1319. SetLength(FPolsInfo,FPolsCount);
  1320. CalcPolsNormals;
  1321. end;
  1322. { TLWVMap }
  1323. {
  1324. *********************************** TLWVMap ************************************
  1325. }
  1326. procedure TLWVMap.Clear;
  1327. var
  1328. i: Integer;
  1329. begin
  1330. for i := 0 to Length(FValues) - 1 do
  1331. SetLength(FValues[i].values,0);
  1332. SetLength(FValues,0);
  1333. end;
  1334. class function TLWVMap.GetID: TID4;
  1335. begin
  1336. result := ID_VMAP;
  1337. end;
  1338. function TLWVMap.GetValue(AIndex: TU2): TLWVertexMap;
  1339. begin
  1340. result := FValues[AIndex];
  1341. end;
  1342. function TLWVMap.GetValueCount: Integer;
  1343. begin
  1344. result := Length(FValues);
  1345. end;
  1346. procedure TLWVMap.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  1347. var
  1348. Idx: TU4;
  1349. begin
  1350. Idx := 0;
  1351. with AStream do
  1352. begin
  1353. Read(FVMapType,4);
  1354. ReadMotorolaNumber(AStream,@FDimensions,2);
  1355. ReadS0(AStream,FName);
  1356. if FDimensions > 0 then
  1357. begin
  1358. while Cardinal(Position) < (DataStart + DataSize) do
  1359. begin
  1360. SetLength(FValues,Length(FValues) + 1);
  1361. ReadVXAsU2(AStream,@FValues[Idx].vert,1);
  1362. SetLength(FValues[Idx].values,Dimensions * 4);
  1363. ReadMotorolaNumber(AStream,@FValues[Idx].values[0],4,Dimensions);
  1364. Inc(Idx);
  1365. end;
  1366. end;
  1367. end;
  1368. end;
  1369. { TLWTags }
  1370. {
  1371. *********************************** TLWTags ************************************
  1372. }
  1373. destructor TLWTags.Destroy;
  1374. begin
  1375. inherited;
  1376. end;
  1377. procedure TLWTags.Clear;
  1378. begin
  1379. FreeAndNil(FTags);
  1380. end;
  1381. class function TLWTags.GetID: TID4;
  1382. begin
  1383. result := ID_TAGS;
  1384. end;
  1385. function TLWTags.GetTags: TStrings;
  1386. begin
  1387. if FTags = nil then
  1388. FTags := TStringList.Create;
  1389. result := FTags;
  1390. end;
  1391. procedure TLWTags.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  1392. var
  1393. EndPos: TU4;
  1394. TmpStr: string;
  1395. begin
  1396. EndPos := DataStart + DataSize;
  1397. while Cardinal(AStream.Position) < Cardinal(EndPos) do
  1398. begin
  1399. ReadS0(AStream,TmpStr);
  1400. Tags.Add(TmpStr);
  1401. TmpStr := '';
  1402. end;
  1403. end;
  1404. function TLWTags.TagToName(Tag: TU2): string;
  1405. begin
  1406. result := Tags[Tag];
  1407. end;
  1408. { TLWSubChunk }
  1409. {
  1410. ********************************* TLWSubChunk **********************************
  1411. }
  1412. procedure TLWSubChunk.LoadFromStream(AStream: TStream);
  1413. var
  1414. DataStart: Integer;
  1415. DataSize: TU2;
  1416. begin
  1417. with AStream do
  1418. begin
  1419. ReadMotorolaNumber(AStream,@DataSize,2);
  1420. DataStart := Position;
  1421. FSize := DataSize;
  1422. LoadData(AStream,DataStart,DataSize);
  1423. Position := DataStart + DataSize + (DataStart + DataSize) mod 2;
  1424. end;
  1425. end;
  1426. {
  1427. *********************************** TLWLayr ************************************
  1428. }
  1429. destructor TLWLayr.Destroy;
  1430. begin
  1431. inherited;
  1432. end;
  1433. class function TLWLayr.GetID: TID4;
  1434. begin
  1435. result := ID_LAYR;
  1436. end;
  1437. procedure TLWLayr.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  1438. begin
  1439. ReadMotorolaNumber(AStream,@FNumber,2);
  1440. ReadMotorolaNumber(AStream,@FFlags,2);
  1441. ReadMotorolaNumber(AStream,@FPivot,4,3);
  1442. ReadS0(AStream,FName);
  1443. if ((DataStart + DataSize) - Cardinal(AStream.Position)) > 2 then
  1444. ReadMotorolaNumber(AStream,@FParent,2);
  1445. end;
  1446. { TLWSurf }
  1447. {
  1448. *********************************** TLWSurf ************************************
  1449. }
  1450. destructor TLWSurf.Destroy;
  1451. begin
  1452. inherited;
  1453. end;
  1454. class function TLWSurf.GetID: TID4;
  1455. begin
  1456. result := ID_SURF;
  1457. end;
  1458. function TLWSurf.GetParamAddr(Param: TID4): Pointer;
  1459. var
  1460. Idx: Integer;
  1461. sParam: string;
  1462. begin
  1463. result:=inherited GetParamAddr(Param);
  1464. if (result=nil) and (Source<>'') then
  1465. begin
  1466. sParam := string(Param);
  1467. Idx:=RootChunks.FindChunk(@FindSurfaceByName,@sParam,0);
  1468. if Idx<>-1 then
  1469. result:=TLWSurf(RootChunks[Idx]).ParamAddr[Param];
  1470. end;
  1471. end;
  1472. function TLWSurf.GetSurfId: Integer;
  1473. var
  1474. c, SurfIdx: Integer;
  1475. begin
  1476. c := 0;
  1477. SurfIdx := Owner.FindChunk(@FindChunkById,@ID_SURF);
  1478. while (SurfIdx <> -1) and (Owner[SurfIdx] <> Self) do
  1479. begin
  1480. SurfIdx := Owner.FindChunk(@FindChunkById,@ID_SURF,SurfIdx + 1);
  1481. Inc(c);
  1482. end;
  1483. result := c;
  1484. end;
  1485. procedure TLWSurf.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  1486. var
  1487. CurId: TID4;
  1488. begin
  1489. ReadS0(AStream,FName);
  1490. ReadS0(AStream,FSource);
  1491. while Cardinal(AStream.Position) < (DataStart + DataSize) do
  1492. begin
  1493. AStream.Read(CurId,4);
  1494. Items.Add(GetChunkClass(CurId, TLWSubChunk).Create);
  1495. with Items[Items.Count - 1] do
  1496. begin
  1497. FID:=CurId;
  1498. LoadFromStream(AStream);
  1499. end;
  1500. end;
  1501. end;
  1502. { TLWPTag }
  1503. {
  1504. *********************************** TLWPTag ************************************
  1505. }
  1506. constructor TLWPTag.Create;
  1507. begin
  1508. inherited;
  1509. end;
  1510. function TLWPTag.AddTag(Value: TU2): Integer;
  1511. var
  1512. i, L: Integer;
  1513. begin
  1514. result := -1;
  1515. L := Length(FTags);
  1516. for i := 0 to L - 1 do
  1517. if Value = FTags[i] then
  1518. begin
  1519. result := i;
  1520. Exit;
  1521. end;
  1522. if result = -1 then
  1523. begin
  1524. SetLength(FTags,L + 1);
  1525. FTags[L] := Value;
  1526. result := L;
  1527. end;
  1528. end;
  1529. procedure TLWPTag.Clear;
  1530. begin
  1531. SetLength(FTagMaps,0);
  1532. SetLength(FTags,0);
  1533. end;
  1534. function TLWPTag.GetPolsByTag(Tag: TU2; var PolyIndices: TU2DynArray): Integer;
  1535. var
  1536. i: Integer;
  1537. procedure AddPoly(Value: TU2);
  1538. var
  1539. L: Integer;
  1540. begin
  1541. L := Length(PolyIndices);
  1542. SetLength(PolyIndices,L+1);
  1543. PolyIndices[L] := Value;
  1544. end;
  1545. begin
  1546. for i := 0 to TagMapCount -1 do
  1547. if TagMaps[i].tag = Tag then
  1548. AddPoly(TagMaps[i].poly);
  1549. result := Length(PolyIndices);
  1550. end;
  1551. class function TLWPTag.GetID: TID4;
  1552. begin
  1553. result := ID_PTAG;
  1554. end;
  1555. function TLWPTag.GetTag(AIndex: Integer): TU2;
  1556. begin
  1557. ValidateTagInfo;
  1558. result := FTags[AIndex];
  1559. end;
  1560. function TLWPTag.GetTagCount: Integer;
  1561. begin
  1562. ValidateTagInfo;
  1563. result := Length(FTags);
  1564. end;
  1565. function TLWPTag.GetTagMapCount: Integer;
  1566. begin
  1567. result := Length(FTagMaps) div 2;
  1568. end;
  1569. function TLWPTag.GetTagMaps(AIndex: Integer): TLWPolyTagMap;
  1570. begin
  1571. result := PLWPolyTagMap(@FTagMaps[AIndex * 2])^;
  1572. end;
  1573. procedure TLWPTag.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
  1574. var
  1575. Idx: Integer;
  1576. begin
  1577. Idx := 0;
  1578. with AStream do
  1579. begin
  1580. Read(FMapType,4);
  1581. SetLength(FTagMaps,(DataSize - 4) div 2);
  1582. while Cardinal(Position) < (DataStart + DataSize) do
  1583. begin
  1584. ReadVXAsU2(AStream, @FTagMaps[Idx]);
  1585. ReadMotorolaNumber(AStream,@FTagMaps[Idx + 1],2);
  1586. Inc(Idx, 2);
  1587. end;
  1588. // correct length guestimate errors if any
  1589. if (Idx + 1) < Length(FTagMaps) then
  1590. SetLength(FTagMaps,Idx + 1);
  1591. end;
  1592. end;
  1593. procedure TLWPTag.ValidateTagInfo;
  1594. var
  1595. i: Integer;
  1596. begin
  1597. if Length(FTags) > 0 then Exit;
  1598. for i := 0 to TagMapCount -1 do
  1599. AddTag(TagMaps[i].tag);
  1600. end;
  1601. { TLWParentChunk }
  1602. {
  1603. ******************************** TLWParentChunk ********************************
  1604. }
  1605. procedure TLWParentChunk.Clear;
  1606. begin
  1607. FreeAndNil(FItems);
  1608. inherited;
  1609. end;
  1610. function TLWParentChunk.GetFloatParam(Param: TID4): Single;
  1611. var
  1612. pdata: Pointer;
  1613. begin
  1614. pdata:=ParamAddr[Param];
  1615. if pdata <> nil then
  1616. begin
  1617. result:=PF4(pdata)^;
  1618. ReverseByteOrder(@result,4);
  1619. end else
  1620. result:=0.0;
  1621. end;
  1622. function TLWParentChunk.GetItems: TLWChunkList;
  1623. begin
  1624. if FItems = nil then
  1625. FItems := TLWChunkList.Create(true,Self);
  1626. result := FItems;
  1627. end;
  1628. function TLWParentChunk.GetLongParam(Param: TID4): LongWord;
  1629. var
  1630. pdata: Pointer;
  1631. begin
  1632. pdata:=ParamAddr[Param];
  1633. if pdata <> nil then
  1634. begin
  1635. result:=PU4(pdata)^;
  1636. ReverseByteOrder(@result,4);
  1637. end else
  1638. result:=0;
  1639. end;
  1640. function TLWParentChunk.GetParamAddr(Param: TID4): Pointer;
  1641. var
  1642. Idx: Integer;
  1643. begin
  1644. result := nil;
  1645. Idx := Items.FindChunk(@FindChunkById,@Param,0);
  1646. if Idx <> -1 then
  1647. result := Items[Idx].Data;
  1648. end;
  1649. function TLWPols.GetPolsByPntIdx(VertIdx: TU2;
  1650. var VertPolys: TU2DynArray): Integer;
  1651. var
  1652. i,j,L: Integer;
  1653. begin
  1654. L:=0;
  1655. if Length(VertPolys) >0 then
  1656. SetLength(VertPolys,0);
  1657. for i := 0 to PolsCount -1 do
  1658. begin
  1659. for j := 1 to Indices[PolsByIndex[i]] do
  1660. begin
  1661. if Indices[PolsByIndex[i] + j] = VertIdx then
  1662. begin
  1663. L := Length(VertPolys);
  1664. SetLength(VertPolys, L + 1);
  1665. VertPolys[L] := i;
  1666. end;
  1667. end;
  1668. end;
  1669. result := L;
  1670. end;
  1671. function TLWChunkList.Add(AChunk: TLWChunk): Integer;
  1672. begin
  1673. if (FOwner<>nil) and (FOwner is TLWParentChunk) then
  1674. AChunk.FParentChunk := TLWParentChunk(FOwner);
  1675. AChunk.FOwner := self;
  1676. result := inherited Add(AChunk);
  1677. end;
  1678. procedure TLWPols.CalcPntsNormals;
  1679. var
  1680. i,j,k,PntIdx,PolyIdx,SurfIdx: Integer;
  1681. Pnts: TLWPnts;
  1682. // PTags: TLWPTag;
  1683. TmpAddr: Pointer;
  1684. sman: TF4;
  1685. begin
  1686. {Todo: CalcPntsNormals}
  1687. if IndiceCount = 0 then Exit;
  1688. with ParentChunk as TLWLayr do
  1689. Pnts := TLWPnts(Items[Items.FindChunk(@FindChunkById,@ID_PNTS,0)]);
  1690. for PolyIdx := 0 to PolsCount-1 do
  1691. begin
  1692. i := PolsByIndex[PolyIdx];
  1693. SurfIdx := RootChunks.FindChunk(@FindSurfaceByTag,@FPolsInfo[PolyIdx].surfid);
  1694. TmpAddr := TLWSurf(RootChunks[SurfIdx]).ParamAddr[ID_SMAN];
  1695. if TmpAddr <> nil then
  1696. begin
  1697. sman := PF4(TmpAddr)^;
  1698. ReverseByteOrder(@sman,4);
  1699. end else
  1700. sman := 0;
  1701. for j := 1 to Indices[i] do
  1702. begin
  1703. FPolsInfo[PolyIdx].vnorms[j-1] := FPolsInfo[PolyIdx].norm;
  1704. if sman <= 0 then continue;
  1705. PntIdx := Indices[i + j];
  1706. for k := 0 to Pnts.PntsInfo[PntIdx].npols -1 do
  1707. begin
  1708. if Pnts.PntsInfo[PntIdx].pols[k] = PolyIdx then continue;
  1709. if ArcCos(VecDot(FPolsInfo[PolyIdx].norm,FPolsInfo[Pnts.PntsInfo[PntIdx].pols[k]].norm)) > sman then continue;
  1710. FPolsInfo[PolyIdx].vnorms[j-1]:=VecAdd(FPolsInfo[PolyIdx].vnorms[j-1],FPolsInfo[Pnts.PntsInfo[PntIdx].pols[k]].norm);
  1711. end;
  1712. FPolsInfo[PolyIdx].vnorms[j-1]:=VecNorm(FPolsInfo[PolyIdx].vnorms[j-1]);
  1713. end;
  1714. end;
  1715. end;
  1716. function TLWChunk.GetRootChunks: TLWChunkList;
  1717. var
  1718. Parent: TLWParentChunk;
  1719. begin
  1720. result := nil;
  1721. if (FParentChunk = nil) then
  1722. begin
  1723. if (FOwner is TLWChunkList) then
  1724. begin
  1725. result := FOwner;
  1726. Exit;
  1727. end;
  1728. end else
  1729. begin
  1730. Parent := FParentChunk;
  1731. while not(Parent.ParentChunk = nil) do
  1732. Parent := Parent.ParentChunk;
  1733. result := Parent.Owner;
  1734. end;
  1735. end;
  1736. function TLWChunkList.FindChunk(ChunkFind: TLWChunkFind; Criteria: Pointer; StartIndex: Integer): Integer;
  1737. var
  1738. Found: boolean;
  1739. begin
  1740. Found := false;
  1741. result := -1;
  1742. while (StartIndex < Count) and (not Found) do
  1743. begin
  1744. ChunkFind(Items[StartIndex],Criteria,Found);
  1745. if Found then
  1746. begin
  1747. result := StartIndex;
  1748. Exit;
  1749. end;
  1750. Inc(StartIndex);
  1751. end;
  1752. end;
  1753. function TLWChunk.GetIndex: Integer;
  1754. begin
  1755. result := Owner.IndexOf(Self);
  1756. end;
  1757. procedure TLWChunk.Loaded;
  1758. begin
  1759. // do nothing
  1760. end;
  1761. procedure TLWChunkList.Loaded;
  1762. var
  1763. i: Integer;
  1764. begin
  1765. for i := 0 to Count-1 do
  1766. begin
  1767. Items[i].Loaded;
  1768. end;
  1769. end;
  1770. function TLWParentChunk.GetVec3Param(Param: TID4): TVec12;
  1771. var
  1772. pdata: Pointer;
  1773. begin
  1774. pdata:=ParamAddr[Param];
  1775. if pdata <> nil then
  1776. begin
  1777. result:=PVec12(pdata)^;
  1778. ReverseByteOrder(@result,4,3);
  1779. end else
  1780. begin
  1781. result[0]:=0;
  1782. result[1]:=1;
  1783. result[2]:=2;
  1784. end;
  1785. end;
  1786. function TLWParentChunk.GetVXParam(Param: TID4): Word;
  1787. var
  1788. pdata: Pointer;
  1789. begin
  1790. pdata:=ParamAddr[Param];
  1791. if pdata <> nil then
  1792. result:=ValueOfVX(pdata)
  1793. else
  1794. result:=0;
  1795. end;
  1796. function TLWParentChunk.GetWordParam(Param: TID4): Word;
  1797. var
  1798. pdata: Pointer;
  1799. begin
  1800. pdata:=ParamAddr[Param];
  1801. if pdata <> nil then
  1802. begin
  1803. result:=PU4(pdata)^;
  1804. ReverseByteOrder(@result,2);
  1805. end else
  1806. result:=0;
  1807. end;
  1808. procedure TLWParentChunk.Loaded;
  1809. begin
  1810. Items.Loaded;
  1811. end;
  1812. procedure TLWPols.Loaded;
  1813. begin
  1814. inherited;
  1815. CalcPntsNormals;
  1816. end;
  1817. function TLWObjectFile.TagToName(Tag: TU2): string;
  1818. var
  1819. TagsIdx: Integer;
  1820. begin
  1821. TagsIdx := Chunks.FindChunk(@FindChunkById,@ID_TAGS);
  1822. if TagsIdx <> -1 then
  1823. result := TLWTags(Chunks[TagsIdx]).TagToName(Tag);
  1824. end;
  1825. { TLWClip }
  1826. class function TLWClip.GetID: TID4;
  1827. begin
  1828. result := ID_CLIP;
  1829. end;
  1830. procedure TLWClip.LoadData(AStream: TStream; DataStart,
  1831. DataSize: LongWord);
  1832. var
  1833. CurId: TID4;
  1834. begin
  1835. ReadMotorolaNumber(AStream,@FClipIndex,4);
  1836. while Cardinal(AStream.Position) < (DataStart + DataSize) do
  1837. begin
  1838. AStream.Read(CurId,4);
  1839. Items.Add(GetChunkClass(CurId, TLWSubChunk).Create);
  1840. with Items[Items.Count - 1] do
  1841. begin
  1842. FID:=CurId;
  1843. LoadFromStream(AStream);
  1844. end;
  1845. end;
  1846. end;
  1847. { TLWContentDir }
  1848. {function TLWContentDir.ContentSearch(AFilename: string): string;
  1849. var
  1850. i: Integer;
  1851. begin
  1852. if not FileExists(AFilename) then
  1853. begin
  1854. result := ExtractFileName(AFilename);
  1855. if not FileExists(result) then
  1856. begin
  1857. for i := 0 to SubDirs.Count - 1 do
  1858. begin
  1859. if FileExists(Root+'\'+SubDirs[i]+'\'+result) then
  1860. begin
  1861. result:=Root+'\'+SubDirs[i]+'\'+result;
  1862. Exit;
  1863. end;
  1864. end;
  1865. result := '';
  1866. end;
  1867. end;
  1868. end;}
  1869. destructor TLWContentDir.Destroy;
  1870. begin
  1871. FreeAndNil(FSubDirs);
  1872. inherited;
  1873. end;
  1874. function TLWContentDir.FindContent(AFilename: string): string;
  1875. var
  1876. i: Integer;
  1877. begin
  1878. if not FileExists(AFilename) then
  1879. begin
  1880. result := ExtractFileName(AFilename);
  1881. if not FileExists(result) then
  1882. begin
  1883. for i := 0 to SubDirs.Count - 1 do
  1884. begin
  1885. if FileExists(Root+'\'+SubDirs[i]+'\'+result) then
  1886. begin
  1887. result:=Root+'\'+SubDirs[i]+'\'+result;
  1888. Exit;
  1889. end;
  1890. end;
  1891. result := '';
  1892. end;
  1893. end;
  1894. end;
  1895. function TLWContentDir.GetSubDirs: TStrings;
  1896. begin
  1897. if FSubDirs = nil then
  1898. FSubDirs := TStringList.Create;
  1899. result := FSubDirs;
  1900. end;
  1901. procedure TLWContentDir.SetRoot(const Value: string);
  1902. begin
  1903. FRoot := Value;
  1904. end;
  1905. procedure TLWContentDir.SetSubDirs(const Value: TStrings);
  1906. begin
  1907. SubDirs.Assign(Value);
  1908. end;
  1909. initialization
  1910. { Pnts }
  1911. RegisterChunkClass(TLWPnts);
  1912. { Pols }
  1913. RegisterChunkClass(TLWPols);
  1914. { VMap }
  1915. RegisterChunkClass(TLWVMap);
  1916. { Tags }
  1917. RegisterChunkClass(TLWTags);
  1918. { PTAG }
  1919. RegisterChunkClass(TLWPTAG);
  1920. { SURF }
  1921. RegisterChunkClass(TLWSurf);
  1922. { LAYR }
  1923. RegisterChunkClass(TLWLayr);
  1924. { CLIP }
  1925. RegisterChunkClass(TLWClip);
  1926. finalization
  1927. // UnRegisterChunkClasses;
  1928. FreeAndNil(ChunkClasses);
  1929. FreeAndNil(ContentDir);
  1930. end.