📄 glfile3ds.pas
字号:
// 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;
//---------------------------------------------------------------------------
procedure DuplicateVertex(Index: Integer);
// extends the vector and normal array by one entry and duplicates the vertex data 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;
//--------------- end local functions ---------------------------------------
var
iMaterial, i, j : Integer;
aFaceGroup : TFGVertexIndexList;
Face, Vertex, TargetVertex: Integer;
SmoothingGroup: Cardinal;
CurrentIndex: Word;
Vector1, Vector2, Normal : TAffineVector;
standardNormalsOrientation : Boolean;
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
if IsHidden or (NVertices<3) then Continue;
hasLightMap:=False;
mesh:=TMeshObject.CreateOwned(Owner.MeshObjects);
mesh.Name:=PMesh3DS(Objects.Mesh[I])^.NameStr;
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) 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
// 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 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
// 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 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
MaterialName:='';
// 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, MatArray[iMaterial].NameStr);
LightMapIndex:=GetOrAllocateLightMap(Materials, 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][0], mesh.TexCoords[j][1]);
end;
finally
Free;
end;
end;
// ------------------------------------------------------------------
// ------------------------------------------------------------------
// ------------------------------------------------------------------
initialization
// ------------------------------------------------------------------
// ------------------------------------------------------------------
// ------------------------------------------------------------------
RegisterVectorFileFormat('3ds', '3D Studio files', TGL3DSVectorFile);
//RegisterVectorFileFormat('prj', '3D Studio project files', TGL3DSVectorFile);
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -