12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.File3DS;
- (* 3DStudio 3DS vector file format implementation *)
- interface
- {$I Stage.Defines.inc}
- uses
- System.Classes,
- System.SysUtils,
- System.Math,
-
- Stage.Strings,
- Stage.OpenGL4,
- GXS.Scene,
- GXS.Objects,
- GXS.VectorFileObjects,
- GXS.Texture,
- GXS.ApplicationFileIO,
- Stage.VectorGeometry,
- GXS.Context,
- GXS.PersistentClasses,
- GXS.File3DSSceneObjects,
- Stage.VectorTypes,
- GXS.VectorLists,
- GXS.RenderContextInfo,
- GXS.Material,
- Formatx.m3DS,
- Formatx.m3DSTypes;
- type
- EGLFile3DS = class(Exception);
- // A record that holds all the information that is used during 3ds animation.
- TgxFile3DSAnimationData = packed record
- ModelMatrix: TMatrix4f;
- Color: TVector4f; // Omni Light.
- TargetPos: TAffineVector; // Spot Light.
- SpotLightCutOff: single;
- HotSpot: single;
- Roll: single;
- end;
- // An abstract class that describes how to interpolate animation keys.
- TgxFile3DSAnimationKeys = class(TgxPersistentObject)
- 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): TMatrix4f; overload;
- public
- procedure LoadData(const ANumKeys: integer; const Keys: PKeyHeaderList; const AData: Pointer); virtual;
- procedure Apply(var DataTransf: TgxFile3DSAnimationData; const AFrame: real); virtual; abstract;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- end;
- TgxFile3DSScaleAnimationKeys = class(TgxFile3DSAnimationKeys)
- private
- FScale: array of TAffineVector;
- public
- procedure LoadData(const ANumKeys: integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TgxFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- end;
- TgxFile3DSRotationAnimationKeys = class(TgxFile3DSAnimationKeys)
- private
- FRot: array of TKFRotKey3DS;
- public
- procedure LoadData(const ANumKeys: integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TgxFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- end;
- TgxFile3DSPositionAnimationKeys = class(TgxFile3DSAnimationKeys)
- private
- FPos: array of TAffineVector;
- public
- procedure LoadData(const ANumKeys: integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TgxFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- end;
- TgxFile3DSColorAnimationKeys = class(TgxFile3DSAnimationKeys)
- private
- FCol: array of TAffineVector;
- public
- procedure LoadData(const ANumKeys: integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TgxFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- end;
- TTgxFile3DSPositionAnimationKeys = class(TgxFile3DSAnimationKeys)
- private
- FTPos: array of TAffineVector;
- public
- procedure LoadData(const ANumKeys: integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TgxFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- end;
- TgxFile3DSSpotLightCutOffAnimationKeys = class(TgxFile3DSAnimationKeys)
- private
- FFall: array of single;
- public
- procedure LoadData(const ANumKeys: integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TgxFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- end;
- TgxFile3DSLightHotSpotAnimationKeys = class(TgxFile3DSAnimationKeys)
- private
- FHot: array of single;
- public
- procedure LoadData(const ANumKeys: integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TgxFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- end;
- TgxFile3DSRollAnimationKeys = class(TgxFile3DSAnimationKeys)
- private
- FRoll: array of single;
- public
- procedure LoadData(const ANumKeys: integer; const Keys: PKeyHeaderList; const AData: Pointer); override;
- procedure Apply(var DataTransf: TgxFile3DSAnimationData; const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- end;
- TgxFile3DSAnimationKeyList = class(TgxPersistentObject)
- private
- FAnimKeysList: array of TgxFile3DSAnimationKeys;
- protected
- procedure ApplyAnimKeys(var DataTransf: TgxFile3DSAnimationData; const AFrame: real);
- public
- procedure AddKeys(const AItem: TgxFile3DSAnimationKeys);
- procedure ClearKeys;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- destructor Destroy; override;
- end;
- // Used only for serialization. There probably is a more efficient way to do it.
- TgxFile3DSAnimKeysClassType = (ctScale, ctRot, ctPos, ctCol, ctTPos, ctFall, ctHot, ctRoll);
- // A 3ds-specific TgxMorphableMeshObject.
- TgxFile3DSDummyObject = class(TgxMorphableMeshObject)
- private
- FAnimList: TgxFile3DSAnimationKeyList;
- FAnimData: Pointer;
- FRefTranf, FAnimTransf: TgxFile3DSAnimationData;
- FParent: TgxFile3DSDummyObject;
- 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: TgxAffineVectorList = nil; normals: TgxAffineVectorList = nil): TgxAffineVectorList;
- override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- procedure Assign(Source: TPersistent); override;
- constructor Create; override;
- destructor Destroy; override;
- property AnimList: TgxFile3DSAnimationKeyList read FAnimList;
- property Parent: TgxFile3DSDummyObject read FParent write FParent;
- property RefrenceTransf: TgxFile3DSAnimationData read FRefTranf write FRefTranf;
- end;
- // A 3ds-specific mesh object.
- TgxFile3DSMeshObject = class(TgxFile3DSDummyObject)
- public
- procedure LoadAnimation(const AData: Pointer); override;
- procedure BuildList(var ARci: TgxRenderContextInfo); override;
- end;
- { A 3ds-specific omni light. }
- TgxFile3DSOmniLightObject = class(TgxFile3DSDummyObject)
- private
- FLightSrc: TgxFile3DSLight;
- FLightSrcName: String64;
- public
- constructor Create; override;
- procedure LoadData(const AOwner: TgxBaseMesh; const AData: PLight3DS); virtual;
- procedure LoadAnimation(const AData: Pointer); override;
- procedure SetFrame(const AFrame: real); override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- destructor Destroy; override;
- end;
- // A 3ds-specific spot light.
- TgxFile3DSSpotLightObject = class(TgxFile3DSOmniLightObject)
- public
- procedure LoadData(const AOwner: TgxBaseMesh; const AData: PLight3DS); override;
- procedure LoadAnimation(const AData: Pointer); override;
- procedure SetFrame(const AFrame: real); override;
- end;
- // A 3ds-specific camera.
- TgxFile3DSCameraObject = class(TgxFile3DSDummyObject)
- private
- FTargetObj: TgxDummyCube;
- FCameraSrc: TgxFile3DSCamera;
- FCameraSrcName: String64;
- public
- constructor Create; override;
- procedure LoadData(Owner: TgxBaseMesh; AData: PCamera3DS);
- procedure LoadAnimation(const AData: Pointer); override;
- procedure SetFrame(const AFrame: real); override;
- procedure WriteToFiler(Writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(Reader: TgxVirtualReader); override;
- destructor Destroy; override;
- end;
- (* The 3DStudio vector file.
- A 3DS file may contain material
- information and require textures when loading. *)
- Tgx3DSVectorFile = class(TgxVectorFile)
- public
- class function Capabilities: TDataFileCapabilities; 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. *)
- vFile3DS_UseTextureEx: boolean = False;
- (* If enabled, allows 3ds animation and fixes loading of some 3ds models,
- but has a few bugs:
- - TgxFreeForm.AutoCentering does now work correctly.
- - TgxMeshObject.vertices return values different from
- TgxMeshObject.ExtractTriangles() *)
- vFile3DS_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 vFile3DS_EnableAnimation = true) *)
- vFile3DS_FixDefaultUpAxisY: boolean = False;
- (* If >= 0, then the vertices list will be updated with selected frame
- animation data. (Note: you need vFile3DS_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. *)
- vFile3DS_LoadedStaticFrame: integer = -1;
- // ------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------
- const
- cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE = PI/2;
- CGLFILE3DS_DEFAULT_FRAME = 0;
- function AnimKeysClassTypeToClass(const AAnimKeysClassType: TgxFile3DSAnimKeysClassType): TClass;
- begin
- case AAnimKeysClassType of
- ctScale: Result := TgxFile3DSScaleAnimationKeys;
- ctRot: Result := TgxFile3DSRotationAnimationKeys;
- ctPos: Result := TgxFile3DSPositionAnimationKeys;
- ctCol: Result := TgxFile3DSColorAnimationKeys;
- ctTPos: Result := TTgxFile3DSPositionAnimationKeys;
- ctFall: Result := TgxFile3DSSpotLightCutOffAnimationKeys;
- ctHot: Result := TgxFile3DSLightHotSpotAnimationKeys;
- ctRoll: Result := TgxFile3DSRollAnimationKeys;
- else
- begin
- Result := nil;
- Assert(False, strErrorEx + strUnknownType);
- end;
- end;
- end;
- function ClassToAnimKeysClassType(const AAnimKeysClass: TClass): TgxFile3DSAnimKeysClassType;
- begin
- if AAnimKeysClass.InheritsFrom(TgxFile3DSScaleAnimationKeys) then
- Result := ctScale
- else if AAnimKeysClass.InheritsFrom(TgxFile3DSRotationAnimationKeys) then
- Result := ctRot
- else if AAnimKeysClass.InheritsFrom(TgxFile3DSPositionAnimationKeys) then
- Result := ctPos
- else if AAnimKeysClass.InheritsFrom(TgxFile3DSColorAnimationKeys) then
- Result := ctCol
- else if AAnimKeysClass.InheritsFrom(TTgxFile3DSPositionAnimationKeys) then
- Result := ctTPos
- else if AAnimKeysClass.InheritsFrom(TgxFile3DSSpotLightCutOffAnimationKeys) then
- Result := ctFall
- else if AAnimKeysClass.InheritsFrom(TgxFile3DSLightHotSpotAnimationKeys) then
- Result := ctHot
- else if AAnimKeysClass.InheritsFrom(TgxFile3DSRollAnimationKeys) then
- Result := ctRoll
- else
- begin
- Result := ctScale;
- Assert(False, strErrorEx + strUnknownType);
- end;
- end;
- function MakeRotationQuaternion(const axis: TAffineVector; angle: single): TQuaternion;
- var
- v: TVector4f;
- 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): TMatrix4f;
- var
- wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2: single;
- quat: TVector4f;
- m: TMatrix4f;
- 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 TgxFile3DSAnimationKeys.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 TgxFile3DSAnimationKeys.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 TgxFile3DSAnimationKeys.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 TgxFile3DSAnimationKeys.InterpolateValue(const AValues: array of TKFRotKey3DS; const AFrame: real): TMatrix4f;
- 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 TgxFile3DSAnimationKeys.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 TgxFile3DSAnimationKeys.Assign(Source: TPersistent);
- var
- I: integer;
- begin
- if Source is TgxFile3DSAnimationKeys then
- begin
- FNumKeys := TgxFile3DSAnimationKeys(Source).FNumKeys;
- SetLength(FKeys, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FKeys[I] := TgxFile3DSAnimationKeys(Source).FKeys[I];
- end
- else
- inherited Assign(Source);
- end;
- procedure TgxFile3DSAnimationKeys.WriteToFiler(Writer: TgxVirtualWriter);
- begin
- Writer.WriteInteger(FNumKeys);
- if FNumKeys > 0 then
- Writer.Write(FKeys[0], FNumKeys * SizeOf(TKeyHeader3DS));
- end;
- procedure TgxFile3DSAnimationKeys.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- FNumKeys := Reader.ReadInteger;
- SetLength(FKeys, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FKeys[0], FNumKeys * SizeOf(TKeyHeader3DS));
- end;
- procedure TgxFile3DSScaleAnimationKeys.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 vFile3DS_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 TgxFile3DSScaleAnimationKeys.Apply(var DataTransf: TgxFile3DSAnimationData;
- const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.ModelMatrix := MatrixMultiply(DataTransf.ModelMatrix,
- CreateScaleMatrix(InterpolateValue(FScale, AFrame)));
- end;
- procedure TgxFile3DSScaleAnimationKeys.Assign(Source: TPersistent);
- var
- I: integer;
- begin
- inherited;
- SetLength(FScale, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FScale[I] := (Source as TgxFile3DSScaleAnimationKeys).Fscale[I];
- end;
- procedure TgxFile3DSScaleAnimationKeys.WriteToFiler(Writer: TgxVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FScale[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TgxFile3DSScaleAnimationKeys.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- inherited;
- SetLength(FScale, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FScale[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TgxFile3DSRotationAnimationKeys.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 vFile3DS_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 TgxFile3DSRotationAnimationKeys.Apply(var DataTransf: TgxFile3DSAnimationData; const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.ModelMatrix := MatrixMultiply(DataTransf.ModelMatrix,
- InterpolateValue(FRot, AFrame));
- end;
- procedure TgxFile3DSRotationAnimationKeys.Assign(Source: TPersistent);
- var
- I: integer;
- begin
- inherited;
- SetLength(FRot, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FRot[I] := (Source as TgxFile3DSRotationAnimationKeys).FRot[I];
- end;
- procedure TgxFile3DSRotationAnimationKeys.WriteToFiler(Writer: TgxVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FRot[0], FNumKeys * SizeOf(TKFRotKey3DS));
- end;
- procedure TgxFile3DSRotationAnimationKeys.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- inherited;
- SetLength(FRot, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FRot[0], FNumKeys * SizeOf(TKFRotKey3DS));
- end;
- procedure TgxFile3DSPositionAnimationKeys.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 vFile3DS_FixDefaultUpAxisY then
- begin
- FPos[I] := VectorRotateAroundX(FPos[I], cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
- end;
- end;
- end;
- procedure TgxFile3DSPositionAnimationKeys.Apply(var DataTransf: TgxFile3DSAnimationData;
- const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.ModelMatrix.W :=
- VectorAdd(DataTransf.ModelMatrix.W, VectorMake(InterpolateValue(FPos, AFrame)));
- end;
- procedure TgxFile3DSPositionAnimationKeys.Assign(Source: TPersistent);
- var
- I: integer;
- begin
- inherited;
- SetLength(FPos, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FPos[I] := (Source as TgxFile3DSPositionAnimationKeys).FPos[I];
- end;
- procedure TgxFile3DSPositionAnimationKeys.WriteToFiler(Writer: TgxVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FPos[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TgxFile3DSPositionAnimationKeys.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- inherited;
- SetLength(FPos, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FPos[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TgxFile3DSColorAnimationKeys.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 TgxFile3DSColorAnimationKeys.Apply(var DataTransf: TgxFile3DSAnimationData;
- const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.Color := VectorAdd(DataTransf.Color,
- VectorMake(InterpolateValue(FCol, AFrame)));
- end;
- procedure TgxFile3DSColorAnimationKeys.Assign(Source: TPersistent);
- var
- I: integer;
- begin
- inherited;
- SetLength(FCol, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FCol[I] := (Source as TgxFile3DSColorAnimationKeys).FCol[I];
- end;
- procedure TgxFile3DSColorAnimationKeys.WriteToFiler(Writer: TgxVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FCol[0], FNumKeys * SizeOf(TFColor3DS));
- end;
- procedure TgxFile3DSColorAnimationKeys.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- inherited;
- SetLength(FCol, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FCol[0], FNumKeys * SizeOf(TFColor3DS));
- end;
- procedure TTgxFile3DSPositionAnimationKeys.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 vFile3DS_FixDefaultUpAxisY then
- begin
- FTPos[I] := VectorRotateAroundX(FTPos[I], cGLFILE3DS_FIXDEFAULTUPAXISY_ROTATIONVALUE);
- end;
- end;
- end;
- procedure TTgxFile3DSPositionAnimationKeys.Apply(var DataTransf: TgxFile3DSAnimationData;
- const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.TargetPos := VectorAdd(DataTransf.TargetPos,
- InterpolateValue(FTPos, AFrame));
- end;
- procedure TTgxFile3DSPositionAnimationKeys.Assign(Source: TPersistent);
- var
- I: integer;
- begin
- inherited;
- SetLength(FTPos, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FTPos[I] := (Source as TTgxFile3DSPositionAnimationKeys).FTPos[I];
- end;
- procedure TTgxFile3DSPositionAnimationKeys.WriteToFiler(Writer: TgxVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FTPos[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TTgxFile3DSPositionAnimationKeys.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- inherited;
- SetLength(FTPos, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FTPos[0], FNumKeys * SizeOf(TPoint3DS));
- end;
- procedure TgxFile3DSSpotLightCutOffAnimationKeys.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 TgxFile3DSSpotLightCutOffAnimationKeys.Apply(
- var DataTransf: TgxFile3DSAnimationData; const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.SpotLightCutOff :=
- DataTransf.SpotLightCutOff + InterpolateValue(FFall, AFrame);
- end;
- procedure TgxFile3DSSpotLightCutOffAnimationKeys.Assign(Source: TPersistent);
- var
- I: integer;
- begin
- inherited;
- SetLength(FFall, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FFall[I] := (Source as TgxFile3DSSpotLightCutOffAnimationKeys).FFall[I];
- end;
- procedure TgxFile3DSSpotLightCutOffAnimationKeys.WriteToFiler(Writer: TgxVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FFall[0], FNumKeys * SizeOf(single));
- end;
- procedure TgxFile3DSSpotLightCutOffAnimationKeys.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- inherited;
- SetLength(FFall, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FFall[0], FNumKeys * SizeOf(single));
- end;
- procedure TgxFile3DSLightHotSpotAnimationKeys.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 TgxFile3DSLightHotSpotAnimationKeys.Apply(
- var DataTransf: TgxFile3DSAnimationData; const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.HotSpot := DataTransf.HotSpot + InterpolateValue(FHot, AFrame);
- end;
- procedure TgxFile3DSLightHotSpotAnimationKeys.Assign(Source: TPersistent);
- var
- I: integer;
- begin
- inherited;
- SetLength(FHot, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FHot[I] := (Source as TgxFile3DSLightHotSpotAnimationKeys).FHot[I];
- end;
- procedure TgxFile3DSLightHotSpotAnimationKeys.WriteToFiler(Writer: TgxVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FHot[0], FNumKeys * SizeOf(single));
- end;
- procedure TgxFile3DSLightHotSpotAnimationKeys.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- inherited;
- SetLength(FHot, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FHot[0], FNumKeys * SizeOf(single));
- end;
- procedure TgxFile3DSRollAnimationKeys.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 TgxFile3DSRollAnimationKeys.Apply(var DataTransf: TgxFile3DSAnimationData;
- const AFrame: real);
- begin
- if FNumKeys > 0 then
- DataTransf.Roll := DataTransf.Roll + InterpolateValue(FRoll, AFrame);
- end;
- procedure TgxFile3DSRollAnimationKeys.Assign(Source: TPersistent);
- var
- I: integer;
- begin
- inherited;
- SetLength(FRoll, FNumKeys);
- for I := 0 to FNumKeys - 1 do
- FRoll[I] := (Source as TgxFile3DSRollAnimationKeys).FRoll[I];
- end;
- procedure TgxFile3DSRollAnimationKeys.WriteToFiler(Writer: TgxVirtualWriter);
- begin
- inherited;
- if FNumKeys > 0 then
- Writer.Write(FRoll[0], FNumKeys * SizeOf(single));
- end;
- procedure TgxFile3DSRollAnimationKeys.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- inherited;
- SetLength(FRoll, FNumKeys);
- if FNumKeys > 0 then
- Reader.Read(FRoll[0], FNumKeys * SizeOf(single));
- end;
- procedure TgxFile3DSAnimationKeyList.AddKeys(const AItem: TgxFile3DSAnimationKeys);
- var
- ind: integer;
- begin
- if AItem = nil then
- Exit;
- ind := Length(FAnimKeysList);
- SetLength(FAnimKeysList, ind + 1);
- FAnimKeysList[ind] := AItem;
- end;
- procedure TgxFile3DSAnimationKeyList.ApplyAnimKeys(
- var DataTransf: TgxFile3DSAnimationData; const AFrame: real);
- var
- I: integer;
- begin
- for I := 0 to Length(FAnimKeysList) - 1 do
- FAnimKeysList[I].Apply(DataTransf, AFrame);
- end;
- procedure TgxFile3DSAnimationKeyList.ClearKeys;
- var
- I: integer;
- begin
- for I := 0 to Length(FAnimKeysList) - 1 do
- FAnimKeysList[I].Free;
- SetLength(FAnimKeysList, 0);
- end;
- procedure TgxFile3DSAnimationKeyList.Assign(Source: TPersistent);
- var
- I: integer;
- item: TgxFile3DSAnimationKeys;
- begin
- if Source is TgxFile3DSAnimationKeyList then
- begin
- ClearKeys;
- for I := 0 to Length(TgxFile3DSAnimationKeyList(Source).FAnimKeysList) - 1 do
- begin
- item := (TgxFile3DSAnimationKeyList(Source).FAnimKeysList[I].ClassType.Create as
- TgxFile3DSAnimationKeys);
- item.Assign(TgxFile3DSAnimationKeyList(Source).FAnimKeysList[I]);
- AddKeys(item);
- end;
- end
- else
- inherited Assign(Source);
- end;
- procedure TgxFile3DSAnimationKeyList.WriteToFiler(Writer: TgxVirtualWriter);
- var
- I: integer;
- Val: TgxFile3DSAnimKeysClassType;
- 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 TgxFile3DSAnimationKeyList.ReadFromFiler(Reader: TgxVirtualReader);
- var
- I, cnt: integer;
- Val: TgxFile3DSAnimKeysClassType;
- 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 TgxFile3DSAnimationKeys;
- FAnimKeysList[I].ReadFromFiler(Reader);
- end;
- end;
- destructor TgxFile3DSAnimationKeyList.Destroy;
- begin
- ClearKeys;
- inherited Destroy;
- end;
- constructor TgxFile3DSDummyObject.Create;
- begin
- inherited;
- FAnimList := TgxFile3DSAnimationKeyList.Create;
- FRefTranf.ModelMatrix := IdentityHmgMatrix;
- FAnimTransf.ModelMatrix := IdentityHmgMatrix;
- FStatic := False;
- end;
- procedure TgxFile3DSDummyObject.LoadAnimation(const AData: Pointer);
- begin
- FAnimList.ClearKeys;
- FAnimData := AData;
- end;
- procedure TgxFile3DSDummyObject.SetFrame(const AFrame: real);
- var
- p: TgxFile3DSDummyObject;
- lAnimationData: TgxFile3DSAnimationData;
- begin
- if not vFile3DS_EnableAnimation then
- Exit;
- if (FParentName <> '') then
- begin
- FParent := Owner.FindMeshByName(string(FParentName)) as TgxFile3DSDummyObject;
- FParentName := '';
- end;
- lAnimationData := FRefTranf;
- p := self;
- while p <> nil do
- begin
- p.FAnimList.ApplyAnimKeys(lAnimationData, AFrame);
- p := p.FParent;
- end;
- FAnimTransf := lAnimationData;
- end;
- procedure TgxFile3DSDummyObject.MorphTo(morphTargetIndex: integer);
- begin
- SetFrame(morphTargetIndex);
- end;
- procedure TgxFile3DSDummyObject.Lerp(morphTargetIndex1, morphTargetIndex2: integer;
- lerpFactor: single);
- begin
- if (Owner.Owner is TgxActor) and ((Owner.Owner as TgxActor).AnimationMode in
- [aamBounceBackward, aamLoopBackward]) then
- SetFrame(morphTargetIndex1 - lerpFactor)
- else
- SetFrame(morphTargetIndex1 + lerpFactor);
- end;
- procedure TgxFile3DSDummyObject.Assign(Source: TPersistent);
- begin
- inherited; // Assign all published properties here.
- if Source is TgxFile3DSDummyObject then
- begin
- FRefTranf := (Source as TgxFile3DSDummyObject).FRefTranf;
- FParent := (Source as TgxFile3DSDummyObject).FParent;
- FAnimList.Assign((Source as TgxFile3DSDummyObject).FAnimList);
- SetFrame(0);
- end;
- end;
- procedure TgxFile3DSDummyObject.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 TgxFile3DSDummyObject.ExtractTriangles(texCoords, normals: TgxAffineVectorList):
- TgxAffineVectorList;
- 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 TgxFile3DSDummyObject.WriteToFiler(Writer: TgxVirtualWriter);
- 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 TgxFile3DSDummyObject.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- inherited;
- Reader.Read(FRefTranf, SizeOf(FRefTranf));
- FParentName := String64(Copy(Reader.ReadString, 1, 64));
- if FParentName = 'nil' then
- FParentName := '';
- FAnimList.ReadFromFiler(Reader);
- end;
- destructor TgxFile3DSDummyObject.Destroy;
- begin
- FAnimList.Free;
- inherited;
- end;
- procedure TgxFile3DSMeshObject.LoadAnimation(const AData: Pointer);
- var
- aScale: TgxFile3DSScaleAnimationKeys;
- aRot: TgxFile3DSRotationAnimationKeys;
- aPos: TgxFile3DSPositionAnimationKeys;
- Mat : TMatrix4f;
- RotMat : TMatrix4f;
- AffVect : TAffineVector;
- begin
- inherited;
- with PKFMesh3DS(AData)^, FAnimList do
- begin
- aScale := TgxFile3DSScaleAnimationKeys.Create;
- aScale.LoadData(NSKeys, SKeys, Scale);
- AddKeys(aScale);
- aRot := TgxFile3DSRotationAnimationKeys.Create;
- aRot.LoadData(NRKeys, RKeys, Rot);
- AddKeys(aRot);
- aPos := TgxFile3DSPositionAnimationKeys.Create;
- aPos.LoadData(NPKeys, PKeys, Pos);
- AddKeys(aPos);
- if ParentStr <> '' then
- FParent := TgxFile3DSDummyObject(Owner.FindMeshByName(string(ParentStr)));
- with FRefTranf do
- begin
- if vFile3DS_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 vFile3DS_LoadedStaticFrame = -1 then
- SetFrame(CGLFILE3DS_DEFAULT_FRAME)
- else
- SetFrame(vFile3DS_LoadedStaticFrame);
- end;
- procedure TgxFile3DSMeshObject.BuildList(var ARci: TgxRenderContextInfo);
- begin
- glPushMatrix;
- if not FStatic then
- glMultMatrixf(@FAnimTransf.ModelMatrix);
- inherited;
- glPopMatrix;
- end;
- constructor TgxFile3DSOmniLightObject.Create;
- begin
- inherited;
- FLightSrc := TgxFile3DSLight.Create(nil);
- end;
- procedure TgxFile3DSOmniLightObject.LoadData(const AOwner: TgxBaseMesh;
- 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 TgxFile3DSOmniLightObject.LoadAnimation(const AData: Pointer);
- var
- aPos: TgxFile3DSPositionAnimationKeys;
- aCol: TgxFile3DSColorAnimationKeys;
- begin
- inherited;
- with PKFOmni3DS(AData)^, FAnimList do
- begin
- aPos := TgxFile3DSPositionAnimationKeys.Create;
- aPos.LoadData(NPKeys, PKeys, Pos);
- AddKeys(aPos);
- aCol := TgxFile3DSColorAnimationKeys.Create;
- aCol.LoadData(NCKeys, CKeys, Color);
- AddKeys(aCol);
- if Parent <> '' then
- FParent := TgxFile3DSDummyObject(Owner.FindMeshByName(string(Parent)));
- end;
- if vFile3DS_LoadedStaticFrame = -1 then
- SetFrame(CGLFILE3DS_DEFAULT_FRAME)
- else
- SetFrame(vFile3DS_LoadedStaticFrame);
- end;
- procedure TgxFile3DSOmniLightObject.SetFrame(const AFrame: real);
- var
- obj: TComponent;
- begin
- if FLightSrcName <> '' then
- begin
- obj := Owner.Owner.FindChild(string(FLightSrcName), True);
- if obj is TgxFile3DSLight then
- begin
- FLightSrc.Free;
- FLightSrc := obj as TgxFile3DSLight;
- end;
- FLightSrcName := '';
- end;
- inherited;
- FLightSrc.Position.SetPoint(FAnimTransf.ModelMatrix.W);
- FLightSrc.Diffuse.Color := FAnimTransf.Color;
- end;
- procedure TgxFile3DSOmniLightObject.Assign(Source: TPersistent);
- begin
- inherited;
- if Source is TgxFile3DSOmniLightObject then
- FlightSrc.Assign((Source as TgxFile3DSOmniLightObject).FLightSrc);
- end;
- procedure TgxFile3DSOmniLightObject.WriteToFiler(Writer: TgxVirtualWriter);
- var
- str: string;
- begin
- inherited;
- if FLightSrc.Name = '' then
- str := 'nil'
- else
- str := Copy(FLightSrc.Name, 1, 64);
- Writer.WriteString(str);
- end;
- procedure TgxFile3DSOmniLightObject.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- inherited;
- FLightSrcName := String64(Copy(Reader.ReadString, 1, 64));
- if FLightSrcName = 'nil' then
- FLightSrcName := '';
- end;
- destructor TgxFile3DSOmniLightObject.Destroy;
- begin
- FLightSrc.Free;
- inherited;
- end;
- procedure TgxFile3DSSpotLightObject.LoadData(const AOwner: TgxBaseMesh;
- 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 TgxFile3DSSpotLightObject.LoadAnimation(const AData: Pointer);
- var
- aTPos: TTgxFile3DSPositionAnimationKeys;
- aFall: TgxFile3DSSpotLightCutOffAnimationKeys;
- aHot: TgxFile3DSLightHotSpotAnimationKeys;
- begin
- inherited;
- with PKFSpot3DS(AData)^, FAnimList do
- begin
- aTPos := TTgxFile3DSPositionAnimationKeys.Create;
- aTPos.LoadData(NTKeys, TKeys, TPos);
- AddKeys(aTPos);
- aFall := TgxFile3DSSpotLightCutOffAnimationKeys.Create;
- aFall.LoadData(NFKeys, FKeys, Fall);
- AddKeys(aFall);
- aHot := TgxFile3DSLightHotSpotAnimationKeys.Create;
- aHot.LoadData(NHKeys, HKeys, Hot);
- AddKeys(aHot);
- if Parent <> '' then
- FParent := TgxFile3DSDummyObject(Owner.FindMeshByName(string(Parent)));
- end;
- if vFile3DS_LoadedStaticFrame = -1 then
- SetFrame(CGLFILE3DS_DEFAULT_FRAME)
- else
- SetFrame(vFile3DS_LoadedStaticFrame);
- end;
- procedure TgxFile3DSSpotLightObject.SetFrame(const AFrame: real);
- begin
- inherited;
- FLightSrc.SpotTargetPos.SetPoint(FAnimTransf.TargetPos);
- FLightSrc.SpotCutOff := FAnimTransf.SpotLightCutOff / 2;
- FLightSrc.HotSpot := FAnimTransf.HotSpot / 2;
- end;
- constructor TgxFile3DSCameraObject.Create;
- begin
- inherited;
- FCameraSrc := TgxFile3DSCamera.Create(nil);
- FTargetObj := TgxDummyCube.Create(nil);
- FCameraSrc.TargetObject := FTargetObj;
- end;
- procedure TgxFile3DSCameraObject.LoadData(Owner: TgxBaseMesh; 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 TgxFile3DSCameraObject.LoadAnimation(const AData: Pointer);
- var
- aPos: TgxFile3DSPositionAnimationKeys;
- aRoll: TgxFile3DSRollAnimationKeys;
- aTPos: TTgxFile3DSPositionAnimationKeys;
- begin
- inherited;
- with PKFCamera3DS(AData)^, FAnimList do
- begin
- aPos := TgxFile3DSPositionAnimationKeys.Create;
- aPos.LoadData(NPKeys, PKeys, Pos);
- AddKeys(aPos);
- aRoll := TgxFile3DSRollAnimationKeys.Create;
- aRoll.LoadData(NRKeys, RKeys, Roll);
- AddKeys(aRoll);
- aTPos := TTgxFile3DSPositionAnimationKeys.Create;
- aTPos.LoadData(NTKeys, TKeys, TPos);
- AddKeys(aTPos);
- end;
- if vFile3DS_LoadedStaticFrame = -1 then
- SetFrame(CGLFILE3DS_DEFAULT_FRAME)
- else
- SetFrame(vFile3DS_LoadedStaticFrame);
- end;
- procedure TgxFile3DSCameraObject.SetFrame(const AFrame: real);
- var
- obj: TComponent;
- begin
- inherited;
- if FCameraSrcName <> '' then
- begin
- obj := Owner.Owner.FindChild(string(FCameraSrcName), True);
- if obj is TgxFile3DSCamera then
- begin
- FCameraSrc.Free;
- FCameraSrc := obj as TgxFile3DSCamera;
- end;
- FCameraSrcName := '';
- end;
- FCameraSrc.Position.SetPoint(FAnimTransf.ModelMatrix.W);
- FCameraSrc.RollAngle := FAnimTransf.Roll;
- FTargetObj.Position.SetPoint(FAnimTransf.TargetPos);
- end;
- procedure TgxFile3DSCameraObject.WriteToFiler(Writer: TgxVirtualWriter);
- var
- str: string;
- begin
- inherited;
- if FCameraSrc.Name = '' then
- str := 'nil'
- else
- str := Copy(FCameraSrc.Name, 1, 64);
- Writer.WriteString(str);
- end;
- procedure TgxFile3DSCameraObject.ReadFromFiler(Reader: TgxVirtualReader);
- begin
- inherited;
- FCameraSrcName := String64(Copy(Reader.ReadString, 1, 64));
- if FCameraSrcName = 'nil' then
- FCameraSrcName := '';
- end;
- destructor TgxFile3DSCameraObject.Destroy;
- begin
- FCameraSrc.Free;
- FTargetObj.Free;
- inherited;
- end;
- // ------------------
- // ------------------ TGL3DSVectorFile ------------------
- // ------------------
- class function Tgx3DSVectorFile.Capabilities: TDataFileCapabilities;
- begin
- Result := [dfcRead];
- end;
- procedure Tgx3DSVectorFile.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: TgxFile3DSMeshObject;
- hasLightmap: boolean;
- //--------------- local functions -------------------------------------------
- function GetOrAllocateMaterial(materials: TMaterialList; const Name: string): string;
- var
- material: PMaterial3DS;
- specColor: TVector4f;
- matLib: TgxMaterialLibrary;
- libMat, SecondMaterial: TgxLibMaterial;
- begin
- material := Materials.MaterialByName[Name];
- Assert(Assigned(material));
- if GetOwner is TgxBaseMesh then
- begin
- matLib := TgxBaseMesh(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 vFile3DS_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 vFile3DS_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 vFile3DS_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: TgxMaterialLibrary;
- libMat: TgxLibMaterial;
- begin
- Result := -1;
- material := Materials.MaterialByName[Name];
- Assert(Assigned(material));
- if GetOwner is TgxBaseMesh then
- begin
- matLib := TgxBaseMesh(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): TMatrix4f;
- // 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: TMatrix4f;
- v4: TVector4f;
- 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;
- //----------------------------------------------------------------------
- {$IFDEF USE_NO_ASM}
- 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;
- {$ELSE}
- function IsVertexMarked(P: Pointer; Index: integer): boolean; assembler;
- // tests the Index-th bit, returns True if set else False
- asm
- BT [EAX], EDX
- SETC AL
- end;
- {$ENDIF}
- //---------------------------------------------------------------------------
- {$IFDEF USE_NO_ASM}
- 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;
- {$ELSE}
- function MarkVertex(P: Pointer; Index: integer): boolean; assembler;
- // sets the Index-th bit and return True if it was already set else False
- asm
- BTS [EAX], EDX
- SETC AL
- end;
- {$ENDIF}
- //---------------------------------------------------------------------------
- // 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.
- {$IFDEF USE_ASM}
- procedure StoreSmoothIndex(ThisIndex, SmoothingGroup, NewIndex: cardinal; P: Pointer);
- asm
- PUSH EBX
- BSF EBX, EDX
- // determine smoothing group index (convert flag into an index)
- MOV EDX, [P] // get address of index array
- SHL EAX, 7 // ThisIndex * SizeOf(TSmoothIndexEntry)
- ADD EAX, EDX
- LEA EDX, [4 * EBX + EAX]
- // Address of array + vertex index + smoothing group index
- MOV [EDX], ECX
- POP EBX
- end;
- {$ELSE}
- 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;
- {$ENDIF}
- //---------------------------------------------------------------------------
- {$IFDEF USE_ASM}
- function GetSmoothIndex(ThisIndex, SmoothingGroup: cardinal; P: Pointer): integer;
- // Retrieves the vertex index for the given index and smoothing group.
- // This redirection is necessary because a vertex might have been duplicated.
- asm
- PUSH EBX
- BSF EBX, EDX // determine smoothing group index
- SHL EAX, 7 // ThisIndex * SizeOf(TSmoothIndexEntry)
- ADD EAX, ECX
- LEA ECX, [4 * EBX + EAX]
- // Address of array + vertex index + smoothing group index
- MOV EAX, [ECX]
- POP EBX
- end;
- {$ELSE}
- 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;
- {$ENDIF}
- //---------------------------------------------------------------------------
- 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;
- var
- CurrentMotionIndex, iMaterial, i, j, x: integer;
- aFaceGroup: TgxFGVertexIndexList;
- Face, Vertex, TargetVertex: integer;
- SmoothingGroup: cardinal;
- CurrentIndex: word;
- Vector1, Vector2, Normal: TAffineVector;
- standardNormalsOrientation: boolean;
- lights_mesh: TgxFile3DSOmniLightObject;
- camera_mesh: TgxFile3DSCameraObject;
- basemesh: TgxBaseMesh;
- 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 := TgxFile3DSMeshObject.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
- TgxMeshMorphTarget.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 vVectorFileObjectsAllocateMaterials) then
- begin
- aFaceGroup := TgxFGVertexIndexList.CreateOwned(mesh.FaceGroups);
- with aFaceGroup do
- begin
- basemesh := TgxBaseMesh(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 := TgxFGVertexIndexList.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 := TgxFile3DSMeshObject.CreateOwned(Owner.MeshObjects);
- mesh.Name := string(KeyFramer.MeshMotion[I].NameStr);
- //dummy targets
- for x := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
- TgxMeshMorphTarget.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 TgxFile3DSMeshObject;
- 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 := TgxFile3DSOmniLightObject.CreateOwned(Owner.MeshObjects);
- // Dummy targets for it.
- for x := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
- TgxMeshMorphTarget.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 := TgxFile3DSSpotLightObject.CreateOwned(Owner.MeshObjects);
- // Dummy targets for it.
- for x := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
- TgxMeshMorphTarget.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 := TgxFile3DSCameraObject.CreateOwned(Owner.MeshObjects);
- // Dummy targets for it.
- for x := KeyFramer.Settings.Seg.SegBegin to KeyFramer.Settings.Seg.SegEnd do
- TgxMeshMorphTarget.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 vFile3DS_LoadedStaticFrame >= 0 then
- begin
- for i := 0 to Owner.MeshObjects.Count - 1 do
- begin
- if Owner.MeshObjects[i] is TgxFile3DSMeshObject then
- begin
- mesh := Owner.MeshObjects[i] as TgxFile3DSMeshObject;
- 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([TgxFile3DSDummyObject, TgxFile3DSMeshObject,
- TgxFile3DSOmniLightObject, TgxFile3DSSpotLightObject,
- TgxFile3DSCameraObject]);
- RegisterVectorFileFormat('3ds', '3D Studio files', Tgx3DSVectorFile);
- RegisterVectorFileFormat('prj', '3D Studio project files', Tgx3DSVectorFile);
- end.
|