读取X文件,Delphi版本

在以前版本上做了修改,完善了功能,修改了BUG。

类代码如下:

unit VRMeshXLoader;

{ TODO : .X模型文件读取单元 }

interface

uses

VRCommon,DXCommon,VRMaterial,VRTexture,VRModelObject,Direct3D9,D3DX9,Windows,SysUtils;

Type

TVRXMeshLoader = class( TInterfacedObject,IVRModelXLoader )

private

FMesh : ID3DXMesh;

SubmitNum : integer;

Position : TPoint3;

Matrix : TD3DXMatrix;

IndexSize : integer;

BoundingBox : IVRModelObject;//包围盒子对象

BoundingBoxVisible : Boolean;

MaterialList : Array Of IVRMaterial;

TextureList : Array of IVRNormalTexture;

function Init(const FaceNum : Cardinal;const VertexNum : Cardinal;const FVF : DWORD;const pVertexElements: PD3DVertexElement9 = nil) : Boolean;overload; //传递顶点格式

function LoadMaterials(const Mat : ID3DXBuffer;const Num : DWORD) : Boolean;

procedure AddMaterial( const index : integer;const Material: IVRMaterial );

function optimizeInPlace() : integer; ////经过优化后将自动建立属性表

procedure AddTexture(const Index : integer;const Texture : IVRTexture);//不让用户调用,暂时不支持

function _CreateBoundingBox() : IVRModelObject; //创建包围盒对象

public

function Init( const FileName : String ) : Boolean;overload; //读取 X 文件

procedure UnInit();

procedure Render();

procedure SetBoundingBox( const Enable : Boolean );

function LockVertexBuffer() : Pchar;

procedure UnLockVertexBuffer();

function LockIndexBuffer() : PWord;

procedure UnLockIndexBuffer();

function LockAttriBuffer() : PDWord;//attrib是相对于 面为最小单位的

procedure UnLockAttriBuffer();

function GetAttriTable(out table : TVRAttriTableArray) : Boolean;//获得属性表

function SetAttribTable( const table : TVRAttriTableArray ) : Boolean; //一般不使用

function GetMaterial( const index : integer ) : IVRMaterial;

Procedure RotationYLocal( const Angle : single );//绕本地 Y轴 旋转,角度为弧度制

Procedure RotationXLocal( const Angle : Single );//绕本地 X轴 旋转,角度为弧度制

Procedure RotationZLocal( const Angle : Single );//绕本地 Z轴 旋转,角度为弧度制

Procedure RotationLocal( const XAngle,YAngle,ZAngle : Single);//绕本地旋转,角度为弧度制

Procedure transfer(const Distance: TPoint3);//平移

function _getD3DXMesh() : ID3DXMesh;

function getMatrix() : TD3DMatrix;

procedure SetMatrix( const Matrix : TD3DMatrix );

function GetIndexSize : integer;

procedure Scale(const value : TPoint3);//缩放比例系数

procedure RotationAxisLocal( const Angle : Single;const Up : TPoint3 );

function GetTexture( const index : integer ) : IVRTexture;

procedure _setD3DXMesh(const Mesh : ID3DXMesh);

function GetBoundingBox() : IVRModelObject;

function GetSubitNum() : integer;

procedure ModifyTexture( const index : integer; const Texture : IVRTexture );

Constructor Create();

Destructor Destroy();override;

end;

implementation

{ TVRXMeshLoader }

procedure TVRXMeshLoader.AddMaterial(const index : integer;const Material: IVRMaterial);

begin

if index < 0 then exit;

if index >= Length( MaterialList ) then

begin

SetLength( MaterialList,index );

end;

MaterialList[Index] := Material;

end;

procedure TVRXMeshLoader.AddTexture(const Index: integer;

const Texture: IVRTexture);

begin

if index < 0 then exit;

if Index >= Length(TextureList) then

begin

SetLength( TextureList, Index );

end;

TextureList[Index] := IVRNormalTexture( Texture ) ;

end;

constructor TVRXMeshLoader.Create;

begin

UnInit;

SetLength( MaterialList,0 );

SetLength( TextureList, 0 );

end;

destructor TVRXMeshLoader.Destroy;

begin

UnInit();

SetLength( MaterialList,0 );

SetLength( TextureList, 0 );

inherited;

end;

function TVRXMeshLoader.GetAttriTable(

out table: TVRAttriTableArray): Boolean;

var

size : DWORD;

begin

Result := false;

size := 0;

if not Assigned( FMesh ) then exit; //不存在

if FMesh.GetAttributeTable(nil,@size) = D3DERR_INVALIDCALL then

exit;

if size = 0 then exit;//没有数据

setLength( table,size );

fillchar( table,size,#0);

if FMesh.GetAttributeTable(PD3DXAttributerange(table),@size) = D3DERR_INVALIDCALL then

exit;

Result := true;

end;

function TVRXMeshLoader.GetBoundingBox: IVRModelObject;

begin

Result := Self.BoundingBox;

end;

function TVRXMeshLoader.GetIndexSize: integer;

begin

result := Self.IndexSize;

end;

function TVRXMeshLoader.GetMaterial(const index: integer): IVRMaterial;

begin

Result := nil;

if index < 0 then exit;

if index >= Length( MaterialList ) then exit;

result := MaterialList[index];

end;

function TVRXMeshLoader.getMatrix: TD3DMatrix;

begin

Result := Self.Matrix;

end;

function TVRXMeshLoader.GetSubitNum: integer;

begin

Result := Self.SubmitNum;

end;

function TVRXMeshLoader.GetTexture(const index: integer): IVRTexture;

begin

result := nil;

if TextureList = nil then exit;

if Index >= Length( TextureList ) then exit;

result := TextureList[index];

end;

function TVRXMeshLoader.Init(const FileName: String): Boolean;

var

Materials : ID3DXBuffer;

MaterialsNum : DWORD;

buf : IDirect3DIndexBuffer9;

Desc:TD3DIndexBufferDesc;

begin

Result := false;

SubmitNum := 0;

IndexSize:= 0;

D3DX9.D3DXMatrixIdentity(Matrix);

Position := Point3(0,0,0);

if FileExists( FileName ) = false then exit;//文件不存在

Materials := nil;

MaterialsNum := 0;

if Failed( D3DXLoadMeshFromX( Pchar( FileName ),D3DXMESH_SYSTEMMEM,DXDevice,nil,@Materials,nil,@MaterialsNum,FMesh ) ) then exit;

D3DX9.D3DXComputeNormals(FMesh,nil);

if LoadMaterials(Materials,MaterialsNum) = false then exit;

Materials :=nil;

SubmitNum := MaterialsNum;

Result := true;

buf := nil;

FMesh.GetIndexBuffer(buf);

if buf = nil then exit;

fillchar(Desc,sizeof(TD3DIndexBufferDesc),#0);

buf.GetDesc(Desc);

case Desc.Format of

D3DFMT_INDEX16 : indexSize := 16;

D3DFMT_INDEX32 : indexSize := 32;

else

indexSize := 0;

end;

//包围盒子

Self.BoundingBoxVisible := false;

Self.BoundingBox := nil;

// Messagebox(0,pchar(inttostr(Self.FMesh.GetFVF)),'',0);

//Messagebox( 0,pchar( inttostr( FMesh.GetNumBytesPerVertex ) +':'+ inttostr(FMesh.GetNumFaces)),'',0);

end;

function TVRXMeshLoader.Init(const FaceNum, VertexNum: Cardinal;

const FVF: DWORD;const pVertexElements: PD3DVertexElement9): Boolean;

begin

Result := false;

end;

function TVRXMeshLoader.LoadMaterials(const Mat : ID3DXBuffer;const Num : DWORD): Boolean;

var

Material : PD3DXMaterial;

Buf : Pchar;

index : integer;

begin

Result := false;

if Num = 0 then //本来就没有材质,就用默认材质

begin

SetLength( MaterialList,1 );

MaterialList[0] := TVRMaterial.Create;

Result := true;

exit;

end;

if Mat = nil then exit;

Buf := Mat.GetBufferPointer;

if Buf = nil then exit;

SetLength( MaterialList,Num );

SetLength( TextureList,Num );

for index := 0 to Num - 1 do

begin

Material := PD3DXMaterial(Buf + sizeof(TD3DXMaterial)*index );

//不用考虑Material不存在的情况

MaterialList[index]:=TVRMaterial.Create(Material.MatD3D);

//MaterialList[index].SetAmibent(Color4(177,177,177,255)); //测试的

if not FileExists( Material.pTextureFilename ) then

begin

result := true;

continue;

end;

TextureList[index] := TVRNormalTexture.Create;

if TextureList[index].Init(Material.pTextureFilename) = false then exit;

//暂时不考虑纹理信息

end;

Result := true;

end;

function TVRXMeshLoader.LockAttriBuffer: PDWord;

begin

//attrib是相对于 面为最小单位的

Result := nil;

if Assigned( FMesh ) then

begin

FMesh.LockAttributeBuffer(D3DLOCK_DISCARD,Result);

end;

end;

function TVRXMeshLoader.LockIndexBuffer: PWord;

begin

Result := nil;

if Assigned( FMesh ) then

begin

FMesh.LockIndexBuffer(D3DLOCK_DISCARD,Pointer( Result ));

end;

end;

function TVRXMeshLoader.LockVertexBuffer: Pchar;

begin

Result := nil;

if Assigned( FMesh ) then

begin

FMesh.LockVertexBuffer(D3DLOCK_DISCARD,Pointer( Result )) ;

end;

end;

procedure TVRXMeshLoader.ModifyTexture(const index: integer;

const Texture: IVRTexture);

begin

if index >= Length( TextureList ) then exit;

TextureList[index] := nil;

TextureList[index] := IVRNormalTexture( Texture );

end;

function TVRXMeshLoader.optimizeInPlace : integer;

begin

Result := 0;

end;

procedure TVRXMeshLoader.Render;

var

index : integer;

Indy,Local : TD3DMatrix;

begin

if FMesh = nil then exit;

DXDevice.GetTransform(D3DTS_WORLD,Indy);

D3DX9.D3DXMatrixMultiply(Local,Indy,Matrix);

DXDevice.SetTransform(D3DTS_WORLD,Local);

for index := 0 to SubmitNum - 1 do

begin

MaterialList[index].PrePare;

if TextureList[index] <> nil then

TextureList[index].PrePare(0);

// DXDevice.SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE );

FMesh.DrawSubset(index);

end;

if Self.BoundingBoxVisible then

begin

if Self.BoundingBox <> nil then

begin

Self.BoundingBox.Render;

end;

end;

DXDevice.SetTransform(D3DTS_WORLD,Indy);

end;

procedure TVRXMeshLoader.RotationAxisLocal(const Angle: Single;

const Up: TPoint3);

var

m : TD3DMatrix;

begin

D3DX9.D3DXMatrixRotationAxis(m,VRCommon.Point3ToVector(Up),Angle);

D3DX9.D3DXMatrixMultiply(Matrix,m,Matrix);

end;

procedure TVRXMeshLoader.RotationLocal(const XAngle, YAngle,

ZAngle: Single);

begin

Self.RotationYLocal(XAngle);

Self.RotationYLocal(YAngle);

Self.RotationZLocal(ZAngle);

end;

procedure TVRXMeshLoader.RotationXLocal(const Angle: Single);

var

Local : TD3DMatrix;

begin

D3DX9.D3DXMatrixRotationX( Local,angle );

D3DX9.D3DXMatrixMultiply(Matrix,Local,Matrix);

end;

procedure TVRXMeshLoader.RotationYLocal(const Angle: single);

var

Local : TD3DMatrix;

begin

D3DX9.D3DXMatrixRotationY( Local,angle );

D3DX9.D3DXMatrixMultiply(Matrix,Local,Matrix);

end;

procedure TVRXMeshLoader.RotationZLocal(const Angle: Single);

var

Local : TD3DMatrix;

begin

D3DX9.D3DXMatrixRotationZ( Local,angle );

D3DX9.D3DXMatrixMultiply(Matrix,Local,Matrix);

end;

procedure TVRXMeshLoader.Scale(const value: TPoint3);

var

scalar : TD3DMatrix;

begin

D3DX9.D3DXMatrixScaling(scalar,value.x,value.y,value.z);

D3DX9.D3DXMatrixMultiply(Matrix,scalar,Matrix);

end;

function TVRXMeshLoader.SetAttribTable(

const table: TVRAttriTableArray): Boolean;

begin

Result := false;

end;

procedure TVRXMeshLoader.SetBoundingBox(const Enable: Boolean);

begin

if Self.BoundingBox = nil then

begin

Self.BoundingBox := Self._CreateBoundingBox;

end;

Self.BoundingBoxVisible := Enable;

end;

procedure TVRXMeshLoader.SetMatrix(const Matrix: TD3DMatrix);

begin

Self.Matrix := Matrix;

end;

procedure TVRXMeshLoader.transfer(const Distance: TPoint3);

var

local : TD3DMatrix;

begin

// Local := D3DX9.D3DXMatrix(1,0,0,0,0,1,0,0,0,0,1,0,Distance.x,Distance.y,Distance.z,1);

D3DX9.D3DXMatrixTranslation(Local,Distance.x,Distance.y,Distance.z);

//D3DX9.D3DXMatrixTranslation(local,Distance.x,Distance.y,Distance.z);

D3DX9.D3DXMatrixMultiply(Matrix,Matrix,Local);

Position := Point3Add( Position, Distance );

end;

procedure TVRXMeshLoader.UnInit;

var

index : integer;

begin

for index := 0 to Length(MaterialList) - 1 do

begin

MaterialList[index] := nil;

end;

Self.BoundingBoxVisible := false;

Self.BoundingBox := nil;

FMesh := nil;

end;

procedure TVRXMeshLoader.UnLockAttriBuffer;

begin

if Assigned( FMesh ) then

begin

FMesh.UnlockAttributeBuffer;

end;

end;

procedure TVRXMeshLoader.UnLockIndexBuffer;

begin

if Assigned( FMesh ) then

begin

FMesh.UnlockIndexBuffer;

end;

end;

procedure TVRXMeshLoader.UnLockVertexBuffer;

begin

if Assigned( FMesh )then

begin

FMesh.UnlockVertexBuffer;

end;

end;

function TVRXMeshLoader._CreateBoundingBox: IVRModelObject;

var

Data : Pointer;

Min,Max : TD3DVector;

Mesh : ID3DXMesh;

begin

Result := nil;

if Failed(FMesh.LockVertexBuffer(D3DLOCK_READONLY,Data)) then exit;

try

if Failed(D3DX9.D3DXComputeBoundingBox( PD3DXVector3( Data ), FMesh.GetNumVertices, FMesh.GetNumBytesPerVertex, Min, Max)) then exit;

if Failed( D3DXCreateBox( DXDevice, Max.x - Min.x, Max.y - Min.y, Max.z - Min.z,Mesh,nil) ) then exit;

Result := TVRModelObject.Create;

Result._setD3DXMesh(Mesh);

Finally

Mesh := nil;

FMesh.UnlockVertexBuffer;

end;

end;

function TVRXMeshLoader._getD3DXMesh: ID3DXMesh;

begin

result := Self.FMesh;

end;

procedure TVRXMeshLoader._setD3DXMesh(const Mesh: ID3DXMesh);

begin

Self.FMesh := Mesh;

Self.optimizeInPlace;

end;

end.