procedureTGLOBJVectorFile.LoadFromStream(aStream:TStream);varhv:THomogeneousVector;av:TAffineVector;mesh:TMeshObject;faceGroup:TOBJFGVertexNormalTexIndexList;faceGroupNames:TStringList;procedureReadHomogeneousVector;{Readavectorwithamaximumof4elementsfromthecurrentline.}vari,c:Integer;f:string;beginFillChar(hv,SizeOf(hv),0);i:=0;while(FLine<>'')and(i<4)dobeginf:=NextToken(FLine,' ');Val(f,hv.V[i],c);ifc<>0thenError(Format('''%s'' is not a valid floating-point constant.',[f]));Inc(i);end;end;procedureReadAffineVector;{Readavectorwithamaximumof3elementsfromthecurrentline.}vari,c:integer;f:string;beginFillChar(av,SizeOf(av),0);i:=0;while(FLine<>'')and(i<3)dobeginf:=NextToken(FLine,' ');Val(f,av.V[i],c);ifc<>0thenError(Format('''%s'' is not a valid floating-point constant.',[f]));inc(i);end;end;procedureSetCurrentFaceGroup(aName:string; const matlName: string);vari:Integer;begini:=faceGroupNames.IndexOf(aName);ifi>=0thenbeginfaceGroup:=TOBJFGVertexNormalTexIndexList(faceGroupNames.Objects[i]);iffaceGroup.MaterialName<>matlNamethenbegini:=faceGroupNames.IndexOf(aName);ifi>=0thenbeginfaceGroup:=TOBJFGVertexNormalTexIndexList(faceGroupNames.Objects[i]);iffaceGroup.MaterialName<>matlNamethenfaceGroup:=nil;end;end;end;if(faceGroup=nil)or(faceGroup.Name<>aName)or(faceGroup.PolygonVertices.Count>0)or(faceGroup.MaterialName<>matlName)thenbeginfaceGroup:=TOBJFGVertexNormalTexIndexList.CreateOwned(Mesh.FaceGroups);faceGroup.FName:=aName;faceGroup.Mode:=objfgmmPolygons;faceGroup.MaterialName:=matlName;faceGroupNames.AddObject(aName,faceGroup);end;end;procedureAddFaceVertex(faceVertices:string);functionGetIndex(Count:Integer):Integer;vars:string;begins:=NextToken(FaceVertices,'/');Result:=StrToIntDef(s,0);ifResult=0thenResult:=-1//MissingelseifResult<0thenbegin{Relative,makeabsolute."-1"meanslast,"-2"secondlast.}Result:=Count+Resultendelsebegin{Absolute,correctforzero-base.}Dec(Result);end;end;varvIdx,tIdx,nIdx:Integer;beginvIdx:=GetIndex(mesh.Vertices.Count);tIdx:=GetIndex(mesh.TexCoords.Count);nIdx:=GetIndex(mesh.Normals.Count);faceGroup.Add(vIdx,nIdx,tIdx);end;procedureReadFace(constcurMtlName:string);varfaceVertices:string;beginifFLine<>''thenbeginifnotAssigned(FaceGroup)thenSetCurrentFaceGroup('',curMtlName);trywhileFLine<>''dobeginfaceVertices:=NextToken(FLine,' ');AddFaceVertex(faceVertices);end;finallyFaceGroup.PolygonComplete;end;end;end;procedureReadTriangleStripContinued;varfaceVertices:string;beginiffaceGroup=nilthenError('q-line without preceding t-line.');whileFLine<>''dobeginFaceVertices:=NextToken(FLine,' ');AddFaceVertex(FaceVertices);end;end;procedureReadTriangleStrip;begin{StartanewFacegroup,mode=trianglestrip}faceGroup:=TOBJFGVertexNormalTexIndexList.CreateOwned(Mesh.FaceGroups);faceGroup.Mode:=objfgmmTriangleStrip;{Therestisthesameasforcontinuationofastrip.}ReadTriangleStripContinued;end;functionGetOrAllocateMaterial(constlibName,matName:string):string;varfs:TStream;objMtl:TGLMTLFile;matLib:TGLMaterialLibrary;libMat,libMat2:TGLLibMaterial;texName:string;libFilename:string;beginifGetOwnerisTGLBaseMeshthenbegin//gotalinkedmateriallibrary?matLib:=TGLBaseMesh(GetOwner).MaterialLibrary;ifAssigned(matLib)thenbeginResult:=matName;libMat:=matLib.Materials.GetLibMaterialByName(matName);ifnotAssigned(libMat)thenbegin//spawnanewmateriallibMat:=matLib.Materials.Add;libMat.Name:=matName;//getfullpathformaterialfiletobeloadifmatLib.TexturePaths=EmptyStrthenlibFilename:=libNameelselibFilename:=IncludeTrailingPathDelimiter(matLib.TexturePaths)+libName;tryfs:=CreateFileStream(libFilename);exceptfs:=nil;end;ifAssigned(fs)thenbeginobjMtl:=TGLMTLFile.Create;tryobjMtl.LoadFromStream(fs);objMtl.Prepare;//setupmaterialcolorswithlibMat.Material.FrontPropertiesdobeginAmbient.Color:=objMtl.MaterialVectorProperty(matName,'Ka',clrGray20);Diffuse.Color:=objMtl.MaterialVectorProperty(matName,'Kd',clrGray80);Diffuse.Alpha:=GLUtils.StrToFloatDef(objMtl.MaterialStringProperty(matName,'d'),1);ifDiffuse.Alpha<1thenlibMat.Material.BlendingMode:=bmTransparency;caseStrToIntDef(objMtl.MaterialStringProperty(matName,'illum'),1)of0:begin//non-litmateriallibMat.Material.MaterialOptions:=[moNoLighting];end;1:; // flat, non-shiny material2:begin//specularmaterialSpecular.Color:=objMtl.MaterialVectorProperty(matName,'Ks',clrTransparent);end;else//unknown,assumeunlitlibMat.Material.MaterialOptions:=[moNoLighting];Diffuse.Color:=clrGray80;end;Shininess:=StrToIntDef(objMtl.MaterialStringProperty(matName,'Ns'),1);end;//setuptexturetexName:=objMtl.MaterialStringProperty(matName,'map_Kd');iftexName<>''thenbegintrywithlibMat.Material.TexturedobeginImage.LoadFromFile(texName);Disabled:=False;TextureMode:=tmModulate;end;exceptonE:ETexturedobeginifnotOwner.IgnoreMissingTexturesthenraise;end;end;end;//setuplightmap(self-illumination)texturetexName:=objMtl.MaterialStringProperty(matName,'map_Ke');iftexName<>''thenbegin//spawnanewmateriallibMat2:=matLib.Materials.Add;libMat2.Name:=matName+'_lm';//UsetheGLScenebuilt-insecondtexturesupport(note:themeshLightmapPropertyMUSTbeempty)libMat.Texture2Name:=libMat2.Name;trywithlibMat2.Material.TexturedobeginImage.LoadFromFile(texName);Disabled:=False;minFilter:=miLinear;TextureWrap:=twNone;TextureFormat:=tfRGB;TextureMode:=tmModulate;end;exceptonE:ETexturedobeginifnotOwner.IgnoreMissingTexturesthenraise;end;end;end;finallyobjMtl.Free;fs.Free;end;end;endelseResult:=matName;endelseResult:='';end;end;procedureSplitMesh;vari,j,count:Integer;newMesh:TMeshObject;newfaceGroup:TOBJFGVertexNormalTexIndexList;VertexIdx,NormalIdx,TexCoordIdx:Integer;AffineVector:TAffineVector;beginfori:=0tomesh.FaceGroups.Count-1dobeginfaceGroup:=mesh.FaceGroups[i]asTOBJFGVertexNormalTexIndexList;newMesh:=TMeshObject.CreateOwned(Owner.MeshObjects);newMesh.Mode:=momFaceGroups;newMesh.Name:=faceGroup.Name;newfaceGroup:=TOBJFGVertexNormalTexIndexList.CreateOwned(newMesh.FaceGroups);newfaceGroup.Assign(faceGroup);newfaceGroup.FName:=faceGroup.Name;newfaceGroup.Mode:=faceGroup.Mode;newfaceGroup.MaterialName:=faceGroup.MaterialName;//SendInteger('VertexIndices',faceGroup.VertexIndices.Count);//SendInteger('TexCoords',faceGroup.TexCoordIndices.Count);//SendInteger('Normals',faceGroup.NormalIndices.Count);count:=faceGroup.VertexIndices.Count;forj:=0tocount-1dobeginVertexIdx:=faceGroup.VertexIndices[j];AffineVector:=mesh.Vertices[VertexIdx];VertexIdx:=newMesh.Vertices.Add(AffineVector);TexCoordIdx:=faceGroup.TexCoordIndices[j];AffineVector:=mesh.TexCoords[TexCoordIdx];TexCoordIdx:=newMesh.TexCoords.Add(AffineVector);NormalIdx:=faceGroup.NormalIndices[j];AffineVector:=mesh.Normals[NormalIdx];NormalIdx:=newMesh.Normals.Add(AffineVector);newfaceGroup.Add(VertexIdx,NormalIdx,TexCoordIdx);end;end;Owner.MeshObjects.RemoveAndFree(mesh);end;varcommand,objMtlFileName,curMtlName:string;{$IFDEFSTATS}t0,t1,t2:Integer;{$ENDIF}begin{$IFDEFSTATS}t0:=GLGetTickCount;{$ENDIF}FEof:=False;FSourceStream:=aStream;FLineNo:=0;objMtlFileName:='';curMtlName:='';mesh:=TMeshObject.CreateOwned(Owner.MeshObjects);mesh.Mode:=momFaceGroups;faceGroupNames:=TStringList.Create;faceGroupNames.Duplicates:=dupAccept;faceGroupNames.Sorted:=True;tryfaceGroup:=nil;whilenotFEofdobeginReadLine;ifFLine=''thenContinue; { Skip blank line }ifCharInSet(FLine[1],['#','$'])thenContinue; { Skip comment and alternate comment }command:=AnsiUpperCase(NextToken(FLine,' '));ifcommand='V'thenbeginReadHomogeneousVector;Mesh.Vertices.Add(hv.X,hv.Y,hv.Z);endelseifcommand='VT'thenbeginReadAffineVector;Mesh.TexCoords.Add(av.X,av.Y,0);endelseifcommand='VN'thenbeginReadAffineVector;Mesh.Normals.Add(av.X,av.Y,av.Z);endelseifcommand='VP'thenbegin{ParameterSpaceVertex:Ignore}endelseifcommand='G'thenbegin{Onlythefirstnameontheline,multiplegroupsnotsupported.}SetCurrentFaceGroup(NextToken(FLine,' '),curMtlName);endelseifcommand='F'thenbeginReadFace(curMtlName);endelseifcommand='O'thenbegin{ObjectName:Ignore}endelseifcommand='MTLLIB'thenbegin//objMtlFileName:=NextToken(FLine,' ');objMtlFileName:=NextToken(FLine,#13); //<- Fixendelseifcommand='USEMTL'thenbegincurMtlName:=GetOrAllocateMaterial(objMtlFileName,NextToken(FLine,' '));iffaceGroup=nilthenSetCurrentFaceGroup('',curMtlName)elseSetCurrentFaceGroup(faceGroup.FName,curMtlName);endelseifcommand='S'thenbegin{SmoothGroup:Ignore}endelseifcommand='T'thenbeginReadTriangleStrip;endelseifcommand='Q'thenbeginReadTriangleStripContinued;endelseError('Unsupported Command '''+command+'''');end;mesh.FaceGroups.SortByMaterial;{$IFDEFSTATS}t1:=GLGetTickCount;{$ENDIF}CalcMissingOBJNormals(mesh);{$IFDEFSTATS}t2:=GLGetTickCount;InformationDlg(Format('TGLOBJVectorFile Loaded in %dms'#13+#13+'%dmsspentreading'#13+'%dmsspentcalculatingnormals'#13+'%dGeometricVertices'#13+'%dTextureVertices'#13+'%dNormals'#13+'%dFaceGroups/Strips',[t2-t0,t1-t0,t2-t1,Mesh.Vertices.Count,Mesh.TexCoords.Count,Mesh.Normals.Count,Mesh.FaceGroups.Count]));{$ENDIF}ifvGLFileOBJ_SplitMeshthenSplitMesh;finallyfaceGroupNames.Free;end;end;
Last edit: Roman 2017-02-09
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ok Roman,
Usually you don't need to attach entire unit with a fixed line of code, so you can use TortoiseSVN merge tool to get a diff one. Apply a sample project and make comments, please, about your proposal.
PW
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Unit: GLFileOBJ.pas
Type: TGLOBJVectorFile
Procedure: LoadFromStream(aStream: TStream); override;
Line: 1075
...
Last edit: Roman 2017-02-09
Unit: GLTexture.pas
Type: TGLPersistentImage
Procedure: TGLPersistentImage.LoadFromFile(const fileName: string);
Line: 1658
Support search textures in the 3D model directory.
Last edit: Roman 2017-02-09
Ok Roman,
Usually you don't need to attach entire unit with a fixed line of code, so you can use TortoiseSVN merge tool to get a diff one. Apply a sample project and make comments, please, about your proposal.
PW
Roman,
I've added your fixed line in GLFileOBj and here is imported armrobe.obj file in GLSceneViewer adv demos. Thanks.
PW
Last edit: Pavel Vassiliev 2017-02-09