C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Как работать с 3D?, Как подгрузить *.3DS и *.MAX в Builder?
Piter_B
  Отправлено: 06.08.2004, 08:44


Не зарегистрирован







Очень нужно знать, как можно подгрузить объекты из 3DSMAX 5 в C++ Builder и как их правильно использовать в нем... Если можно, то дайте исходник или ссылку на ресурсы — как использовать 3D объекты из других программ в C++ Builder.

Буду очень благодарен. sad.gif
Shura
Отправлено: 06.08.2004, 10:29


Дежурный стрелочник

Группа: Участник
Сообщений: 45



формат 3DS -
www.wotsit.org

исходник загрузки
www.gametutorials.com
Piter_B
Отправлено: 06.08.2004, 10:52


Не зарегистрирован







Спасибо! Открыл для себя много ценного...

Кстати, я помоему только-что нарыл тоже много ценного на:

http://www.3dborland.com/downloads.asp

кому надо заходите, мне не жалко! smile.gif

Если есть еще, что-то интересное по этой теме, пишите.
Piter_B
  Отправлено: 07.08.2004, 10:38


Не зарегистрирован







Упс... ohmy.gif
Найти то нашел, но оно на Паскале... Как сие чудо заставить работать в Билдере?

Файл gl3ds.pas:

CODE

//TODO:
//  save skeleton msa and bin
//  save skeleton animations msa and bin
//  load skeleton (with animations) bin
//  clean up code...
//  example load save example (converter)
//  example vertex picking (selection of face)... And assign bone to it...
//  selected propertie for mesh, face, vertex and bone

//02.08.2004 by Noeska Software (now uses glbitmap.pas instead of textures.pas)
//01.08.2004 by Noeska Software (bump mapping)
//27.06.2004 by Noeska Software (do not calculate bounding boxes for non mesh objects)
//20.06.2004 by Noeska Software (bounding boxes per submesh)
//15.06.2004 by Noeska Software (bugfixed: cw to ccw, color loading in msa, transparency)
//14.06.2004 by Noeska Software (changed rendering from cw to ccw, transparency with msa and bin)
//14.06.2004 by SOS (two sided materials)
//15.04.2004 by Noeska Software (bin save and load)
//14.04.2004 by Noeska Software (allow saving of milkshape ascii files)
//12.04.2004 by Noeska Software (seperated bones from mesh using a skeleton class, allows ussage of multiple different bone animations per mesh)
//??.03.2004 by Noeska Software (fixed milkshape ascii support, now works again)
//14.02.2004 by Noeska Software (allow adding faces and assign material to a mesh, not yet optimized)
//08.02.2004 by Noeska Software (allow adding materials and meshes...)
//26.01.2004 by Noeska Software (improved transparency mesh order, corrected skipping light and camera chunks)
//25.01.2004 by Noeska Software (transparency added)
//15.01.2004 by Noeska Software (rewrote (some) source to borland standard, added displaylist renderer)
//06.10.2003 by Noeska Software (ms3d ascii bone animation, thanks to Maarten "McCLaw" Kronberger)
//05.10.2003 by Noeska Software (3ds meshes with no material and no texture coordinates)
//02.10.2003 by Noeska Software (ms3d ascii loader)
//01.10.2003 by Noeska Software (textures are back, added some more properties, SwitchAxesP is not used anymore)
//30.09.2003 by Noeska Software (converted to classes, optimized setting matarial on rendering)
//24.09.2003 by Noeska Software (uses pivot points to draw meshes when needed, removed matrix)
//21.09.2003 by Noeska Software (more then 1 material per submesh, smoothed normals, dummy submeshes)
//18.09.2003 by Noeska Software (rewrite to 1 chunk parser) now it also reads non-standard 3ds files.
//16.09.2003 by Noeska Software
//08.09.2002 by Noeska Software
//01.05.2002 by Jan Michalowsky
//Thx a lot  Prometheus,Poetikus
//Version 2.4a

unit gl3ds;

interface

uses Windows, Classes, SysUtils, DGLOpenGL, GLMath, Math, glBitmap, glMatrix{, logger};

const
 //numbering may change so use names instead of numbers
 MeshBin = 64;   //own bin format...
 MeshMs3d = 16;  //bin milkshape mesh and/or animation
 MeshMsa = 8;    //ascii milkshape mesh and/or animation
 Mesh3dsBvh = 4; //3ds with bvh animation (does not work yet)
 Mesh3dsa = 2;   //3ds with keyframe animation
 Mesh3ds = 1;    //3ds

 //channel types for milkshape bone animation
 ChanneltypeNone = 0;                 //no channel applied
 ChanneltypeScaleRotateTranslate = 1; //scale rotation and translation (bva)
 ChanneltypeTranslate = 2;            //translation x y z
 ChanneltypeRxyz = 4;                 //rotation x y z order
 ChanneltypeRzxy = 8;                 //rotation z x y order
 ChanneltypeRyzx = 16;                //rotation y z x order
 ChanneltypeRzyx = 32;                //rotation z y x order
 ChanneltypeRxzy = 64;                //rotation x z y order
 ChanneltypeRyxz = 128;               //rotation y x z order
 ChanneltypeScale = 256;              //scale only
 ChanneltypeTranslateXyz = 512;       //translate x y z only
 channeltypeInterleaved = 1024;       //multiple channels?

type
 //texturemapping coords
 TMap = packed record
   tu: single;
   tv: single;
 end;

 //keyframe data
 TKeyFrame = packed record
   time: integer;
   Value: T3dPoint;
   bvh_value: T3dPoint;
 end;

 //bone data
 T3dsBone = class(TComponent)
 private
   FName: string;
   FParentName: string;
   FParent: T3dsBone;                   //direct access to the parent bone
   FTranslate: T3dPoint;
   FRotate: T3dPoint;
   FBvhChanneltype: integer;
   FMatrix: ClsMatrix;                  //absolute in accordance to animation
   FNumTranslateFrames: integer;
   FNumRotateFrames: integer;
   FTranslateFrame: array of TKeyFrame;
   FRotateFrame: array of TKeyFrame;
 public
   constructor Create(AOwner: TComponent); override;
   destructor Destroy; override;
   procedure Init;
   procedure Render;
   procedure AdvanceAnimation;
   property Name: string read FName;
   property ParentName: string read FParentName;
   property Translate: T3DPoint read FTranslate;
   property Rotate: T3DPoint read FRotate;
   //TODO: add access to keyframes data
 end;

 T3dsMesh = class(TComponent)
 private
   Fname: string;                 //meshname
   Fid: integer;                  //id for picking...
   Fmatname: array of string;     //array of material names.
   Fnumvertex: integer;           //number of vertexes
   Fnumindices: integer;          //number of faces
   Fpivot: T3DPoint;              //where to draw submesh (also for anim?)
   Fvertex: array of T3dpoint;    //vertexes
   Fboneid: array of integer;     //boneid for a vertex
   Fvnormal: array of T3dPoint;   //vertex normals for smoother meshes
   Fmapping: array of TMap;       //uvmapping
   Fmatid: array of word;         //material for a face
   Findices: array of word;       //faces
   Fnormalindices: array of word; //normal index
   FDisplaylist: integer;         //displaylist id
   FMinimum: T3dPoint;            //min pos
   FMaximum: T3dPoint;            //max pos
   function GetVertex(Index: integer): T3dPoint;
   function GetNormal(Index: integer): T3dPoint;
   function GetMapping(Index: integer): TMap;
   procedure SetMapping(Index: integer; Value: TMap);
   function GetMatID(Index: integer): word;
   function GetFace(Index: integer): word;
 public
   destructor Destroy; override;
   procedure Render;
   procedure RenderBoundBox;
   procedure CalculateSize;
   procedure BuildDisplayList;
   procedure AddFace(v1, v2, v3: T3DPoint; matname: string);
   property Name: string read FName write FName;
   property Id: integer read FId write FId;
   property NumVertex: integer read FNumVertex;
   property NumFaces: integer read FNumIndices;
   property Vertex[Index: integer]: T3dPoint read GetVertex;
   property Normal[Index: integer]: T3dPoint read GetNormal;
   property Mapping[Index: integer]: TMap read GetMapping write SetMapping;
   property MatID[Index: integer]: word read GetMatID;
   property Face[Index: integer]: word read GetFace;
   property Maximum: T3dPoint read FMaximum;
   property Minimum: T3dPoint read FMinimum;
 end;

 T3dsMaterial = class(TComponent)
 private
   FHastexturemap: boolean;
   FHasbumpmap: boolean;
   FHasmaterial: boolean;
   FIsAmbient: boolean;
   FIsDiffuse: boolean;
   FIsSpecular: boolean;
   FTwoSided: boolean;
   FName: string;
   FFileName: string;
   FBumpMapFileName: string;
   FUs: single;
   FVs: single;
   FUoff: single;
   FVoff: single;
   FRot: single;
   FAmbR: single;
   FAmbG: single;
   FAmbB: single;
   FDifR: single;
   FDifG: single;
   FDifB: single;
   FSpcR: single;
   FSpcG: single;
   FSpcB: single;
   FTransparency: single;
   FBumpMapStrength: single;
   FTexId: integer;
   FTexture: TglBitmap2D;
 public
   constructor Create(AOwner: TComponent); override;
   destructor Destroy; override;
   procedure Apply;
   procedure Updatetexture;
   property Name: string read FName write FName;
   property HasMaterial: boolean read FHasMaterial write FHasMaterial;
   property IsAmbient: boolean read FIsambient write FIsambient;
   property IsDiffuse: boolean read FIsdiffuse write FIsdiffuse;
   property IsSpecular: boolean read FIsSpecular write FIsSpecular;
   property TwoSided: boolean read FTwoSided write FTwoSided;
   property HasTexturemap: boolean read FHasTexturemap write FHasTexturemap;
   property HasBumpmap: boolean read FHasBumpmap write FHasBumpmap;
   property TextureFilename: string read FFileName write FFileName;
   property BumpMapFilename: string read FBumpMapFileName write FBumpMapFileName;
   property TextureID: integer read FTexId;
   property Us: single read FUs write FUs;
   property Vs: single read FVs write FVs;
   property Uoff: single read FUoff write FUoff;
   property Voff: single read FVoff write FVoff;
   property Rotate: single read FRot write FRot;
   property AmbientRed: single read FAmbr write FAmbr;
   property AmbientGreen: single read FAmbg write FAmbg;
   property AmbientBlue: single read FAmbb write FAmbb;
   property DiffuseRed: single read FDifr write FDifr;
   property DiffuseGreen: single read FDifg write FDifg;
   property DiffuseBlue: single read FDifb write FDifb;
   property SpecularRed: single read FSpcr write FSpcr;
   property SpecularGreen: single read FSpcg write FSpcg;
   property SpecularBlue: single read FSpcb write FSpcb;
   property Transparency: single read FTransparency write FTransparency;
   property Bumpmapstrength: single read FBumpmapstrength write FBumpMapStrength;    
   property TexID: integer read FTexId write FTexID;
 end;

 TSkeleton = class(TComponent)
 private
   FName: string;
   FBone: array of T3dsBone;
   FNumBones: integer;
   FNumFrames: integer;
   FCurrentFrame: integer;
   function GetBone(Index: integer): T3dsBone;
   procedure LoadBvhFromFile(Filename: string);
   procedure LoadBvhFromStream(Stream: TStream);
   procedure LoadMsaFromFile(filename: string);
   procedure LoadMsaFromStream(stream: Tstream);
 public
   destructor Destroy; override;
   property Name: string read FName write FName;
   property NumBones: integer read FNumBones;
   property NumFrames: integer read FNumFrames;
   property CurrentFrame: integer read FCurrentFrame write FCurrentFrame;
   property Bone[Index: integer]: T3dsBone read GetBone;
   function GetBoneByName(s: string): T3dsBone;
   procedure AdvanceAnimation;
   procedure LoadFromFile(Filename: string);
   procedure LoadFromStream(Stream: TStream);
 end;

 TAll3dsMesh = class(TComponent)
 private
   FName: string;
   FType: integer;
   FMasterScale: single;
   FDisplayList: TGlInt;
   FMesh: array of T3dsMesh;
   FRenderOrder: array of integer;
   FMaterial: array of T3dsMaterial;
   FSkeleton: array of TSkeleton;
   FNumSkeletons: integer;
   FCurrentSkeleton: integer;
   FLoadSkeleton: boolean;
   FMinimum: T3dPoint;
   FMaximum: T3dPoint;
   FVersion: integer;
   FSubVersion: integer;
   FNumMeshes: integer;
   FNumMaterials: integer;
   FTexturePath: string;
   function GetMesh(Index: integer): T3dsMesh;
   function GetMaterial(Index: integer): T3dsMaterial;
   function GetMaterialIdByName(s: string): integer;
   function GetSkeleton(Index: integer): TSkeleton;
   procedure MoveToPivot;
   procedure CalculateScale;
   procedure CalculateRenderOrder;
   procedure LoadMsaFromFile(filename: string);
   procedure LoadMsaFromStream(stream: Tstream);
   procedure Load3dsFromFile(filename: string);
   procedure Load3dsFromStream(stream: Tstream);
   procedure LoadBinFromFile(filename: string);
   procedure LoadBinFromStream(stream: Tstream);
   procedure SaveMsaToFile(filename: string);
   procedure SaveMsaToStream(stream: Tstream);
   procedure SaveBinToFile(filename: string);
   procedure SaveBinToStream(stream: Tstream);
 public
   destructor Destroy; override;
   property Name: string read FName write FName;
   property FileType: integer read FType write FType;
   property MasterScale: single read FMasterScale write FMasterScale;
   property Version: integer read FVersion;
   property SubVersion: integer read FSubVersion;
   property NumMeshes: integer read FNumMeshes;
   property NumMaterials: integer read FNumMaterials;
   property Maximum: T3dPoint read FMaximum;
   property Minimum: T3dPoint read FMinimum;
   property TexturePath: string read FTexturePath write FTexturePath;
   property Mesh[Index: integer]: T3dsMesh read GetMesh;
   property Material[Index: integer]: T3dsMaterial read GetMaterial;
   property Skeleton[Index: integer]: TSkeleton read GetSkeleton;
   property NumSkeletons: integer read FNumSkeletons;
   property CurrentSkeleton: integer read FCurrentSkeleton write FCurrentSkeleton;
   procedure Render;
   procedure RenderBoundBox;
   procedure CalculateSize;
   procedure BuildDisplayList;
   procedure LoadFromFile(Filename: string);
   procedure LoadFromStream(Stream: TStream);
   procedure SaveToFile(Filename: string);
   procedure SaveToStream(Stream: TStream);
   function GetMeshByName(s: string): T3dsMesh;
   function GetMaterialByName(s: string): T3dsMaterial;
   procedure InitSkin;
   procedure CalcVnormals;
   procedure AddMesh;
   procedure AddMaterial;
   procedure AddSkeleton;
 end;

procedure preloadtextures(mesh: Tall3dsMesh);
procedure startpickmode;
procedure endpickmode;

var
 pickmode: boolean;
 pickmesh: boolean;
 pickface: boolean;
 pickvertex: boolean;

 //TODO: also read lights form 3ds file
 //TODO: also make light class...
 objlightpos: T3dPoint; //lightpos needed for bumpmap calculations

implementation

const
 OVersion = 3; //expects 3ds version 3 files

 //Chunk ID's
 //  INT_PERCENTAGE = $0030; //hm transparency always has this subchunck
 MAIN3DS = $4D4D;
 VERS3DS = $0002;
 EDIT3DS = $3D3D;
 KEYF3DS = $B000;

 EDIT_OBJECT = $4000;

 MASTER_SCALE = $0100;

 OBJ_HIDDEN = $4010;
 OBJ_VERINFO = $3D3E;
 OBJ_TRIMESH = $4100;
 OBJ_LIGHT = $4600;
 OBJ_CAMERA = $4700;

 TRI_VERTEXL = $4110;
 TRI_FACEL1 = $4120;
 TRI_MATERIAL = $4130;
 TRI_MAPPINGCOORDS = $4140;
 TRI_MATRIX = $4160;


 MAT_MATRIAL = $AFFF;
 MAT_MATNAME = $A000;
 MAT_AMBIENT = $A010;
 MAT_DIFFUSE = $A020;
 MAT_SPECULAR = $A030;
 MAT_TRANSPARENCY = $A050; // Transparency Material
 MAT_TEXTURE = $A200;  //texmap
 MAT_BUMPMAP = $A230;
 MAT_MAPFILE = $A300;
 MAT_VSCALE = $A354;
 MAT_USCALE = $A356;
 MAT_VOFF = $A35A;
 MAT_UOFF = $A358;
 MAT_TEXROT = $A35C;
 MAT_COLOR = $0010;
 MAT_COLOR24 = $0011;
 MAT_TWO_SIDE = $A081; //thanks sos

 KEYF_OBJDES = $B002;
 KEYF_OBJHIERARCH = $B010;
 KEYF_OBJPIVOT = $B013;

type
 T3DSColor = packed record
   r, g, b: single;
 end;

 rgb = packed record
   r, g, b: byte
 end;

 TChunkHdr = packed record
   chunkID: word;
   chunkLE: longword;
 end;

procedure startpickmode;
begin
 pickmode:=true;
 glDisable(GL_LIGHTING);
 glDisable(GL_DITHER);
end;

procedure endpickmode;
begin
 pickmode:=false;
 glEnable(GL_LIGHTING);
 glEnable(GL_DITHER);
end;

//T3DSBone routines ...
constructor T3DSBone.Create(AOwner: TComponent);
begin
 inherited Create(AOWner);
 FMatrix := clsMatrix.Create;
end;

destructor T3DSBone.Destroy;
begin
 FMatrix.Free;
 SetLength(FTranslateFrame, 0);
 SetLength(FRotateFrame, 0);
 //free parent also?
 inherited Destroy;
end;

procedure T3DSBone.init;
var
 m_rel: clsMatrix;
 tempm: array [0..15] of single;
 tempv: array [0..2] of single;
begin
 glpushmatrix();

 //init parent bone direct access
 FParent := nil;
 if FParentName > '' then
   FParent := TSkeleton(owner).GetBoneByName(FParentName);

 //calculate the matrix for the bone
 m_rel := clsMatrix.Create;
 //m_rel.loadIdentity;
 // Create a transformation matrix from the position and rotation
 tempv[0] := FRotate.x;
 tempv[1] := FRotate.y;
 tempv[2] := FRotate.z;
 m_rel.setRotationRadians(tempv);


 tempv[0] := FTranslate.x;
 tempv[1] := FTranslate.y;
 tempv[2] := FTranslate.z;
 m_rel.setTranslation(tempv);

 // Each bone's final matrix is its relative matrix concatenated onto its
 // parent's final matrix (which in turn is ....)
 if (FParent = nil) then
 begin
   m_rel.getMatrix(tempm);
   FMatrix.setMatrixValues(tempm);
 end
 else
 begin
   FParent.FMatrix.getMatrix(tempm);
   FMatrix.setMatrixValues(tempm);
   FMatrix.postMultiply(m_rel);
 end;

 m_rel.Free;

 glpopmatrix();
end;

procedure T3DSBone.render;
var
 parentvertex, vertex: T3DPoint;

begin
 vertex.x := 0;
 vertex.y := 0;
 vertex.z := 0;
 vertex := MatrixTransform(FMatrix, Vertex);

 if FParent <> nil then
 begin
   parentvertex.x := 0;
   parentvertex.y := 0;
   parentvertex.z := 0;
   parentvertex := MatrixTransform(FParent.FMatrix, ParentVertex);
 end;

 glPointSize(4.0);
 glBegin(GL_POINTS);
 glvertex3fv(@vertex);
 glend;

 if FParent <> nil then
 begin
   glBegin(GL_LINES);
   glvertex3fv(@vertex);
   glvertex3fv(@parentvertex);
   glend;

   glPointSize(4.0);
   glBegin(GL_POINTS);
   glvertex3fv(@parentvertex);
   glend;
 end;
end;

procedure T3DSBone.AdvanceAnimation;
var
 i: integer;
 deltaTime: single;
 fraction: single;
 Position: array [0..2] of single;
 Rotation: array [0..2] of single;
 m_rel, m_frame: clsMatrix;
 tempm: array [0..15] of single;
 tvec: array [0..2] of single;
begin
 // Position

 // Find appropriate position key frame
 i := 0;
 while ((i < FNumTranslateFrames — 1) and (FTranslateFrame[i].Time <
   TSkeleton(owner).FCurrentFrame)) do
   i := i + 1;

 if (i > 0) then
 begin
   // Interpolate between 2 key frames

   // time between the 2 key frames
   deltaTime := FTranslateFrame[i].Time — FTransLateFrame[i — 1].Time;

   // relative position of interpolation point to the keyframes [0..1]
   fraction := (TSkeleton(owner).FCurrentFrame — FTransLateFrame[i — 1].Time) / deltaTime;

   Position[0] := FTransLateFrame[i — 1].Value.x + fraction *
     (FTransLateFrame[i].Value.x — FTransLateFrame[i — 1].Value.x);
   Position[1] := FTransLateFrame[i — 1].Value.y + fraction *
     (FTransLateFrame[i].Value.y — FTransLateFrame[i — 1].Value.y);
   Position[2] := FTransLateFrame[i — 1].Value.z + fraction *
     (FTransLateFrame[i].Value.z — FTransLateFrame[i — 1].Value.z);
 end
 else
 begin
   Position[0] := FTransLateFrame[i].Value.x;
   Position[1] := FTransLateFrame[i].Value.y;
   Position[2] := FTransLateFrame[i].Value.z;
 end;

 // Rotation

 // Find appropriate rotation key frame
 i := 0;
 while ((i < FNumRotateFrames — 1) and (FRotateFrame[i].Time <
   TSkeleton(owner).CurrentFrame)) do
   i := i + 1;

 if (i > 0) then
 begin
   // Interpolate between 2 key frames

   // time between the 2 key frames
   deltaTime := FRotateFrame[i].Time — FRotateFrame[i — 1].Time;

   // relative position of interpolation point to the keyframes [0..1]
   fraction := ({TAll3DSMesh}TSkeleton(Owner).CurrentFrame — FRotateFrame[i — 1].Time) / deltaTime;

   Rotation[0] := FRotateFrame[i — 1].Value.x + fraction *
     (FRotateFrame[i].Value.x — FRotateFrame[i — 1].Value.x);
   Rotation[1] := FRotateFrame[i — 1].Value.y + fraction *
     (FRotateFrame[i].Value.y — FRotateFrame[i — 1].Value.y);
   Rotation[2] := FRotateFrame[i — 1].Value.z + fraction *
     (FRotateFrame[i].Value.z — FRotateFrame[i — 1].Value.z);
 end
 else
 begin
   Rotation[0] := FRotateFrame[i].Value.x;
   Rotation[1] := FRotateFrame[i].Value.y;
   Rotation[2] := FRotateFrame[i].Value.z;
 end;

 // Now we know the position and rotation for this animation frame.
 // Let's calculate the transformation matrix (_matrix) for this bone...

 m_rel := clsMatrix.Create;
 m_frame := clsMatrix.Create;

 // Create a transformation matrix from the position and rotation of this
 // joint in the rest position
 tvec[0] := FRotate.x;
 tvec[1] := FRotate.y;
 tvec[2] := FRotate.z;

 m_rel.setRotationRadians(tvec);

 tvec[0] := FTranslate.x;
 tvec[1] := FTranslate.y;
 tvec[2] := FTranslate.z;

 m_rel.setTranslation(tvec);

 // Create a transformation matrix from the position and rotation
 // m_frame: additional transformation for this frame of the animation

 m_frame.setRotationRadians(Rotation);

 m_frame.setTranslation(Position);

 // Add the animation state to the rest position
 m_rel.postMultiply(m_frame);

 if (FParent = nil) then // this is the root node
 begin
   m_rel.getMatrix(tempm);
   FMatrix.setMatrixValues(tempm);  // _matrix := m_rel
 end
 else                  // not the root node
 begin
   // _matrix := parent's _matrix * m_rel (matrix concatenation)
   FParent.FMatrix.getMatrix(tempm);
   FMatrix.setMatrixValues(tempm);
   FMatrix.postMultiply(m_rel);
 end;

 m_frame.Free;
 m_rel.Free;
end;

//TSkeleton routines ...
procedure TSkeleton.LoadFromFile(filename: string);
begin
 fname:=filename;
 if LowerCase(copy(filename, length(filename) — 3, 4)) = '.bvh' then
   LoadBVHFromFile(Filename);
 if LowerCase(copy(filename, length(filename) — 3, 4)) = '.txt' then
   LoadMSAFromFile(Filename);
end;

procedure TSkeleton.LoadFromStream(stream: Tstream);
begin
 if TAll3dsMesh(owner).FType = Mesh3dsBVH then
   LoadBVHFromStream(stream);
 if TAll3dsMesh(owner).FType = MeshMsa then
   LoadMSAFromStream(stream);
end;

destructor TSkeleton.Destroy;
begin
 inherited Destroy; //this will automaticaly free the meshes, materials, bones...
 //however do free the dynamic arrays used
 SetLength(FBone, 0);
end;

function TSkeleton.GetBoneByName(s: string): T3DSBone;
var
 i: word;
begin
 Result := nil;
 for i := 0 to High(FBone) do
   if uppercase(FBone[i].FName) = uppercase(s) then
   begin
     Result := FBone[i];
     break;
   end;
end;

procedure TSkeleton.AdvanceAnimation;
var
 m: integer;
begin
 //increase the currentframe
 FCurrentFrame := FCurrentFrame + 1;
 if FCurrentFrame > FNumFrames then FCurrentFrame := 1; //reset when needed

 //set the bones to their new positions
 if FNumBones > 0 then
   for m := 0 to FNumBones — 1 do
   begin
     FBone[m].AdvanceAnimation;
   end;
end;

function TSkeleton.GetBone(Index: integer): T3DSBone;
begin
 Result := FBone[index];
end;

procedure TSkeleton.LoadBvhFromFile(filename: string);
var
 stream: TFileStream;
begin
 TAll3dsMesh(owner).FType := Mesh3dsBvh;

 stream := TFilestream.Create(Filename, fmOpenRead);
 LoadBvhFromStream(stream);
 stream.Free;
end;

procedure TSkeleton.LoadBvhFromStream(stream: Tstream);
var
 mem: TStringList;
 parseline: TStringList;
 loop, parselineloop: integer;
 line: string;
 tbld, tempbonelevel, bonelevel, maxbonelevel, childparentbone,
 parentbone, channelcount, framecount: integer;
 endsite: boolean;
 tempparentname: string;
 m: integer;
 downlevel: boolean;
 nbl: integer;
 First: boolean;

 mybone: integer;
begin
 TAll3dsMesh(owner).FType := Mesh3dsBvh;

 // Create a StringList and load in BVH file
 mem := TStringList.Create;
 mem.loadfromstream(stream);

 channelcount := 0;

 bonelevel := 0;
 tempbonelevel := 0;
 maxbonelevel := 0;
 nbl := 0;
 endsite := False;

 // Parse through the whole BVH file
 for loop := 0 to mem.Count — 1 do
 begin
   line := mem.Strings[loop];
   if Line <> '' then
   begin
     //Set bone hierarchie level up
     if Pos('{', lowercase(line)) > 0 then
     begin
       bonelevel := bonelevel + 1; //points to parent bone id
       //downlevel:=false;
     end;

     //Set bone hierarchie level down
     if Pos('}', lowercase(line)) > 0 then
     begin
       bonelevel := bonelevel — 1;
       downlevel := True;
     end;

     //Find End Site joint
     if Pos('end site', lowercase(line)) > 0 then
     begin
       endsite := True;
       //ignore it for the time being (later make it a bone?)
       //treat it like a bone with no anim data put with a position?
     end;

     //Find root bone
     if Pos('root', lowercase(line)) > 0 then
     begin
       maxbonelevel := maxbonelevel + 1;
       FNumBones := maxbonelevel;
       setlength(FBone, maxbonelevel);
       FBone[maxbonelevel — 1] := t3dsbone.Create(self);
       FBone[maxbonelevel — 1].FName :=
         trim(copy(line, Pos('root', lowercase(line)) + 5,Length(line) — Pos('root',
         lowercase(line)) + 5));
       FBone[maxbonelevel — 1].FParentname := ''; //no parent;

       tempparentname := FBone[maxbonelevel — 1].FName;
     end;

     //Find child bone
     if Pos('joint', lowercase(line)) > 0 then
     begin
       maxbonelevel := maxbonelevel + 1;
       FNumBones := maxbonelevel;

       setlength(FBone, maxbonelevel);
       FBone[maxbonelevel — 1] := t3dsbone.Create(self);

       FBone[maxbonelevel — 1].FName :=
         trim(copy(line, Pos('joint', lowercase(line)) + 5,Length(line) — Pos('root',
         lowercase(line)) + 5));
       FBone[maxbonelevel — 1].FParentname := tempparentname;

       tempparentname := FBone[maxbonelevel — 1].FName;

       if downlevel then
       begin

         FBone[maxbonelevel — 1].FParentname :=
           FBone[bonelevel — 1].FName;
         downlevel := False;
       end;

     end;

     //Find the offset (translate) for the current bone
     if Pos('offset', lowercase(line)) > 0 then
     begin
       if endsite = False then
       begin
         //create a stringlist for current frame values
         parseline := TStringList.Create;

         //sepperate the values frim line in a list
         parseline.CommaText :=
           trim(copy(line, Pos('offset', lowercase(line)) + 7,Length(line) — Pos('offset',
           lowercase(line)) + 7));;

         FBone[maxbonelevel — 1].FTranslate.x :=
           StrToFloat(ParseLine.Strings[0]);
         FBone[maxbonelevel — 1].FTranslate.y :=
           StrToFloat(ParseLine.Strings[1]);
         FBone[maxbonelevel — 1].FTranslate.z :=
           StrToFloat(ParseLine.Strings[2]);

         //no rotation in the skeleton definition of bvh
         FBone[maxbonelevel — 1].FRotate.x := 0.0;
         FBone[maxbonelevel — 1].FRotate.y := 0.0;
         FBone[maxbonelevel — 1].FRotate.z := 0.0;

         //destroy the stringlist for parsing the currentframe
         parseline.Clear;
         parseline.Free;
       end
       else
       begin
         endsite := False;
       end;
     end;

     //Find the channels (like xrot, xpos, yrot ...)
     if Pos('channels', lowercase(line)) > 0 then
     begin
       if endsite = False then
       begin
         //create a stringlist for current frame values
         parseline := TStringList.Create;

         //sepperate the values frim line in a list
         parseline.CommaText :=
           trim(copy(lowercase(line), Pos('channels', lowercase(line)) + 9,Length(line)
           - Pos('channels', lowercase(line)) + 9));

         //read in the frametypes
         if bonelevel > 1 then
         begin
           //for child bones
           channelcount := channelcount + StrToInt(ParseLine.Strings[0]);

           //find rotatation order...
           if ParseLine.Strings[1] = 'xposition' then
           begin
             FBone[maxbonelevel — 1].FBvhChanneltype :=
               ChanneltypeTranslate;
             if (ParseLine.Strings[4] = 'xrotation') and
               (ParseLine.Strings[5] = 'yrotation') and (ParseLine.Strings[6] = 'zrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := Channeltypetranslate + ChanneltypeRxyz;
             if (ParseLine.Strings[4] = 'zrotation') and
               (ParseLine.Strings[5] = 'xrotation') and (ParseLine.Strings[6] = 'yrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeTranslate + ChanneltypeRzxy;
             if (ParseLine.Strings[4] = 'yrotation') and
               (ParseLine.Strings[5] = 'zrotation') and (ParseLine.Strings[6] = 'xrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeTranslate + ChanneltypeRyzx;
             if (ParseLine.Strings[4] = 'zrotation') and
               (ParseLine.Strings[5] = 'yrotation') and (ParseLine.Strings[6] = 'xrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeTranslate + ChanneltypeRzyx;
             if (ParseLine.Strings[4] = 'xrotation') and
               (ParseLine.Strings[5] = 'zrotation') and (ParseLine.Strings[6] = 'yrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeTranslate + ChanneltypeRxzy;
             if (ParseLine.Strings[4] = 'yrotation') and
               (ParseLine.Strings[5] = 'xrotation') and (ParseLine.Strings[6] = 'zrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := channeltypeTranslate + ChanneltypeRyxz;
           end;
           if (ParseLine.Strings[1] = 'xrotation') and
             (ParseLine.Strings[2] = 'yrotation') and (ParseLine.Strings[3] = 'zrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRxyz;
           if (ParseLine.Strings[1] = 'zrotation') and
             (ParseLine.Strings[2] = 'xrotation') and (ParseLine.Strings[3] = 'yrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRzxy;
           if (ParseLine.Strings[1] = 'yrotation') and
             (ParseLine.Strings[2] = 'zrotation') and (ParseLine.Strings[3] = 'xrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRyzx;
           if (ParseLine.Strings[1] = 'zrotation') and
             (ParseLine.Strings[2] = 'yrotation') and (ParseLine.Strings[3] = 'xrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRzyx;
           if (ParseLine.Strings[1] = 'xrotation') and
             (ParseLine.Strings[2] = 'zrotation') and (ParseLine.Strings[3] = 'yrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRxzy;
           if (ParseLine.Strings[1] = 'yrotation') and
             (ParseLine.Strings[2] = 'xrotation') and (ParseLine.Strings[3] = 'zrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRyxz;
         end
         else
         begin
           // for the root bone
           channelcount := channelcount + StrToInt(ParseLine.Strings[0]);

           //find rotatation order...
           if ParseLine.Strings[1] = 'xposition' then
           begin
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeTranslate;
             if (ParseLine.Strings[4] = 'xrotation') and
               (ParseLine.Strings[5] = 'yrotation') and (ParseLine.Strings[6] = 'zrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeTranslate + ChanneltypeRxyz;
             if (ParseLine.Strings[4] = 'zrotation') and
               (ParseLine.Strings[5] = 'xrotation') and (ParseLine.Strings[6] = 'yrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeTranslate + ChanneltypeRzxy;
             if (ParseLine.Strings[4] = 'yrotation') and
               (ParseLine.Strings[5] = 'zrotation') and (ParseLine.Strings[6] = 'xrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeTranslate + ChanneltypeRyzx;
             if (ParseLine.Strings[4] = 'zrotation') and
               (ParseLine.Strings[5] = 'yrotation') and (ParseLine.Strings[6] = 'xrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeTranslate + ChanneltypeRzyx;
             if (ParseLine.Strings[4] = 'xrotation') and
               (ParseLine.Strings[5] = 'zrotation') and (ParseLine.Strings[6] = 'yrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeTranslate + ChanneltypeRxzy;
             if (ParseLine.Strings[4] = 'yrotation') and
               (ParseLine.Strings[5] = 'xrotation') and (ParseLine.Strings[6] = 'zrotation') then
               FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeTranslate + ChanneltypeRyxz;
           end;
           if (ParseLine.Strings[1] = 'xrotation') and
             (ParseLine.Strings[2] = 'yrotation') and (ParseLine.Strings[3] = 'zrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRxyz;
           if (ParseLine.Strings[1] = 'zrotation') and
             (ParseLine.Strings[2] = 'xrotation') and (ParseLine.Strings[3] = 'yrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRzxy;
           if (ParseLine.Strings[1] = 'yrotation') and
             (ParseLine.Strings[2] = 'zrotation') and (ParseLine.Strings[3] = 'xrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRyzx;
           if (ParseLine.Strings[1] = 'zrotation') and
             (ParseLine.Strings[2] = 'yrotation') and (ParseLine.Strings[3] = 'xrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRzyx;
           if (ParseLine.Strings[1] = 'xrotation') and
             (ParseLine.Strings[2] = 'zrotation') and (ParseLine.Strings[3] = 'yrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRxzy;
           if (ParseLine.Strings[1] = 'yrotation') and
             (ParseLine.Strings[2] = 'xrotation') and (ParseLine.Strings[3] = 'zrotation') then
             FBone[maxbonelevel — 1].FBvhChanneltype := ChanneltypeRyxz;
         end;
         //destroy the stringlist for parsing the current bone frametypes
         parseline.Clear;
         parseline.Free;
       end
       else
       begin
         endsite := False;
       end;
     end;

     //Find number of Frames
     if Pos('frames', lowercase(line)) > 0 then
     begin
       FNumFrames := StrToInt(trim(copy(line,
         Pos(':', lowercase(line)) + 1,Length(line) — Pos(':', lowercase(line)) + 1)));
       FCurrentFrame := 0; //reset currentframe!
     end;

     //read in animation
     if (Pos('end site', lowercase(line)) = 0) and
       (Pos('{', lowercase(line)) = 0) and (Pos('}', lowercase(line)) = 0) and
       (Pos('root', lowercase(line)) = 0) and (Pos('joint', lowercase(line)) = 0) and
       (Pos('offset', lowercase(line)) = 0) and (Pos('hierarchy', lowercase(line)) = 0) and
       (Pos('motion', lowercase(line)) = 0) and (Pos('frame time', lowercase(line)) = 0) and
       (Pos('frames', lowercase(line)) = 0) and (Pos('channels', lowercase(line)) = 0) then
     begin
       FCurrentFrame := FCurrentFrame + 1;

       //create a stringlist for current frame values
       parseline := TStringList.Create;

       //sepperate the values frim line in a list
       parseline.CommaText := line;

       parselineloop := 0;
       mybone := 0;

       for m := 0 to FNumBones — 1 do
       begin
         if mybone <> m then
         begin
           mybone := m;
           //parselineloop:=0;
         end;

         FBone[m].FNumTranslateFrames := FNumFrames;
         FBone[m].FNumRotateFrames := FNumFrames;
         SetLength(FBone[m].FTranslateFrame, FNumframes);
         SetLength(FBone[m].FRotateFrame, FNumframes);

         if FBone[m].FBvhChanneltype = ChanneltypeTranslate + ChanneltypeRxzy then
         begin
           FBone[m].FTranslateframe[FCurrentFrame — 1].time := FCurrentFrame;
           FBone[m].FRotateframe[FCurrentFrame — 1].time := FCurrentFrame;
           FBone[m].FTranslateframe[FCurrentFrame — 1].bvh_value.x :=
             StrToFloat(parseline.strings[parselineloop + 0]);
           FBone[m].FTranslateframe[FCurrentFrame — 1].bvh_value.y :=
             StrToFloat(parseline.strings[parselineloop + 1]);
           FBone[m].FTranslateframe[FCurrentFrame — 1].bvh_value.z :=
             StrToFloat(parseline.strings[parselineloop + 2]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.x :=
             StrToFloat(parseline.strings[parselineloop + 3]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.y :=
             StrToFloat(parseline.strings[parselineloop + 4]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.z :=
             StrToFloat(parseline.strings[parselineloop + 5]);

           parselineloop := parselineloop + 6;
         end;

         if FBone[m].FBvhChanneltype = ChanneltypeRxzy then
         begin
           FBone[m].FRotateframe[FCurrentFrame — 1].time := FCurrentFrame;
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.x :=
             StrToFloat(parseline.strings[parselineloop + 0]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.z :=
             StrToFloat(parseline.strings[parselineloop + 1]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.y :=
             StrToFloat(parseline.strings[parselineloop + 2]);

           parselineloop := parselineloop + 3;
         end;

         if FBone[m].FBvhChanneltype = ChanneltypeRxyz then
         begin
           FBone[m].FRotateframe[FCurrentFrame — 1].time := FCurrentFrame;
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.x :=
             StrToFloat(parseline.strings[parselineloop + 0]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.y :=
             StrToFloat(parseline.strings[parselineloop + 1]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.z :=
             StrToFloat(parseline.strings[parselineloop + 2]);
           parselineloop := parselineloop + 3;
         end;

         if FBone[m].FBvhChanneltype = ChanneltypeRzxy then
         begin
           FBone[m].FRotateframe[FCurrentFrame — 1].time := FCurrentFrame;
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.z :=
             StrToFloat(parseline.strings[parselineloop + 0]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.x :=
             StrToFloat(parseline.strings[parselineloop + 1]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.y :=
             StrToFloat(parseline.strings[parselineloop + 2]);
           parselineloop := parselineloop + 3;
         end;

         if FBone[m].FBvhChanneltype = ChanneltypeRyzx then
         begin
           FBone[m].FRotateframe[FCurrentFrame — 1].time := FCurrentFrame;
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.y :=
             StrToFloat(parseline.strings[parselineloop + 0]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.z :=
             StrToFloat(parseline.strings[parselineloop + 1]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.x :=
             StrToFloat(parseline.strings[parselineloop + 2]);
           parselineloop := parselineloop + 3;
         end;

         if FBone[m].FBvhChanneltype = ChanneltypeRzyx then
         begin
           FBone[m].FRotateframe[FCurrentFrame — 1].time := CurrentFrame;
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.z :=
             StrToFloat(parseline.strings[parselineloop + 0]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.y :=
             StrToFloat(parseline.strings[parselineloop + 1]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.x :=
             StrToFloat(parseline.strings[parselineloop + 2]);
           parselineloop := parselineloop + 3;
         end;

         if FBone[m].FBvhChanneltype = ChanneltypeRyxz then
         begin
           FBone[m].FRotateframe[FCurrentFrame — 1].time := FCurrentFrame;
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.y :=
             StrToFloat(parseline.strings[parselineloop + 0]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.x :=
             StrToFloat(parseline.strings[parselineloop + 1]);
           FBone[m].FRotateframe[FCurrentFrame — 1].bvh_value.z :=
             StrToFloat(parseline.strings[parselineloop + 2]);
           parselineloop := parselineloop + 3;
         end;

         FBone[m].FRotateframe[FCurrentFrame — 1].Value.x :=
           degtorad(FBone[m].
Gedeon
Отправлено: 09.08.2004, 11:52


Ветеран

Группа: Модератор
Сообщений: 1742



Подключить к проекту pas файл и работать с ним.
Dima
Отправлено: 09.08.2004, 12:07


Дежурный стрелочник

Группа: Участник
Сообщений: 61




OpenGL

Вернуться в Вопросы программирования в C++Builder