123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.FileLWO;
- (* Support-code to load Lightwave LWO Files (v6.0+, partial support) *)
- interface
- {$I Stage.Defines.inc}
- uses
- System.SysUtils,
- System.Classes,
- System.Math,
-
- Stage.VectorTypes,
- Stage.VectorGeometry,
- GXS.VectorLists,
- GXS.Texture,
- GXS.Material,
- GXS.VectorFileObjects,
- Formatx.LWO;
- type
- TgxLWOVectorFile = class(TgxVectorFile)
- private
- FLWO: TLWObjectFile;
- FPnts: TLWPnts;
- procedure AddLayr(Layr: TLWLayr; LWO: TLWObjectFile);
- procedure AddSurf(Surf: TLWSurf; LWO: TLWObjectFile);
- procedure AddPnts(Pnts: TLWPnts; Mesh: TgxMeshObject);
- procedure AddPols(Pols: TLWPols; Mesh: TgxMeshObject);
- procedure AddVMap(VMap: TLWVMap; Mesh: TgxMeshObject);
- public
- procedure LoadFromStream(aStream: TStream); override;
- end;
- //=============================================================================
- implementation
- //=============================================================================
- type
- PVector3f = ^TVector3f;
- function CalcTriNorm(v1, v2, v3: TVec12): TVector3f;
- var
- e1, e2: TVector3f;
- begin
- e1 := VectorSubtract(PVector3f(@v2)^, PVector3f(@v1)^);
- e2 := VectorSubtract(PVector3f(@v3)^, PVector3f(@v1)^);
- VectorCrossProduct(e1, e2, result);
- result := VectorNormalize(result);
- end;
- type
- TNormBuffer = record
- count, lasttag: TU2;
- end;
- TNormBufferDynArray = array of TNormBuffer;
- (******************************* TgxLWOVectorFile *****************************)
- procedure TgxLWOVectorFile.AddLayr(Layr: TLWLayr; LWO: TLWObjectFile);
- var
- Idx: Integer;
- Mesh: TgxMeshObject;
- Pnts: TLWPnts;
- begin
- // Add mesh
- Mesh := TgxMeshObject.CreateOwned(Owner.MeshObjects);
- with Mesh do
- begin
- Name := Layr.Name;
- Mode := momFaceGroups;
- // pnts
- Idx := Layr.Items.FindChunk(@FindChunkById, @ID_PNTS);
- Pnts := TLWPnts(Layr.Items[Idx]);
- if Idx <> -1 then
- AddPnts(Pnts, Mesh);
- // vertex maps
- Idx := TLWPnts(Layr.Items[Idx]).Items.FindChunk(@FindChunkById, @ID_VMAP);
- while Idx <> -1 do
- begin
- AddVMap(TLWVMap(Pnts.Items[Idx]), Mesh);
- Idx := Pnts.Items.FindChunk(@FindChunkById, @ID_VMAP, Idx + 1);
- end;
- // Polygons
- Idx := Layr.Items.FindChunk(@FindChunkById, @ID_POLS);
- while Idx <> -1 do
- begin
- AddPols(TLWPols(Layr.Items[Idx]), Mesh);
- Idx := Layr.Items.FindChunk(@FindChunkById, @ID_POLS, Idx + 1);
- end;
- // Normals.Normalize;
- end;
- FPnts := nil;
- end;
- procedure TgxLWOVectorFile.AddPnts(Pnts: TLWPnts; Mesh: TgxMeshObject);
- var
- i: Integer;
- begin
- FPnts := Pnts;
- with Mesh do
- begin
- Vertices.Capacity := Pnts.PntsCount;
- TexCoords.Capacity := Pnts.PntsCount;
- TexCoords.AddNulls(Pnts.PntsCount);
- for i := 0 to Pnts.PntsCount - 1 do
- Vertices.Add(PAffineVector(@Pnts.Pnts[i])^);
- end;
- end;
- procedure TgxLWOVectorFile.AddPols(Pols: TLWPols; Mesh: TgxMeshObject);
- var
- Idx: Integer;
- i, j, k, PolyIdx, NormIdx: Integer;
- TagPolys: TU2DynArray;
- FaceGrp: TFGVertexNormalTexIndexList;
- VertPolys: TU2DynArray;
- begin
- SetLength(VertPolys, 0);
- with Pols do
- begin
- // face type pols chunk
- if PolsType = POLS_TYPE_FACE then
- begin
- Idx := Items.FindChunk(@FindChunkById, @ID_PTAG);
- while Idx <> -1 do
- begin
- with TLWPTag(Items[Idx]) do
- begin
- if MapType = PTAG_TYPE_SURF then
- begin
- // for each tag
- for i := 0 to TagCount - 1 do
- begin
- // get polygons using this tag
- if GetPolsByTag(Tags[i], TagPolys) > 0 then
- begin
- // make the facegroup and set the material name
- FaceGrp := TFGVertexNormalTexIndexList.CreateOwned(Mesh.FaceGroups);
- FaceGrp.MaterialName := FLWO.SurfaceByTag[Tags[i]].Name;
- FaceGrp.Mode := fgmmTriangles;
- // for each polygon in the current surface Tags[i]
- for j := 0 to Length(TagPolys) - 1 do
- begin
- PolyIdx := PolsByIndex[TagPolys[j]];
- // triple 2,3 and 4 point ngons
- case Indices[PolyIdx] of
- 2:
- begin
- // triangle line segment
- NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[0])^);
- FaceGrp.Add(Indices[PolyIdx + 1], NormIdx, Indices[PolyIdx + 1]);
- NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[1])^);
- FaceGrp.Add(Indices[PolyIdx + 2], NormIdx, Indices[PolyIdx + 1]);
- NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[0])^);
- FaceGrp.Add(Indices[PolyIdx + 1], NormIdx, Indices[PolyIdx + 1]);
- end;
- 3: for k := 1 to 3 do
- begin
- NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[k - 1])^);
- FaceGrp.Add(Indices[PolyIdx + k], NormIdx, Indices[PolyIdx + 1]);
- end;
- 4:
- begin
- // triangle A
- NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[0])^);
- FaceGrp.Add(Indices[PolyIdx + 1], NormIdx, Indices[PolyIdx + 1]);
- NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[1])^);
- FaceGrp.Add(Indices[PolyIdx + 2], NormIdx, Indices[PolyIdx + 1]);
- NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[2])^);
- FaceGrp.Add(Indices[PolyIdx + 3], NormIdx, Indices[PolyIdx + 1]);
- // triangle B
- NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[0])^);
- FaceGrp.Add(Indices[PolyIdx + 1], NormIdx, Indices[PolyIdx + 1]);
- NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[2])^);
- FaceGrp.Add(Indices[PolyIdx + 3], NormIdx, Indices[PolyIdx + 1]);
- NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[3])^);
- FaceGrp.Add(Indices[PolyIdx + 4], NormIdx, Indices[PolyIdx + 1]);
- end;
- end;
- end;
- SetLength(TagPolys, 0);
- end;
- end;
- end
- else
- if MapType = PTAG_TYPE_PART then
- begin
- // Todo: PTag PART
- end
- else
- if MapType = PTAG_TYPE_SMGP then
- begin
- // Todo: PTag Smooth Group
- end;
- Idx := Items.FindChunk(@FindChunkById, @ID_PTAG, Idx + 1);
- end;
- end;
- end
- else
- //// curv type pols chunk (catmull-rom splines)
- if PolsType = POLS_TYPE_CURV then
- begin
- // Todo: CURV Pols import
- end
- else
- {// nurbs patch pols type chunk}
- if PolsType = POLS_TYPE_PTCH then
- begin
- {Todo: NURBS Patch Pols import}
- end
- else
- {// metaball pols type chunk}
- if PolsType = POLS_TYPE_MBAL then
- begin
- {Todo: MetaBall type Pols import}
- end
- else
- {// bone pols type chunk}
- if PolsType = POLS_TYPE_BONE then
- begin
- {Todo: Bone Pols import}
- end;
- SetLength(TagPolys, 0);
- end;
- end;
- procedure TgxLWOVectorFile.AddSurf(Surf: TLWSurf; LWO: TLWObjectFile);
- var
- matLib: TgxMaterialLibrary;
- libMat: TgxLibMaterial;
- tex2Mat: TgxLibMaterial;
- colr: TColr12;
- FloatParm, tran, refl: TF4;
- WordParm: TU2;
- StrParm: string;
- Idx: integer;
- begin
- // DONE: implement surface inheritance
- if GetOwner is TgxBaseMesh then
- begin
- matLib := TgxBaseMesh(GetOwner).MaterialLibrary;
- if Assigned(matLib) then
- begin
- libMat := matLib.Materials.GetLibMaterialByName(Surf.Name);
- if not Assigned(libMat) then
- begin
- libMat := matLib.Materials.Add;
- libMat.Name := Surf.Name;
- with libMat.Material.FrontProperties do
- begin
- tran := Surf.FloatParam[ID_TRAN];
- if tran <> 0 then
- libMat.Material.BlendingMode := bmTransparency;
- colr := Surf.Vec3Param[ID_COLR];
- // Ambient.Color := VectorMake(colr[0],colr[1],colr[2],1);
- Ambient.Color := VectorMake(0, 0, 0, 1);
- (* Diffuse *)
- FloatParm := Surf.FloatParam[ID_DIFF];
- Diffuse.Color := VectorMake(colr[0] * FloatParm, colr[1] * FloatParm, colr[2] * FloatParm, tran);
- (* Luminosity -> Emission *)
- FloatParm := Surf.FloatParam[ID_LUMI];
- Emission.Color := VectorMake(colr[0] * FloatParm, colr[1] * FloatParm, colr[2] * FloatParm, 1);
- (* Specularity *)
- FloatParm := Surf.FloatParam[ID_SPEC];
- Specular.Color := VectorMake(colr[0] * FloatParm, colr[1] * FloatParm, colr[2] * FloatParm, 1);
- (* Glossiness -> Shininess *)
- FloatParm := Surf.FloatParam[ID_GLOS];
- Shininess := Round(Power(2, 7 * FloatParm));
- (* Polygon sidedness *)
- WordParm := Surf.WordParam[ID_SIDE];
- if (WordParm and SIDE_BACK) = SIDE_BACK then
- AssignTo(libMat.Material.BackProperties);
- (* Reflection settings *)
- refl := Surf.FloatParam[ID_REFL];
- if refl > 0 then
- begin
- // Check the reflection options
- WordParm := Surf.WordParam[ID_RFOP];
- if WordParm > RFOP_RAYTRACEANDBACKDROP then
- begin
- WordParm := Surf.VXParam[ID_RIMG];
- Idx := Surf.RootChunks.FindChunk(@FindClipByClipIndex, @WordParm);
- if Idx <> -1 then
- begin
- StrParm := string(PAnsiChar(TLWClip(Surf.RootChunks[Idx]).ParamAddr[ID_STIL]));
- StrParm := GetContentDir.FindContent(ToDosPath(StrParm));
- if FileExists(StrParm) then
- try
- if (not libMat.Material.Texture.Enabled) then
- tex2Mat := libMat
- else
- tex2Mat := matLib.Materials.Add;
- with tex2Mat do
- begin
- Material.Texture.Image.LoadFromFile(StrParm);
- Material.Texture.Disabled := False;
- with Material.Texture do
- begin
- MappingMode := tmmCubeMapReflection;
- if refl < 100 then
- TextureMode := tmBlend
- else
- TextureMode := tmDecal;
- end;
- end;
- libMat.Texture2Name := 'REFL_' + ExtractFileName(StrParm);
- except
- on E: ETexture do
- begin
- if not Self.Owner.IgnoreMissingTextures then
- raise;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- procedure TgxLWOVectorFile.AddVMap(VMap: TLWVMap; Mesh: TgxMeshObject);
- var
- i: integer;
- begin
- with VMap, Mesh do
- begin
- // texture coords
- if VMapType = VMAP_TYPE_TXUV then
- begin
- for i := 0 to ValueCount - 1 do
- TexCoords.Items[Value[i].vert] := AffineVectorMake(Value[i].values[0], Value[i].values[1], 0);
- end
- else
- {// vertex weight map}
- if VMapType = VMAP_TYPE_WGHT then
- begin
- // Todo: WeightMap import
- end
- else
- {// vertex morph (relative)}
- if VMapType = VMAP_TYPE_MORF then
- begin
- // Todo: Morph target (relative) import
- end
- else
- {// vertex morph (absolute)}
- if VMapType = VMAP_TYPE_SPOT then
- begin
- // Todo: Morph target (absolute) import
- end;
- end;
- end;
- procedure TgxLWOVectorFile.LoadFromStream(aStream: TStream);
- var
- Ind: Integer;
- begin
- FLWO := TLWObjectFile.Create;
- with FLWO do
- try
- LoadFromStream(aStream);
- // Add Surfaces to material list
- Ind := Chunks.FindChunk(@FindChunkById, @ID_SURF, 0);
- while Ind <> -1 do
- begin
- AddSurf(TLWSurf(Chunks[Ind]), FLWO);
- Ind := Chunks.FindChunk(@FindChunkById, @ID_SURF, Ind + 1);
- end;
- // Lw layer
- Ind := Chunks.FindChunk(@FindChunkById, @ID_LAYR, 0);
- while Ind <> -1 do
- begin
- AddLayr(TLWLayr(Chunks[Ind]), FLWO);
- Ind := Chunks.FindChunk(@FindChunkById, @ID_LAYR, Ind + 1);
- end;
- finally
- FreeAndNil(FLWO);
- end;
- end;
- //---------------------------------------------------
- initialization
- //---------------------------------------------------
- RegisterVectorFileFormat('lwo', 'Lightwave3D object file (6.0 or above)', TgxLWOVectorFile);
- finalization
- end.
|