123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199 |
- //
- // The graphics engine GLScene
- //
- unit GLS.File3DS;
- (* 3DStudio 3DS vector file format implementation *)
- interface
- {$I Stage.Defines.inc}
- uses
- System.Classes,
- System.SysUtils,
- System.Math,
-
- Stage.Strings,
- Stage.OpenGLTokens,
- Stage.VectorTypes,
- Stage.VectorGeometry,
- GLS.Scene,
- GLS.Objects,
- GLS.VectorFileObjects,
- GLS.Texture,
- GLS.ApplicationFileIO,
- GLS.Context,
- GLS.PersistentClasses,
- GLS.File3DSSceneObjects,
- GLS.VectorLists,
- GLS.RenderContextInfo,
- GLS.Material,
- Formats.m3DS,
- Formats.m3DSTypes;
- type
- EGLFile3DS = class(Exception);
- // A record that holds all the information that is used during 3ds animation.
- TGLFile3DSAnimationData = packed record
- ModelMatrix: TGLMatrix;
- Color: TGLVector; // Omni Light.
- TargetPos: TAffineVector; // Spot Light.
- SpotLightCutOff: Single;
- HotSpot: Single;
- Roll: Single;
- end;
- // An abstract class that describes how to interpolate animation keys.
- TGLFile3DSAnimationKeys = class(TGLPersistentObject)
- private
- FNumKeys: Integer;
- FKeys: array of TKeyHeader3DS;
- procedure InterpolateFrame(var I: Integer; var w: real; const AFrame: real);
- protected
- function InterpolateValue(const AValues: array of Single; const AFrame: real): Single; overload;
- function InterpolateValue(const AValues: array of TAffineVector; const AFrame: real): TAffineVector; overload;
- function InterpolateValue(const AValues: array of TKFRotKey3DS; const AFrame: real): TGLMatrix; overload;
- public
- procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); virtual;
- procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); virtual; abstract;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- end;
- TGLFile3DSScaleAnimationKeys = class(TGLFile3DSAnimationKeys)
- private
- FScale: array of TAffineVector;
- public
- procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- end;
- TGLFile3DSRotationAnimationKeys = class(TGLFile3DSAnimationKeys)
- private
- FRot: array of TKFRotKey3DS;
- public
- procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- end;
- TGLFile3DSPositionAnimationKeys = class(TGLFile3DSAnimationKeys)
- private
- FPos: array of TAffineVector;
- public
- procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- end;
- TGLFile3DSColorAnimationKeys = class(TGLFile3DSAnimationKeys)
- private
- FCol: array of TAffineVector;
- public
- procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- end;
- TTGLFile3DSPositionAnimationKeys = class(TGLFile3DSAnimationKeys)
- private
- FTPos: array of TAffineVector;
- public
- procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- end;
- TGLFile3DSSpotLightCutOffAnimationKeys = class(TGLFile3DSAnimationKeys)
- private
- FFall: array of Single;
- public
- procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- end;
- TGLFile3DSLightHotSpotAnimationKeys = class(TGLFile3DSAnimationKeys)
- private
- FHot: array of Single;
- public
- procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- end;
- TGLFile3DSRollAnimationKeys = class(TGLFile3DSAnimationKeys)
- private
- FRoll: array of Single;
- public
- procedure LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- end;
- TGLFile3DSAnimationKeyList = class(TGLPersistentObject)
- private
- FAnimKeysList: array of TGLFile3DSAnimationKeys;
- protected
- procedure ApplyAnimKeys(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
- public
- procedure AddKeys(const AItem: TGLFile3DSAnimationKeys);
- procedure ClearKeys;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- destructor Destroy; override;
- end;
- // Used only for serialization. There probably is a more efficient way to do it.
- TGLFile3DSAnimKeysClassType = (ctScale, ctRot, ctPos, ctCol, ctTPos, ctFall, ctHot, ctRoll);
- // A 3ds-specific TGLMorphableMeshObject.
- TGLFile3DSDummyObject = class(TGLMorphableMeshObject)
- private
- FAnimList: TGLFile3DSAnimationKeyList;
- FAnimData: Pointer;
- FRefTranf, FAnimTransf: TGLFile3DSAnimationData;
- FParent: TGLFile3DSDummyObject;
- FParentName: String64;
- FStatic: Boolean; // Static tag used in BuildList to not apply animation matrix
- public
- procedure LoadAnimation(const AData: Pointer); virtual;
- procedure SetFrame(const AFrame: real); virtual;
- procedure MorphTo(morphTargetIndex: Integer); override;
- procedure Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single); override;
- procedure GetExtents(out min, max: TAffineVector); override;
- function ExtractTriangles(texCoords: TGLAffineVectorList = nil; normals: TGLAffineVectorList = nil): TGLAffineVectorList;
- override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- procedure Assign(Source: TPersistent); override;
- constructor Create; override;
- destructor Destroy; override;
- property AnimList: TGLFile3DSAnimationKeyList read FAnimList;
- property Parent: TGLFile3DSDummyObject read FParent write FParent;
- property RefrenceTransf: TGLFile3DSAnimationData read FRefTranf write FRefTranf;
- end;
- // A 3ds-specific mesh object.
- TGLFile3DSMeshObject = class(TGLFile3DSDummyObject)
- public
- procedure LoadAnimation(const AData: Pointer); override;
- procedure BuildList(var ARci: TGLRenderContextInfo); override;
- end;
- // A 3ds-specific omni light.
- TGLFile3DSOmniLightObject = class(TGLFile3DSDummyObject)
- private
- FLightSrc: TGLFile3DSLight;
- FLightSrcName: String64;
- public
- constructor Create; override;
- procedure LoadData(const AOwner: TGLBaseMesh; const AData: PLight3DS); virtual;
- procedure LoadAnimation(const AData: Pointer); override;
- procedure SetFrame(const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- destructor Destroy; override;
- end;
- // A 3ds-specific spot light.
- TGLFile3DSSpotLightObject = class(TGLFile3DSOmniLightObject)
- public
- procedure LoadData(const AOwner: TGLBaseMesh; const AData: PLight3DS); override;
- procedure LoadAnimation(const AData: Pointer); override;
- procedure SetFrame(const AFrame: real); override;
- end;
- // A 3ds-specific camera.
- TGLFile3DSCameraObject = class(TGLFile3DSDummyObject)
- private
- FTargetObj: TGLDummyCube;
- FCameraSrc: TGLFile3DSCamera;
- FCameraSrcName: String64;
- public
- constructor Create; override;
- procedure LoadData(Owner: TGLBaseMesh; AData: PCamera3DS);
- procedure LoadAnimation(const AData: Pointer); override;
- procedure SetFrame(const AFrame: real); override;
- procedure WriteToFiler(Writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(Reader: TGLVirtualReader); override;
- destructor Destroy; override;
- end;
- (* The 3DStudio vector file.
- Uses an upgraded version if a 3DS import library by Mike Lischke.
- (http://www.lishcke-online.de). A 3DS file may contain material
- information and require textures when loading. *)
- TGL3DSVectorFile = class(TGLVectorFile)
- public
- class function Capabilities: TGLDataFileCapabilities; override;
- procedure LoadFromStream(aStream: TStream); override;
- end;
- var
- (* If enabled, advanced parameters will be loaded from a 3ds file
- (TextureScale, TextureOffset), but it might break backwards compatibility.
- If disabled, it won't break anything, but some parameters will not be
- loaded correctly from a 3ds file.
- Also there is a significant drop in FPS when this option is on
- (for unknown reasons), so it is off by default. *)
- vGLFile3DS_UseTextureEx: Boolean = False;
- (* If enabled, allows 3ds animation and fixes loading of some 3ds models,
- but has a few bugs:
- - TGLFreeForm.AutoCentering does now work correctly.
- - TGLMeshObject.vertices return values different from
- TGLMeshObject.ExtractTriangles() *)
- vGLFile3DS_EnableAnimation: Boolean = False;
- (* If enabled, a -90 degrees (-PI/2) rotation will occured on X Axis.
- By design 3dsmax has a Z Up-Axis, after the rotation the Up axis will
- be Y. (Note: you need vGLFile3DS_EnableAnimation = true) *)
- vGLFile3DS_FixDefaultUpAxisY: Boolean = False;
- (* If >= 0, then the vertices list will be updated with selected frame
- animation data. (Note: you need vGLFile3DS_EnableAnimation = true).
- Be aware that in that case animation will not be usable, it is made
- to be used with a static mesh like GLFreeForm. *)
- vGLFile3DS_LoadedStaticFrame: Integer = -1;
- // ------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------
- const
- cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE = PI / 2;
- CGLFILE3DS_DEFAULT_FRAME = 0;
- function AnimKeysClassTypeToClass(const AAnimKeysClassType: TGLFile3DSAnimKeysClassType): TClass;
- begin
- case AAnimKeysClassType of
- ctScale: Result := TGLFile3DSScaleAnimationKeys;
- ctRot: Result := TGLFile3DSRotationAnimationKeys;
- ctPos: Result := TGLFile3DSPositionAnimationKeys;
- ctCol: Result := TGLFile3DSColorAnimationKeys;
- ctTPos: Result := TTGLFile3DSPositionAnimationKeys;
- ctFall: Result := TGLFile3DSSpotLightCutOffAnimationKeys;
- ctHot: Result := TGLFile3DSLightHotSpotAnimationKeys;
- ctRoll: Result := TGLFile3DSRollAnimationKeys;
- else
- begin
- Result := nil;
- Assert(False, strErrorEx + strUnknownType);
- end;
- end;
- end;
- function ClassToAnimKeysClassType(const AAnimKeysClass: TClass): TGLFile3DSAnimKeysClassType;
- begin
- if AAnimKeysClass.InheritsFrom(TGLFile3DSScaleAnimationKeys) then
- Result := ctScale
- else if AAnimKeysClass.InheritsFrom(TGLFile3DSRotationAnimationKeys) then
- Result := ctRot
- else if AAnimKeysClass.InheritsFrom(TGLFile3DSPositionAnimationKeys) then
- Result := ctPos
- else if AAnimKeysClass.InheritsFrom(TGLFile3DSColorAnimationKeys) then
- Result := ctCol
- else if AAnimKeysClass.InheritsFrom(TTGLFile3DSPositionAnimationKeys) then
- Result := ctTPos
- else if AAnimKeysClass.InheritsFrom(TGLFile3DSSpotLightCutOffAnimationKeys) then
- Result := ctFall
- else if AAnimKeysClass.InheritsFrom(TGLFile3DSLightHotSpotAnimationKeys) then
- Result := ctHot
- else if AAnimKeysClass.InheritsFrom(TGLFile3DSRollAnimationKeys) then
- Result := ctRoll
- else
- begin
- Result := ctScale;
- Assert(False, strErrorEx + strUnknownType);
- end;
- end;
- function MakeRotationQuaternion(const axis: TAffineVector; angle: Single): TQuaternion;
- var
- v: TGLVector;
- halfAngle, invAxisLengthMult: Single;
- begin
- halfAngle := (angle) / 2;
- invAxisLengthMult := 1 / VectorLength(axis) * sin(halfAngle);
- v.X := axis.X * invAxisLengthMult;
- v.Y := axis.Y * invAxisLengthMult;
- v.Z := axis.Z * invAxisLengthMult;
- v.W := cos(halfAngle);
- Result.ImagPart := AffineVectorMake(v);
- Result.RealPart := v.W;
- end;
- function QuaternionToRotateMatrix(const Quaternion: TQuaternion): TGLMatrix;
- var
- wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2: Single;
- quat: TGLVector;
- m: TGLMatrix;
- begin
- quat := VectorMake(Quaternion.ImagPart);
- quat.W := Quaternion.RealPart;
- x2 := quat.X + quat.X;
- y2 := quat.Y + quat.Y;
- z2 := quat.Z + quat.Z;
- xx := quat.X * x2;
- xy := quat.X * y2;
- xz := quat.X * z2;
- yy := quat.Y * y2;
- yz := quat.Y * z2;
- zz := quat.Z * z2;
- wx := quat.W * x2;
- wy := quat.W * y2;
- wz := quat.W * z2;
- m.X.X := 1.0 - (yy + zz);
- m.X.Y := xy - wz;
- m.X.Z := xz + wy;
- m.Y.X := xy + wz;
- m.Y.Y := 1.0 - (xx + zz);
- m.Y.Z := yz - wx;
- m.Z.X := xz - wy;
- m.Z.Y := yz + wx;
- m.Z.Z := 1.0 - (xx + yy);
- m.X.W := 0;
- m.Y.W := 0;
- m.Z.W := 0;
- m.W.X := 0;
- m.W.Y := 0;
- m.W.Z := 0;
- m.W.W := 1;
- Result := m;
- end;
- // ------------------
- // ------------------ Support classes ------------------
- // ------------------
- procedure TGLFile3DSAnimationKeys.InterpolateFrame(var I: Integer; var w: real; const AFrame: real);
- begin
- w := 1;
- I := 0;
- if FNumKeys > 1 then
- begin
- while (FNumKeys > I) and ((FKeys[I].Time) <= AFrame) do
- Inc(I);
- if (FNumKeys > I) and ((FKeys[I - 1].Time) <= AFrame) then
- w := (AFrame - FKeys[I - 1].Time) / (FKeys[I].Time - FKeys[I - 1].Time);
- // Don't allow keys to go our of range.
- if I = FNumKeys then
- I := FNumKeys - 1;
- end;
- end;
- function TGLFile3DSAnimationKeys.InterpolateValue(const AValues: array of Single; const AFrame: real): Single;
- var
- I: Integer;
- w: real;
- start, stop: Single;
- begin
- InterpolateFrame(I, w, AFrame);
- if I > 0 then
- start := AValues[I - 1]
- else
- start := 0;
- if FNumKeys > I then
- stop := AValues[I]
- else
- stop := 0;
- Result := Lerp(start, stop, w);
- end;
- function TGLFile3DSAnimationKeys.InterpolateValue(const AValues: array of TAffineVector; const AFrame: real): TAffineVector;
- var
- I: Integer;
- w: real;
- start, stop: TAffineVector;
- begin
- InterpolateFrame(I, w, AFrame);
- if I > 0 then
- start := AValues[I - 1]
- else
- start := NullVector;
- if FNumKeys > I then
- stop := AValues[I]
- else
- stop := NullVector;
- Result := VectorLerp(start, stop, w);
- end;
- function TGLFile3DSAnimationKeys.InterpolateValue(const AValues: array of TKFRotKey3DS; const AFrame: real): TGLMatrix;
- var
- I: Integer;
- w: real;
- begin
- Result := IdentityHmgMatrix;
- // First find the final matrix for this frame.
- I := 0;
- while (FNumKeys > I) and ((FKeys[I].Time) <= AFrame) do
- begin
- with AValues[I] do
- Result := MatrixMultiply(Result, CreateRotationMatrix(AffineVectorMake(X, Y, Z), angle));
- Inc(I);
- end;
- InterpolateFrame(I, w, AFrame);
- // Then interpolate this matrix
- if (FNumKeys > I) and ((FKeys[I].Time) > AFrame) and ((FKeys[I - 1].Time) < AFrame) then
- begin
- with AValues[I] do
- Result := MatrixMultiply(Result, CreateRotationMatrix(AffineVectorMake(X, Y, Z), AngleLerp(0, angle, w)));
- end;
- end;
- procedure TGLFile3DSAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
- var
- I: Integer;
- begin
- FNumKeys := ANumKeys;
- SetLength(FKeys, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FKeys[I] := Keys[I];
- end;
- procedure TGLFile3DSAnimationKeys.Assign(Source: TPersistent);
- var
- I: Integer;
- begin
- if Source is TGLFile3DSAnimationKeys then
- begin
- FNumKeys := TGLFile3DSAnimationKeys(Source).FNumKeys;
- SetLength(FKeys, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FKeys[I] := TGLFile3DSAnimationKeys(Source).FKeys[I];
- end
- else
- inherited Assign(Source);
- end;
- procedure TGLFile3DSAnimationKeys.WriteToFiler(Writer: TGLVirtualWriter);
- begin
- Writer.WriteInteger(FNumKeys);
- if FNumKeys > 0 then
- Writer.Write(FKeys[0], FNumKeys * SizeOf(TKeyHeader3DS));
- end;
- procedure TGLFile3DSAnimationKeys.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- FNumKeys := Reader.ReadInteger;
- SetLength(FKeys, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FKeys[0], FNumKeys * SizeOf(TKeyHeader3DS));
- end;
- procedure TGLFile3DSScaleAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
- var
- I: Integer;
- AffVect: TAffineVector;
- Sign: ShortInt;
- begin
- inherited;
- SetLength(FScale, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- begin
- FScale[I] := TAffineVector(PPointList(AData)[I]);
- if vGLFile3DS_FixDefaultUpAxisY then
- begin
- AffVect := FScale[I];
- if (AffVect.X < 0) or (AffVect.Y < 0) or (AffVect.Z < 0) then
- Sign := -1
- else
- Sign := 1;
- AffVect := VectorRotateAroundX(AffVect, cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
- FScale[I].X := Sign * Abs(AffVect.X);
- FScale[I].Y := Sign * Abs(AffVect.Y);
- FScale[I].Z := Sign * Abs(AffVect.Z);
- end;
- end;
- end;
- procedure TGLFile3DSScaleAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.ModelMatrix := MatrixMultiply(DataTransf.ModelMatrix, CreateScaleMatrix(InterpolateValue(FScale, AFrame)));
- end;
- procedure TGLFile3DSScaleAnimationKeys.Assign(Source: TPersistent);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FScale, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FScale[I] := (Source as TGLFile3DSScaleAnimationKeys).FScale[I];
- end;
- procedure TGLFile3DSScaleAnimationKeys.WriteToFiler(Writer: TGLVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FScale[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TGLFile3DSScaleAnimationKeys.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- inherited;
- SetLength(FScale, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FScale[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TGLFile3DSRotationAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
- var
- I: Integer;
- Rot: PKFRotKeyList;
- AffVect: TAffineVector;
- begin
- inherited;
- SetLength(FRot, FNumKeys);
- Rot := PKFRotKeyList(AData);
- for I := 0 to FNumKeys - 1 do
- begin
- // The initial values do not contain any turns, that's why we have to make one.
- if (Rot[I].X = 0) and (Rot[I].Y = 0) and (Rot[I].Z = 0) then
- Rot[I].X := 1;
- // One quartalion can't describe a big angle (>180), that's why we have to subtract it from 2*pi
- if Rot[I].Angle > pi then
- begin
- Rot[I].Angle := 2 * PI - Rot[I].Angle;
- Rot[I].X := -Rot[I].X;
- Rot[I].Y := -Rot[I].Y;
- Rot[I].Z := -Rot[I].Z;
- end;
- FRot[I] := Rot[I];
- if vGLFile3DS_FixDefaultUpAxisY then
- begin
- AffVect.X := FRot[I].X;
- AffVect.Y := FRot[I].Y;
- AffVect.Z := FRot[I].Z;
- AffVect := VectorRotateAroundX(AffVect, cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
- FRot[I].X := AffVect.X;
- FRot[I].Y := AffVect.Y;
- FRot[I].Z := AffVect.Z;
- end;
- end;
- end;
- procedure TGLFile3DSRotationAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.ModelMatrix := MatrixMultiply(DataTransf.ModelMatrix, InterpolateValue(FRot, AFrame));
- end;
- procedure TGLFile3DSRotationAnimationKeys.Assign(Source: TPersistent);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FRot, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FRot[I] := (Source as TGLFile3DSRotationAnimationKeys).FRot[I];
- end;
- procedure TGLFile3DSRotationAnimationKeys.WriteToFiler(Writer: TGLVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FRot[0], FNumKeys * SizeOf(TKFRotKey3DS));
- end;
- procedure TGLFile3DSRotationAnimationKeys.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- inherited;
- SetLength(FRot, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FRot[0], FNumKeys * SizeOf(TKFRotKey3DS));
- end;
- procedure TGLFile3DSPositionAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FPos, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- begin
- FPos[I] := TAffineVector(PPointList(AData)[I]);
- if vGLFile3DS_FixDefaultUpAxisY then
- begin
- FPos[I] := VectorRotateAroundX(FPos[I], cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
- end;
- end;
- end;
- procedure TGLFile3DSPositionAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.ModelMatrix.V[3] :=
- VectorAdd(DataTransf.ModelMatrix.V[3], VectorMake(InterpolateValue(FPos, AFrame)));
- end;
- procedure TGLFile3DSPositionAnimationKeys.Assign(Source: TPersistent);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FPos, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FPos[I] := (Source as TGLFile3DSPositionAnimationKeys).FPos[I];
- end;
- procedure TGLFile3DSPositionAnimationKeys.WriteToFiler(Writer: TGLVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FPos[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TGLFile3DSPositionAnimationKeys.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- inherited;
- SetLength(FPos, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FPos[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TGLFile3DSColorAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FCol, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FCol[I] := TAffineVector(PFColorList(AData)[I]);
- end;
- procedure TGLFile3DSColorAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.Color := VectorAdd(DataTransf.Color, VectorMake(InterpolateValue(FCol, AFrame)));
- end;
- procedure TGLFile3DSColorAnimationKeys.Assign(Source: TPersistent);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FCol, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FCol[I] := (Source as TGLFile3DSColorAnimationKeys).FCol[I];
- end;
- procedure TGLFile3DSColorAnimationKeys.WriteToFiler(Writer: TGLVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FCol[0], FNumKeys * SizeOf(TFColor3DS));
- end;
- procedure TGLFile3DSColorAnimationKeys.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- inherited;
- SetLength(FCol, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FCol[0], FNumKeys * SizeOf(TFColor3DS));
- end;
- procedure TTGLFile3DSPositionAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FTPos, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- begin
- FTPos[I] := TAffineVector(PPointList(AData)[I]);
- if vGLFile3DS_FixDefaultUpAxisY then
- begin
- FTPos[I] := VectorRotateAroundX(FTPos[I], cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
- end;
- end;
- end;
- procedure TTGLFile3DSPositionAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.TargetPos := VectorAdd(DataTransf.TargetPos, InterpolateValue(FTPos, AFrame));
- end;
- procedure TTGLFile3DSPositionAnimationKeys.Assign(Source: TPersistent);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FTPos, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FTPos[I] := (Source as TTGLFile3DSPositionAnimationKeys).FTPos[I];
- end;
- procedure TTGLFile3DSPositionAnimationKeys.WriteToFiler(Writer: TGLVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FTPos[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TTGLFile3DSPositionAnimationKeys.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- inherited;
- SetLength(FTPos, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FTPos[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TGLFile3DSSpotLightCutOffAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList;
- const AData: Pointer);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FFall, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FFall[I] := PSingleList(AData)[I];
- end;
- procedure TGLFile3DSSpotLightCutOffAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.SpotLightCutOff := DataTransf.SpotLightCutOff + InterpolateValue(FFall, AFrame);
- end;
- procedure TGLFile3DSSpotLightCutOffAnimationKeys.Assign(Source: TPersistent);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FFall, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FFall[I] := (Source as TGLFile3DSSpotLightCutOffAnimationKeys).FFall[I];
- end;
- procedure TGLFile3DSSpotLightCutOffAnimationKeys.WriteToFiler(Writer: TGLVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FFall[0], FNumKeys * SizeOf(Single));
- end;
- procedure TGLFile3DSSpotLightCutOffAnimationKeys.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- inherited;
- SetLength(FFall, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FFall[0], FNumKeys * SizeOf(Single));
- end;
- procedure TGLFile3DSLightHotSpotAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList;
- const AData: Pointer);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FHot, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FHot[I] := PSingleList(AData)[I];
- end;
- procedure TGLFile3DSLightHotSpotAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.HotSpot := DataTransf.HotSpot + InterpolateValue(FHot, AFrame);
- end;
- procedure TGLFile3DSLightHotSpotAnimationKeys.Assign(Source: TPersistent);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FHot, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FHot[I] := (Source as TGLFile3DSLightHotSpotAnimationKeys).FHot[I];
- end;
- procedure TGLFile3DSLightHotSpotAnimationKeys.WriteToFiler(Writer: TGLVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FHot[0], FNumKeys * SizeOf(Single));
- end;
- procedure TGLFile3DSLightHotSpotAnimationKeys.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- inherited;
- SetLength(FHot, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FHot[0], FNumKeys * SizeOf(Single));
- end;
- procedure TGLFile3DSRollAnimationKeys.LoadData(const ANumKeys: Integer; const Keys: PKeyHeaderList; const AData: Pointer);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FRoll, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FRoll[I] := PSingleList(AData)[I];
- end;
- procedure TGLFile3DSRollAnimationKeys.Apply(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.Roll := DataTransf.Roll + InterpolateValue(FRoll, AFrame);
- end;
- procedure TGLFile3DSRollAnimationKeys.Assign(Source: TPersistent);
- var
- I: Integer;
- begin
- inherited;
- SetLength(FRoll, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FRoll[I] := (Source as TGLFile3DSRollAnimationKeys).FRoll[I];
- end;
- procedure TGLFile3DSRollAnimationKeys.WriteToFiler(Writer: TGLVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FRoll[0], FNumKeys * SizeOf(Single));
- end;
- procedure TGLFile3DSRollAnimationKeys.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- inherited;
- SetLength(FRoll, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FRoll[0], FNumKeys * SizeOf(Single));
- end;
- procedure TGLFile3DSAnimationKeyList.AddKeys(const AItem: TGLFile3DSAnimationKeys);
- var
- ind: Integer;
- begin
- if AItem = nil then
- Exit;
- ind := Length(FAnimKeysList);
- SetLength(FAnimKeysList, ind + 1);
- FAnimKeysList[ind] := AItem;
- end;
- procedure TGLFile3DSAnimationKeyList.ApplyAnimKeys(var DataTransf: TGLFile3DSAnimationData; const AFrame: real);
- var
- I: Integer;
- begin
- for I := 0 to Length(FAnimKeysList) - 1 do
- FAnimKeysList[I].Apply(DataTransf, AFrame);
- end;
- procedure TGLFile3DSAnimationKeyList.ClearKeys;
- var
- I: Integer;
- begin
- for I := 0 to Length(FAnimKeysList) - 1 do
- FAnimKeysList[I].Free;
- SetLength(FAnimKeysList, 0);
- end;
- procedure TGLFile3DSAnimationKeyList.Assign(Source: TPersistent);
- var
- I: Integer;
- item: TGLFile3DSAnimationKeys;
- begin
- if Source is TGLFile3DSAnimationKeyList then
- begin
- ClearKeys;
- for I := 0 to Length(TGLFile3DSAnimationKeyList(Source).FAnimKeysList) - 1 do
- begin
- item := (TGLFile3DSAnimationKeyList(Source).FAnimKeysList[I].ClassType.Create as TGLFile3DSAnimationKeys);
- item.Assign(TGLFile3DSAnimationKeyList(Source).FAnimKeysList[I]);
- AddKeys(item);
- end;
- end
- else
- inherited Assign(Source);
- end;
- procedure TGLFile3DSAnimationKeyList.WriteToFiler(Writer: TGLVirtualWriter);
- var
- I: Integer;
- Val: TGLFile3DSAnimKeysClassType;
- begin
- Writer.WriteInteger(Length(FAnimKeysList));
- for I := 0 to Length(FAnimKeysList) - 1 do
- begin
- Val := ClassToAnimKeysClassType(FAnimKeysList[I].ClassType);
- Writer.Write(Val, SizeOf(Val));
- FAnimKeysList[I].WriteToFiler(Writer);
- end;
- end;
- procedure TGLFile3DSAnimationKeyList.ReadFromFiler(Reader: TGLVirtualReader);
- var
- I, cnt: Integer;
- Val: TGLFile3DSAnimKeysClassType;
- begin
- ClearKeys;
- cnt := Reader.ReadInteger;
- SetLength(FAnimKeysList, cnt);
- for I := 0 to Length(FAnimKeysList) - 1 do
- begin
- Reader.Read(Val, SizeOf(Val));
- FAnimKeysList[I] := AnimKeysClassTypeToClass(Val).Create as TGLFile3DSAnimationKeys;
- FAnimKeysList[I].ReadFromFiler(Reader);
- end;
- end;
- destructor TGLFile3DSAnimationKeyList.Destroy;
- begin
- ClearKeys;
- inherited Destroy;
- end;
- constructor TGLFile3DSDummyObject.Create;
- begin
- inherited;
- FAnimList := TGLFile3DSAnimationKeyList.Create;
- FRefTranf.ModelMatrix := IdentityHmgMatrix;
- FAnimTransf.ModelMatrix := IdentityHmgMatrix;
- FStatic := False;
- end;
- procedure TGLFile3DSDummyObject.LoadAnimation(const AData: Pointer);
- begin
- FAnimList.ClearKeys;
- FAnimData := AData;
- end;
- procedure TGLFile3DSDummyObject.SetFrame(const AFrame: real);
- var
- p: TGLFile3DSDummyObject;
- lAnimationData: TGLFile3DSAnimationData;
- begin
- if not vGLFile3DS_EnableAnimation then
- Exit;
- if (FParentName <> '') then
- begin
- FParent := Owner.FindMeshByName(string(FParentName)) as TGLFile3DSDummyObject;
- FParentName := '';
- end;
- lAnimationData := FRefTranf;
- p := self;
- while p <> nil do
- begin
- p.FAnimList.ApplyAnimKeys(lAnimationData, AFrame);
- p := p.FParent;
- end;
- FAnimTransf := lAnimationData;
- end;
- procedure TGLFile3DSDummyObject.MorphTo(morphTargetIndex: Integer);
- begin
- SetFrame(morphTargetIndex);
- end;
- procedure TGLFile3DSDummyObject.Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single);
- begin
- if (Owner.Owner is TGLActor) and ((Owner.Owner as TGLActor).AnimationMode in [aamBounceBackward, aamLoopBackward]) then
- SetFrame(morphTargetIndex1 - lerpFactor)
- else
- SetFrame(morphTargetIndex1 + lerpFactor);
- end;
- procedure TGLFile3DSDummyObject.Assign(Source: TPersistent);
- begin
- inherited; // Assign all published properties here.
- if Source is TGLFile3DSDummyObject then
- begin
- FRefTranf := (Source as TGLFile3DSDummyObject).FRefTranf;
- FParent := (Source as TGLFile3DSDummyObject).FParent;
- FAnimList.Assign((Source as TGLFile3DSDummyObject).FAnimList);
- SetFrame(0);
- end;
- end;
- procedure TGLFile3DSDummyObject.GetExtents(out min, max: TAffineVector);
- begin
- inherited GetExtents(min, max);
- if not FStatic then
- begin
- if not IsInfinite(min.X) then
- min := VectorTransform(min, FAnimTransf.ModelMatrix);
- if not IsInfinite(max.X) then
- max := VectorTransform(max, FAnimTransf.ModelMatrix);
- end;
- end;
- function TGLFile3DSDummyObject.ExtractTriangles(texCoords, normals: TGLAffineVectorList): TGLAffineVectorList;
- var
- I: Integer;
- begin
- Result := inherited ExtractTriangles(texCoords, normals);
- if not FStatic then
- begin
- if (Result.Count <> 0) and not MatrixEquals(FAnimTransf.ModelMatrix, IdentityHmgMatrix) then
- for I := 0 to Result.Count - 1 do
- Result[I] := VectorTransform(Result[I], FAnimTransf.ModelMatrix);
- end;
- end;
- procedure TGLFile3DSDummyObject.WriteToFiler(Writer: TGLVirtualWriter);
- var
- str: string;
- begin
- inherited;
- Writer.Write(FRefTranf, SizeOf(FRefTranf));
- if FParent <> nil then
- str := Copy(FParent.Name, 1, 32)
- else
- str := 'nil';
- Writer.WriteString(str);
- FAnimList.WriteToFiler(Writer);
- end;
- procedure TGLFile3DSDummyObject.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- inherited;
- Reader.Read(FRefTranf, SizeOf(FRefTranf));
- FParentName := String64(Copy(Reader.ReadString, 1, 64));
- if FParentName = 'nil' then
- FParentName := '';
- FAnimList.ReadFromFiler(Reader);
- end;
- destructor TGLFile3DSDummyObject.Destroy;
- begin
- FAnimList.Free;
- inherited;
- end;
- procedure TGLFile3DSMeshObject.LoadAnimation(const AData: Pointer);
- var
- aScale: TGLFile3DSScaleAnimationKeys;
- aRot: TGLFile3DSRotationAnimationKeys;
- aPos: TGLFile3DSPositionAnimationKeys;
- Mat : TGLMatrix;
- RotMat : TGLMatrix;
- AffVect : TAffineVector;
- begin
- inherited;
- with PKFMesh3DS(AData)^, FAnimList do
- begin
- aScale := TGLFile3DSScaleAnimationKeys.Create;
- aScale.LoadData(NSKeys, SKeys, Scale);
- AddKeys(aScale);
- aRot := TGLFile3DSRotationAnimationKeys.Create;
- aRot.LoadData(NRKeys, RKeys, Rot);
- AddKeys(aRot);
- aPos := TGLFile3DSPositionAnimationKeys.Create;
- aPos.LoadData(NPKeys, PKeys, Pos);
- AddKeys(aPos);
- if ParentStr <> '' then
- FParent := TGLFile3DSDummyObject(Owner.FindMeshByName(string(ParentStr)));
- with FRefTranf do
- begin
- if vGLFile3DS_FixDefaultUpAxisY then
- begin
- RotMat := CreateRotationMatrixX(cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
- InvertMatrix(RotMat);
- Mat := ModelMatrix;
- ModelMatrix := MatrixMultiply(Mat, RotMat);
- AffVect.X := Pivot.X;
- AffVect.Y := Pivot.Y;
- AffVect.Z := Pivot.Z;
- AffVect := VectorRotateAroundX(AffVect, cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
- Pivot.X := AffVect.X;
- Pivot.Y := AffVect.Y;
- Pivot.Z := AffVect.Z;
- end;
- ModelMatrix.W.X := ModelMatrix.W.X - Pivot.X;
- ModelMatrix.W.Y := ModelMatrix.W.Y - Pivot.Y;
- ModelMatrix.W.Z := ModelMatrix.W.Z - Pivot.Z;
- end;
- end;
- if vGLFile3DS_LoadedStaticFrame = -1 then
- SetFrame(CGLFILE3DS_DEFAULT_FRAME)
- else
- SetFrame(vGLFile3DS_LoadedStaticFrame);
- end;
- procedure TGLFile3DSMeshObject.BuildList(var ARci: TGLRenderContextInfo);
- begin
- gl.PushMatrix;
- if not FStatic then
- gl.MultMatrixf(@FAnimTransf.ModelMatrix);
- inherited;
- gl.PopMatrix;
- end;
- constructor TGLFile3DSOmniLightObject.Create;
- begin
- inherited;
- FLightSrc := TGLFile3DSLight.Create(nil);
- end;
- procedure TGLFile3DSOmniLightObject.LoadData(const AOwner: TGLBaseMesh; const AData: PLight3DS);
- begin
- FLightSrc.Parent := AOwner;
- FLightSrc.LightStyle := lsOmni;
- FLightSrc.Name := string(AData.NameStr);
- Name := string(AData.NameStr);
- FLightSrc.Position.SetPoint(PAffineVector(@AData.Pos)^);
- FLightSrc.Diffuse.Color := VectorMake(AData.Color.R, AData.Color.G, AData.Color.B);
- FLightSrc.Specular.Color := VectorMake(AData.Color.R, AData.Color.G, AData.Color.B);
- FLightSrc.Diffuse.Color := VectorScale(FLightSrc.Diffuse.Color, AData.Multiplier);
- FLightSrc.Shining := not AData.DLOff;
- FLightSrc.Multipler := AData.Multiplier;
- FLightSrc.ConstAttenuation := 1;
- FLightSrc.LinearAttenuation := 0;
- FLightSrc.QuadraticAttenuation := 0;
- end;
- procedure TGLFile3DSOmniLightObject.LoadAnimation(const AData: Pointer);
- var
- aPos: TGLFile3DSPositionAnimationKeys;
- aCol: TGLFile3DSColorAnimationKeys;
- begin
- inherited;
- with PKFOmni3DS(AData)^, FAnimList do
- begin
- aPos := TGLFile3DSPositionAnimationKeys.Create;
- aPos.LoadData(NPKeys, PKeys, Pos);
- AddKeys(aPos);
- aCol := TGLFile3DSColorAnimationKeys.Create;
- aCol.LoadData(NCKeys, CKeys, Color);
- AddKeys(aCol);
- if Parent <> '' then
- FParent := TGLFile3DSDummyObject(Owner.FindMeshByName(string(Parent)));
- end;
- if vGLFile3DS_LoadedStaticFrame = -1 then
- SetFrame(CGLFILE3DS_DEFAULT_FRAME)
- else
- SetFrame(vGLFile3DS_LoadedStaticFrame);
- end;
- procedure TGLFile3DSOmniLightObject.SetFrame(const AFrame: real);
- var
- obj: TComponent;
- begin
- if FLightSrcName <> '' then
- begin
- obj := Owner.Owner.FindChild(string(FLightSrcName), True);
- if obj is TGLFile3DSLight then
- begin
- FLightSrc.Free;
- FLightSrc := obj as TGLFile3DSLight;
- end;
- FLightSrcName := '';
- end;
- inherited;
- FLightSrc.Position.SetPoint(FAnimTransf.ModelMatrix.V[3]);
- FLightSrc.Diffuse.Color := FAnimTransf.Color;
- end;
- procedure TGLFile3DSOmniLightObject.Assign(Source: TPersistent);
- begin
- inherited;
- if Source is TGLFile3DSOmniLightObject then
- FLightSrc.Assign((Source as TGLFile3DSOmniLightObject).FLightSrc);
- end;
- procedure TGLFile3DSOmniLightObject.WriteToFiler(Writer: TGLVirtualWriter);
- var
- str: string;
- begin
- inherited;
- if FLightSrc.Name = '' then
- str := 'nil'
- else
- str := Copy(FLightSrc.Name, 1, 64);
- Writer.WriteString(str);
- end;
- procedure TGLFile3DSOmniLightObject.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- inherited;
- FLightSrcName := String64(Copy(Reader.ReadString, 1, 64));
- if FLightSrcName = 'nil' then
- FLightSrcName := '';
- end;
- destructor TGLFile3DSOmniLightObject.Destroy;
- begin
- FLightSrc.Free;
- inherited;
- end;
- procedure TGLFile3DSSpotLightObject.LoadData(const AOwner: TGLBaseMesh; const AData: PLight3DS);
- begin
- inherited;
- FLightSrc.LightStyle := lsSpot;
- FLightSrc.SpotTargetPos.SetPoint(TAffineVector(AData.Spot.Target));
- FLightSrc.SpotCutOff := AData.Spot.FallOff / 2;
- FLightSrc.HotSpot := AData.Spot.HotSpot / 2;
- end;
- procedure TGLFile3DSSpotLightObject.LoadAnimation(const AData: Pointer);
- var
- aTPos: TTGLFile3DSPositionAnimationKeys;
- aFall: TGLFile3DSSpotLightCutOffAnimationKeys;
- aHot: TGLFile3DSLightHotSpotAnimationKeys;
- begin
- inherited;
- with PKFSpot3DS(AData)^, FAnimList do
- begin
- aTPos := TTGLFile3DSPositionAnimationKeys.Create;
- aTPos.LoadData(NTKeys, TKeys, TPos);
- AddKeys(aTPos);
- aFall := TGLFile3DSSpotLightCutOffAnimationKeys.Create;
- aFall.LoadData(NFKeys, FKeys, Fall);
- AddKeys(aFall);
- aHot := TGLFile3DSLightHotSpotAnimationKeys.Create;
- aHot.LoadData(NHKeys, HKeys, Hot);
- AddKeys(aHot);
- if Parent <> '' then
- FParent := TGLFile3DSDummyObject(Owner.FindMeshByName(string(Parent)));
- end;
- if vGLFile3DS_LoadedStaticFrame = -1 then
- SetFrame(CGLFILE3DS_DEFAULT_FRAME)
- else
- SetFrame(vGLFile3DS_LoadedStaticFrame);
- end;
- procedure TGLFile3DSSpotLightObject.SetFrame(const AFrame: real);
- begin
- inherited;
- FLightSrc.SpotTargetPos.SetPoint(FAnimTransf.TargetPos);
- FLightSrc.SpotCutOff := FAnimTransf.SpotLightCutOff / 2;
- FLightSrc.HotSpot := FAnimTransf.HotSpot / 2;
- end;
- constructor TGLFile3DSCameraObject.Create;
- begin
- inherited;
- FCameraSrc := TGLFile3DSCamera.Create(nil);
- FTargetObj := TGLDummyCube.Create(nil);
- FCameraSrc.TargetObject := FTargetObj;
- end;
- procedure TGLFile3DSCameraObject.LoadData(Owner: TGLBaseMesh; AData: PCamera3DS);
- begin
- FCameraSrc.Parent := Owner;
- FTargetObj.Parent := Owner;
- FCameraSrc.Name := string(AData.NameStr);
- Name := string(AData.NameStr);
- FCameraSrc.Position.AsAffineVector := TAffineVector(AData.Position);
- FTargetObj.Position.SetPoint(TAffineVector(AData.Target));
- FCameraSrc.RollAngle := AData.Roll;
- FCameraSrc.FocalLength := AData.FOV;
- end;
- procedure TGLFile3DSCameraObject.LoadAnimation(const AData: Pointer);
- var
- aPos: TGLFile3DSPositionAnimationKeys;
- aRoll: TGLFile3DSRollAnimationKeys;
- aTPos: TTGLFile3DSPositionAnimationKeys;
- begin
- inherited;
- with PKFCamera3DS(AData)^, FAnimList do
- begin
- aPos := TGLFile3DSPositionAnimationKeys.Create;
- aPos.LoadData(NPKeys, PKeys, Pos);
- AddKeys(aPos);
- aRoll := TGLFile3DSRollAnimationKeys.Create;
- aRoll.LoadData(NRKeys, RKeys, Roll);
- AddKeys(aRoll);
- aTPos := TTGLFile3DSPositionAnimationKeys.Create;
- aTPos.LoadData(NTKeys, TKeys, TPos);
- AddKeys(aTPos);
- end;
- if vGLFile3DS_LoadedStaticFrame = -1 then
- SetFrame(CGLFILE3DS_DEFAULT_FRAME)
- else
- SetFrame(vGLFile3DS_LoadedStaticFrame);
- end;
- procedure TGLFile3DSCameraObject.SetFrame(const AFrame: real);
- var
- obj: TComponent;
- begin
- inherited;
- if FCameraSrcName <> '' then
- begin
- obj := Owner.Owner.FindChild(string(FCameraSrcName), True);
- if obj is TGLFile3DSCamera then
- begin
- FCameraSrc.Free;
- FCameraSrc := obj as TGLFile3DSCamera;
- end;
- FCameraSrcName := '';
- end;
- FCameraSrc.Position.SetPoint(FAnimTransf.ModelMatrix.W);
- FCameraSrc.RollAngle := FAnimTransf.Roll;
- FTargetObj.Position.SetPoint(FAnimTransf.TargetPos);
- end;
- procedure TGLFile3DSCameraObject.WriteToFiler(Writer: TGLVirtualWriter);
- var
- str: string;
- begin
- inherited;
- if FCameraSrc.Name = '' then
- str := 'nil'
- else
- str := Copy(FCameraSrc.Name, 1, 64);
- Writer.WriteString(str);
- end;
- procedure TGLFile3DSCameraObject.ReadFromFiler(Reader: TGLVirtualReader);
- begin
- inherited;
- FCameraSrcName := String64(Copy(Reader.ReadString, 1, 64));
- if FCameraSrcName = 'nil' then
- FCameraSrcName := '';
- end;
- destructor TGLFile3DSCameraObject.Destroy;
- begin
- FCameraSrc.Free;
- FTargetObj.Free;
- inherited;
- end;
- // ------------------
- // ------------------ TGL3DSVectorFile ------------------
- // ------------------
- class function TGL3DSVectorFile.Capabilities: TGLDataFileCapabilities;
- begin
- Result := [dfcRead];
- end;
- procedure TGL3DSVectorFile.LoadFromStream(aStream: TStream);
- type
- TSmoothIndexEntry = array[0..31] of cardinal;
- PSmoothIndexArray = ^TSmoothIndexArray;
- TSmoothIndexArray = array[0..MaxInt shr 8] of TSmoothIndexEntry;
- var
- Marker: PByteArray;
- CurrentVertexCount: Integer;
- SmoothIndices: PSmoothIndexArray;
- mesh: TGLFile3DSMeshObject;
- hasLightmap: Boolean;
- // --------------- local functions -------------------------------------------
- function GetOrAllocateMaterial(materials: TMaterialList; const Name: string): string;
- var
- material: PMaterial3DS;
- specColor: TGLVector;
- matLib: TGLMaterialLibrary;
- libMat, SecondMaterial: TGLLibMaterial;
- begin
- material := Materials.MaterialByName[Name];
- Assert(Assigned(material));
- if GetOwner is TGLBaseMesh then
- begin
- matLib := TGLBaseMesh(GetOwner).MaterialLibrary;
- if Assigned(matLib) then
- begin
- Result := Name;
- libMat := matLib.Materials.GetLibMaterialByName(Name);
- if not Assigned(libMat) then
- begin
- libMat := matLib.Materials.Add;
- libMat.Name := Name;
- with libMat.Material.FrontProperties do
- begin
- Ambient.Color := VectorMake(material.Ambient.R, material.Ambient.G, material.Ambient.B, 1);
- // Material transparency can be stored as a positive or negative value.
- Diffuse.Color := VectorMake(material.Diffuse.R, material.Diffuse.G, material.Diffuse.B,
- 1 - Abs(material.Transparency));
- specColor := VectorMake(material.Specular.R, material.Specular.G, material.Specular.B, 1);
- Specular.Color := VectorScale(specColor, material.ShinStrength);
- Shininess := MaxInteger(0, Integer(round((material.Shininess) * 128)));
- if material.Transparency <> 0 then
- libMat.material.BlendingMode := bmTransparency;
- end;
- if Trim(string(material.Texture.Map.NameStr)) <> '' then
- try
- if vGLFile3DS_UseTextureEx then
- with libMat.material.TextureEx.Add do
- begin
- Texture.Image.LoadFromFile(string(material.Texture.Map.NameStr));
- Texture.Disabled := False;
- Texture.TextureMode := tmModulate;
- TextureIndex := 0;
- with material.Texture.Map do
- begin
- TextureScale.SetPoint(UScale, VScale, 0);
- TextureOffset.SetPoint((1 - frac(UOffset)) * UScale, (frac(VOffset)) * VScale, 0);
- end;
- end
- else
- with libMat.Material.Texture do
- begin
- Image.LoadFromFile(string(material.Texture.Map.NameStr));
- Disabled := False;
- TextureMode := tmModulate;
- end
- except
- on E: ETexture do
- begin
- if not Owner.IgnoreMissingTextures then
- raise EGLFile3DS.CreateFmt(str3DSMapNotFound, ['diffuse', E.Message, matLib.TexturePaths]);
- end
- else
- raise;
- end;
- if Trim(string(material.Opacity.Map.NameStr)) <> '' then
- try
- if vGLFile3DS_UseTextureEx then
- with libMat.Material.TextureEx.Add do
- begin
- libMat.Material.BlendingMode := bmTransparency;
- Texture.ImageAlpha := tiaAlphaFromIntensity;
- Texture.TextureMode := tmModulate;
- Texture.Image.LoadFromFile(string(material.Opacity.Map.NameStr));
- Texture.Disabled := False;
- TextureIndex := 1;
- with material.Opacity.Map do
- begin
- TextureScale.SetPoint(UScale, VScale, 0);
- TextureOffset.SetPoint((1 - frac(UOffset)) * UScale, (frac(VOffset)) * VScale, 0);
- end;
- end
- else
- with libMat.Material.Texture do
- begin
- SecondMaterial := matLib.Materials.Add;
- SecondMaterial.material.Texture.Image.LoadFromFile(string(material.Opacity.Map.NameStr));
- SecondMaterial.Material.Texture.Disabled := False;
- SecondMaterial.Material.Texture.ImageAlpha := tiaAlphaFromIntensity;
- SecondMaterial.Material.Texture.TextureMode := tmModulate;
- SecondMaterial.Name := string(material.Opacity.Map.NameStr);
- LibMat.Texture2Name := SecondMaterial.Name;
- Disabled := False;
- end;
- except
- on E: ETexture do
- begin
- if not Owner.IgnoreMissingTextures then
- raise EGLFile3DS.CreateFmt(str3DSMapNotFound, ['opacity', E.Message, matLib.TexturePaths]);
- end
- else
- raise;
- end;
- if Trim(string(material.Bump.Map.NameStr)) <> '' then
- try
- if vGLFile3DS_UseTextureEx then
- with libMat.Material.TextureEx.Add do
- begin
- Texture.Image.LoadFromFile(string(material.Bump.Map.NameStr));
- Texture.Disabled := False;
- Texture.TextureMode := tmModulate;
- // You need a hight map for this parameter (like in 3d Max).
- // Texture.TextureFormat := tfNormalMap;
- TextureIndex := 2;
- with material.Bump.Map do
- begin
- TextureScale.SetPoint(UScale, VScale, 0);
- TextureOffset.SetPoint((1 - frac(UOffset)) * UScale, (frac(VOffset)) * VScale, 0);
- end;
- end
- else
- with libMat.Material.Texture do
- begin
- SecondMaterial := matLib.materials.Add;
- SecondMaterial.material.Texture.Image.LoadFromFile(string(material.Bump.Map.NameStr));
- SecondMaterial.material.Texture.Disabled := False;
- SecondMaterial.material.Texture.ImageAlpha := tiaAlphaFromIntensity;
- SecondMaterial.material.Texture.TextureMode := tmModulate;
- SecondMaterial.Name := string(material.Opacity.Map.NameStr);
- Disabled := False;
- end;
- except
- on E: ETexture do
- begin
- if not Owner.IgnoreMissingTextures then
- raise EGLFile3DS.CreateFmt(str3DSMapNotFound, ['bump', E.Message, matLib.TexturePaths]);
- end
- else
- raise;
- end;
- end;
- end
- else
- Result := '';
- end
- else
- Result := '';
- end;
- function GetOrAllocateLightMap(materials: TMaterialList; const Name: string): Integer;
- var
- material: PMaterial3DS;
- matLib: TGLMaterialLibrary;
- libMat: TGLLibMaterial;
- begin
- Result := -1;
- material := Materials.MaterialByName[Name];
- Assert(Assigned(material));
- if GetOwner is TGLBaseMesh then
- begin
- matLib := TGLBaseMesh(GetOwner).LightmapLibrary;
- if Assigned(matLib) then
- begin
- if Trim(string(material.IllumMap.Map.NameStr)) <> '' then
- begin
- libMat := matLib.materials.GetLibMaterialByName(string(material.IllumMap.Map.NameStr));
- if not Assigned(libMat) then
- begin
- libMat := matLib.Materials.Add;
- libMat.Name := string(material.IllumMap.Map.NameStr);
- try
- with libMat.Material.Texture do
- begin
- Image.LoadFromFile(string(material.IllumMap.Map.NameStr));
- Disabled := False;
- TextureMode := tmModulate;
- end;
- except
- on E: ETexture do
- begin
- if not Owner.IgnoreMissingTextures then
- raise EGLFile3DS.CreateFmt(str3DSMapNotFound, ['light', E.Message, matLib.TexturePaths]);
- end
- else
- raise;
- end;
- end;
- Result := libMat.Index;
- hasLightMap := True;
- end;
- end;
- end;
- end;
- // ----------------------------------------------------------------------
- function InvertMeshMatrix(Objects: TObjectList; const Name: string): TGLMatrix;
- // constructs a 4x4 matrix from 3x4 local mesh matrix given by Name and
- // inverts it so it can be used for the keyframer stuff
- var
- I, Index: Integer;
- boolY: Boolean;
- m: TGLMatrix;
- v4: TGLVector;
- factor: Single;
- begin
- with Objects do
- begin
- Index := -1;
- for I := 0 to MeshCount - 1 do
- if CompareText(string(Mesh[I].NameStr), Name) = 0 then
- begin
- Index := I;
- Break;
- end;
- if Index > -1 then
- begin
- with Mesh[Index]^ do
- begin
- Result.X.X := LocMatrix[0];
- Result.X.Y := LocMatrix[1];
- Result.X.Z := LocMatrix[2];
- Result.X.W := 0;
- Result.Y.X := LocMatrix[3];
- Result.Y.Y := LocMatrix[4];
- Result.Y.Z := LocMatrix[5];
- Result.Y.W := 0;
- Result.Z.X := LocMatrix[6];
- Result.Z.Y := LocMatrix[7];
- Result.Z.Z := LocMatrix[8];
- Result.Z.W := 0;
- Result.W.X := LocMatrix[9];
- Result.W.Y := LocMatrix[10];
- Result.W.Z := LocMatrix[11];
- Result.W.W := 1;
- end;
- InvertMatrix(Result);
- // If the matrix is not normalized, ie the third column is not equal to the vector product of the first two columns,
- // it means that it is necessary to turn to-pi around the axis Y.
- m := Result;
- v4 := m.W;
- factor := VectorLength(m.X);
- NormalizeMatrix(m);
- ScaleMatrix(m, factor);
- m.W := v4;
- v4 := VectorAbs(VectorSubtract(Result.Z, m.Z));
- boolY := (v4.X > abs(Result.Z.X)) and
- (v4.Y > abs(Result.Z.Y)) and
- (v4.Z > abs(Result.Z.Z));
- if boolY then
- Result := MatrixMultiply(Result, CreateRotationMatrix(AffineVectorMake(0, 1, 0), -PI));
- end
- else
- Result := IdentityHmgMatrix;
- end;
- end;
- // ----------------------------------------------------------------------
- function IsVertexMarked(p: PByteArray; Index: word): Boolean; inline;
- // tests the Index-th bit, returns True if set else False
- var
- mi: word;
- begin
- DivMod(index, 8, mi, index);
- Result := (((p^[mi] shr Index) and 1) = 1);
- end;
- // ---------------------------------------------------------------------------
- function MarkVertex(p: PByteArray; Index: word): Boolean; inline;
- // sets the Index-th bit and return True if it was already set else False
- var
- mi: word;
- begin
- DivMod(index, 8, mi, index);
- Result := (((p^[mi] shr Index) and 1) = 1);
- if not(Result) then
- p^[mi] := p^[mi] or (1 shl index);
- end;
- // ---------------------------------------------------------------------------
- // Stores new vertex index (NewIndex) into the smooth index array of vertex ThisIndex
- // using field SmoothingGroup, which must not be 0.
- // For each vertex in the vertex array (also for duplicated vertices) an array of 32 cardinals
- // is maintained (each for one possible smoothing group. If a vertex must be duplicated because
- // it has no smoothing group or a different one then the index of the newly created vertex is
- // stored in the SmoothIndices to avoid loosing the conjunction between not yet processed vertices
- // and duplicated vertices.
- // Note: Only one smoothing must be assigned per vertex. Some available models break this rule and
- // have more than one group assigned to a face. To make the code fail safe the group ID
- // is scanned for the lowest bit set.
- procedure StoreSmoothIndex(ThisIndex, SmoothingGroup, NewIndex: cardinal; p: PSmoothIndexArray);
- var
- I: word;
- begin
- I := 0;
- while SmoothingGroup and (1 shl I) = 0 do
- Inc(I);
- p^[ThisIndex, I] := NewIndex;
- end;
- // ---------------------------------------------------------------------------
- function GetSmoothIndex(ThisIndex, SmoothingGroup: cardinal; p: PSmoothIndexArray): Integer; inline;
- // Retrieves the vertex index for the given index and smoothing group.
- // This redirection is necessary because a vertex might have been duplicated.
- var
- I: word;
- begin
- I := 0;
- while SmoothingGroup and (1 shl I) = 0 do
- Inc(I);
- Result := Integer(p^[ThisIndex, I]);
- end;
- // ---------------------------------------------------------------------------
- procedure DuplicateVertex(Index: Integer);
- // extends the vector and normal array by one entry and duplicates the vertex AData given by Index
- // the marker and texture arrays will be extended too, if necessary
- begin
- // enhance vertex array
- with mesh.Vertices do
- Add(Items[index]);
- mesh.Normals.Add(NullVector);
- // enhance smooth index array
- ReallocMem(SmoothIndices, (CurrentVertexCount + 1) * SizeOf(TSmoothIndexEntry));
- FillChar(SmoothIndices[CurrentVertexCount], SizeOf(TSmoothIndexEntry), $FF);
- // enhance marker array
- if (CurrentVertexCount div 8) <> ((CurrentVertexCount + 1) div 8) then
- begin
- ReallocMem(Marker, ((CurrentVertexCount + 1) div 8) + 1);
- Marker[(CurrentVertexCount div 8) + 1] := 0;
- end;
- with mesh.texCoords do
- if Count > 0 then
- Add(Items[index]);
- Inc(CurrentVertexCount);
- end;
- // ---------------------------------------------------------------------------
- function FindMotionIndex(KeyFramer: TKeyFramer; const ObjectName: AnsiString): Integer;
- // Looks through the motion list for the object "ObjectName" and returns its index
- // or -1 if the name is not it the list
- var
- I: Integer;
- begin
- Result := -1;
- with KeyFramer do
- for I := 0 to MeshMotionCount - 1 do
- if CompareText(string(MeshMotion[I].NameStr), string(ObjectName)) = 0 then
- begin
- Result := I;
- Break;
- end;
- end;
- // --------------- end local functions ---------------------------------------
- var
- CurrentMotionIndex, iMaterial, I, j, X: Integer;
- aFaceGroup: TFGVertexIndexList;
- Face, Vertex, TargetVertex: Integer;
- SmoothingGroup: cardinal;
- CurrentIndex: word;
- Vector1, Vector2, Normal: TAffineVector;
- standardNormalsOrientation: Boolean;
- lights_mesh: TGLFile3DSOmniLightObject;
- camera_mesh: TGLFile3DSCameraObject;
- basemesh: TGLBaseMesh;
- begin
- with TFile3DS.Create do
- try
- LoadFromStream(aStream);
- // determine front face winding
- { TODO : better face winding }
- standardNormalsOrientation := not(NormalsOrientation = mnoDefault);
- for i := 0 to Objects.MeshCount - 1 do
- with PMesh3DS(Objects.Mesh[I])^ do
- begin
- hasLightMap := False;
- mesh := TGLFile3DSMeshObject.CreateOwned(Owner.MeshObjects);
- mesh.Name := string(PMesh3DS(Objects.Mesh[I])^.NameStr);
- //dummy targets
- for x := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
- TGLMeshMorphTarget.CreateOwned(mesh.MorphTargets);
- with mesh do
- begin
- Mode := momFaceGroups;
- // make a copy of the vertex data, this must always be available
- Vertices.Capacity := NVertices;
- Normals.AddNulls(NVertices);
- if NTextVerts > 0 then
- begin
- TexCoords.Capacity := NVertices;
- for j := 0 to NVertices - 1 do
- begin
- Vertices.Add(PAffineVector(@VertexArray[j])^);
- TexCoords.Add(PTexPoint(@TextArray[j])^);
- end;
- end
- else
- begin
- for j := 0 to NVertices - 1 do
- Vertices.Add(PAffineVector(@VertexArray[j])^);
- end;
- end;
- // allocate memory for the smoothindices and the marker array
- CurrentVertexCount := NVertices;
- Marker := AllocMem((NVertices div 8) + 1); // one bit for each vertex
- GetMem(SmoothIndices, NVertices * SizeOf(TSmoothIndexEntry));
- if SmoothArray = nil then
- begin
- // no smoothing groups to consider
- for Face := 0 to NFaces - 1 do
- with FaceArray^[Face] do
- begin
- // normal vector for the face
- with mesh.Vertices do
- begin
- VectorSubtract(Items[V1], Items[V2], Vector1);
- VectorSubtract(Items[V3], Items[V2], Vector2);
- end;
- if standardNormalsOrientation then
- Normal := VectorCrossProduct(Vector1, Vector2)
- else
- Normal := VectorCrossProduct(Vector2, Vector1);
- // go for each vertex in the current face
- for Vertex := 0 to 2 do
- begin
- // copy current index for faster access
- CurrentIndex := FaceRec[Vertex];
- // already been touched?
- if IsVertexMarked(Marker, CurrentIndex) and (CurrentVertexCount < High(FaceRec[Vertex])) then
- begin
- // already touched vertex must be duplicated
- DuplicateVertex(CurrentIndex);
- FaceRec[Vertex] := CurrentVertexCount - 1;
- mesh.Normals[CurrentVertexCount - 1] := Normal;
- end
- else
- begin
- // not yet touched, so just store the normal
- mesh.Normals[CurrentIndex] := Normal;
- MarkVertex(Marker, CurrentIndex);
- end;
- end;
- end;
- end
- else
- begin
- // smoothing groups are to be considered
- for Face := 0 to NFaces - 1 do
- with FaceArray^[Face] do
- begin
- // normal vector for the face
- with mesh.Vertices do
- begin
- VectorSubtract(Items[V1], Items[V2], Vector1);
- VectorSubtract(Items[V3], Items[V2], Vector2);
- end;
- if standardNormalsOrientation then
- Normal := VectorCrossProduct(Vector1, Vector2)
- else
- Normal := VectorCrossProduct(Vector2, Vector1);
- SmoothingGroup := SmoothArray^[Face];
- // go for each vertex in the current face
- for Vertex := 0 to 2 do
- begin
- // copy current index for faster access
- CurrentIndex := FaceRec[Vertex];
- // Has vertex already been touched?
- if IsVertexMarked(Marker, CurrentIndex) then
- begin
- // check smoothing group
- if (SmoothingGroup = 0) then
- begin
- if (CurrentVertexCount < High(FaceRec[Vertex])) then
- begin
- // no smoothing then just duplicate vertex
- DuplicateVertex(CurrentIndex);
- FaceRec[Vertex] := CurrentVertexCount - 1;
- mesh.Normals[CurrentVertexCount - 1] := Normal;
- // mark new vertex also as touched
- MarkVertex(Marker, CurrentVertexCount - 1);
- end;
- end
- else
- begin
- // this vertex must be smoothed, check if there's already
- // a (duplicated) vertex for this smoothing group
- TargetVertex := GetSmoothIndex(CurrentIndex, SmoothingGroup, SmoothIndices);
- if (TargetVertex < 0) then
- begin
- if (CurrentVertexCount < High(FaceRec[Vertex])) then
- begin
- // vertex has not yet been duplicated for this smoothing
- // group, so do it now
- DuplicateVertex(CurrentIndex);
- FaceRec[Vertex] := CurrentVertexCount - 1;
- mesh.Normals[CurrentVertexCount - 1] := Normal;
- StoreSmoothIndex(CurrentIndex, SmoothingGroup, CurrentVertexCount - 1, SmoothIndices);
- StoreSmoothIndex(CurrentVertexCount - 1, SmoothingGroup, CurrentVertexCount - 1, SmoothIndices);
- // mark new vertex also as touched
- MarkVertex(Marker, CurrentVertexCount - 1);
- end;
- end
- else
- begin
- // vertex has already been duplicated,
- // so just add normal vector to other vertex...
- mesh.Normals[TargetVertex] := VectorAdd(mesh.Normals[TargetVertex], Normal);
- // ...and tell which new vertex has to be used from now on
- FaceRec[Vertex] := TargetVertex;
- end;
- end;
- end
- else
- begin
- // vertex not yet touched, so just store the normal
- mesh.Normals[CurrentIndex] := Normal;
- // initialize smooth indices for this vertex
- FillChar(SmoothIndices[CurrentIndex], SizeOf(TSmoothIndexEntry), $FF);
- if SmoothingGroup <> 0 then
- StoreSmoothIndex(CurrentIndex, SmoothingGroup, CurrentIndex, SmoothIndices);
- MarkVertex(Marker, CurrentIndex);
- end;
- end;
- end;
- end;
- FreeMem(Marker);
- FreeMem(SmoothIndices);
- Assert(mesh.Vertices.Count = CurrentVertexCount);
- // and normalize the Normals array
- mesh.Normals.Normalize;
- // now go for each material group
- // if there's no face to material assignment then just copy the
- // face definitions and rely on the default texture of the scene object
- if (NMats = 0) or (not vGLVectorFileObjectsAllocateMaterials) then
- begin
- aFaceGroup := TFGVertexIndexList.CreateOwned(mesh.FaceGroups);
- with aFaceGroup do
- begin
- basemesh := TGLBaseMesh(Self.GetOwner);
- if basemesh.MaterialLibrary <> nil then
- MaterialName := basemesh.MaterialLibrary.Materials.Add.Name;
- // copy the face list
- for j := 0 to NFaces - 1 do
- begin
- Add(FaceArray[J].V1);
- Add(FaceArray[J].V2);
- Add(FaceArray[J].V3);
- end;
- end;
- end
- else
- begin
- for iMaterial := 0 to NMats - 1 do
- begin
- aFaceGroup := TFGVertexIndexList.CreateOwned(mesh.FaceGroups);
- with aFaceGroup do
- begin
- MaterialName := GetOrAllocateMaterial(Materials, string(MatArray[iMaterial].NameStr));
- LightMapIndex := GetOrAllocateLightMap(Materials, string(MatArray[iMaterial].NameStr));
- // copy all vertices belonging to the current face into our index array,
- // there won't be redundant vertices since this would mean a face has more than one
- // material
- // NFaces is the one from FaceGroup
- with MatArray[iMaterial] do
- for j := 0 to NFaces - 1 do
- begin
- Add(FaceArray[FaceIndex[J]].V1);
- Add(FaceArray[FaceIndex[J]].V2);
- Add(FaceArray[FaceIndex[J]].V3);
- end;
- end;
- end;
- end;
- if hasLightMap then
- for j := 0 to mesh.TexCoords.Count - 1 do
- mesh.LightMapTexCoords.Add(mesh.TexCoords[j].X, mesh.TexCoords[j].Y);
- end;
- // Adding non-mesh objects (for example, dummies).
- for I := 0 to KeyFramer.MeshMotionCount - 1 do
- if (Owner.MeshObjects.FindMeshByName(string(KeyFramer.MeshMotion[I].NameStr)) = nil) then
- begin
- mesh := TGLFile3DSMeshObject.CreateOwned(Owner.MeshObjects);
- mesh.Name := string(KeyFramer.MeshMotion[I].NameStr);
- // dummy targets
- for X := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
- TGLMeshMorphTarget.CreateOwned(mesh.MorphTargets);
- mesh.LoadAnimation(KeyFramer.MeshMotion[I]);
- end;
- for I := 0 to Objects.MeshCount - 1 do
- with PMesh3DS(Objects.Mesh[I])^ do
- begin
- mesh := Owner.MeshObjects.FindMeshByName(string(NameStr)) as TGLFile3DSMeshObject;
- with mesh, KeyFramer do
- begin
- CurrentMotionIndex := FindMotionIndex(KeyFramer, NameStr);
- FRefTranf.ModelMatrix := InvertMeshMatrix(Objects, string(NameStr));
- if MeshMotionCount > 0 then
- LoadAnimation(MeshMotion[CurrentMotionIndex]);
- end;
- end;
- // Lights Omni.
- for I := 0 to Objects.OmniLightCount - 1 do
- begin
- lights_mesh := TGLFile3DSOmniLightObject.CreateOwned(Owner.MeshObjects);
- // Dummy targets for it.
- for X := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
- TGLMeshMorphTarget.CreateOwned(lights_mesh.MorphTargets);
- lights_mesh.LoadData(Owner, Objects.OmniLight[I]);
- lights_mesh.LoadAnimation(KeyFramer.OmniLightMotion[I]);
- end;
- // Lights Spot.
- for I := 0 to Objects.SpotLightCount - 1 do
- begin
- lights_mesh := TGLFile3DSSpotLightObject.CreateOwned(Owner.MeshObjects);
- // Dummy targets for it.
- for X := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
- TGLMeshMorphTarget.CreateOwned(lights_mesh.MorphTargets);
- lights_mesh.LoadData(Owner, Objects.SpotLight[I]);
- lights_mesh.LoadAnimation(KeyFramer.SpotLightMotion[I]);
- end;
- // Camera Objects.
- for I := 0 to Objects.CameraCount - 1 do
- begin
- camera_mesh := TGLFile3DSCameraObject.CreateOwned(Owner.MeshObjects);
- // Dummy targets for it.
- for X := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
- TGLMeshMorphTarget.CreateOwned(camera_mesh.MorphTargets);
- camera_mesh.LoadData(Owner, Objects.Camera[I]);
- camera_mesh.LoadAnimation(KeyFramer.CameraMotion[I]);
- end;
- // Apply animation matrix to static data
- if vGLFile3DS_LoadedStaticFrame >= 0 then
- begin
- for I := 0 to Owner.MeshObjects.Count - 1 do
- begin
- if Owner.MeshObjects[I] is TGLFile3DSMeshObject then
- begin
- mesh := Owner.MeshObjects[I] as TGLFile3DSMeshObject;
- mesh.FStatic := True;
- for j := 0 to mesh.Vertices.Count - 1 do
- mesh.Vertices[j] := VectorTransform(mesh.Vertices[j], mesh.FAnimTransf.ModelMatrix);
- end;
- end;
- end;
- finally
- Free;
- end;
- end;
- // ------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------
- RegisterClasses([TGLFile3DSDummyObject, TGLFile3DSMeshObject, TGLFile3DSOmniLightObject, TGLFile3DSSpotLightObject,
- TGLFile3DSCameraObject]);
- RegisterVectorFileFormat('3ds', '3D Studio files', TGL3DSVectorFile);
- RegisterVectorFileFormat('prj', '3D Studio project files', TGL3DSVectorFile);
- end.
|