📄 model.pas
字号:
AssignFile(F, filename);
Reset(F,1);
// copy name
MD3Name :=Filename;
// read header
BlockRead(F, Header, Sizeof(Header));
if (Uppercase(Header.ID) <> 'IDP3') OR (Header.Version <> 15) then
begin
CloseFile(F);
exit;
end;
// read boneframes
SetLength(BoneFrames, Header.numBoneFrames);
BlockRead(F, BoneFrames[0], Header.numBoneFrames*sizeof(TBoneFrame));
// read tags
SetLength(Tags, Header.numBoneFrames * Header.numTags);
BlockRead(F, Tags[0], Header.numBoneFrames*Header.numTags*sizeof(TTag));
// init links
SetLength(Links, Header.numTags);
for I :=0 to Header.NumTags-1 do
Links[I] :=nil;
// read meshes
SetLength(Meshes, Header.numMeshes);
MeshOffset := FilePos(F);
For I :=0 to Header.numMeshes-1 do
begin
Seek(F, MeshOffset);
BlockRead(F, Meshes[I].MeshHeader, sizeOf(TMeshHeader));
// Load the Skins
SetLength(Meshes[I].Skins, Meshes[I].MeshHeader.numSkins);
BlockRead(F, Meshes[I].Skins[0], 68 * Meshes[I].MeshHeader.numSkins);
// Triangles
Seek(F, MeshOffset + Meshes[I].MeshHeader.triStart);
SetLength(Meshes[I].Triangle, Meshes[I].MeshHeader.numTriangles);
BlockRead(F, Meshes[I].Triangle[0], sizeOf(TTriangle)*Meshes[I].MeshHeader.numTriangles);
// Texture Coordiantes
Seek(F, MeshOffset + Meshes[I].MeshHeader.TexVectorStart);
SetLength(Meshes[I].TexCoord, Meshes[I].MeshHeader.numVertexes);
BlockRead(F, Meshes[I].TexCoord[0], sizeOf(TTexCoord)*Meshes[I].MeshHeader.numVertexes);
// Vertices
Seek(F, MeshOffset + Meshes[I].MeshHeader.VertexStart);
SetLength(Meshes[I].Vertex, Meshes[I].MeshHeader.numVertexes * Meshes[I].MeshHeader.numMeshFrames);
BlockRead(F, Meshes[I].Vertex[0], sizeOf(TVertex)*Meshes[I].MeshHeader.numVertexes * Meshes[I].MeshHeader.numMeshFrames);
MeshOffset :=MeshOffset + Meshes[I].MeshHeader.MeshSize;
end;
CloseFile(F);
// set the start, end frame
Header.numBoneFrames :=Header.numBoneFrames - 1;
startFrame := 0;
endFrame := Header.numBoneFrames;
end;
{-------------------------------------------------------------}
{--- Draws the model and other models linked to this model ---}
{-------------------------------------------------------------}
procedure TMD3Model.DrawSkeleton(var Mdl : TMD3Model);
var I : Integer;
pMdl : PMD3Model;
m : Array[0..15] of glFloat;
Rotation : TRotationMatrix;
Position : TVector;
begin
Mdl.DrawModel;
for I :=0 to Mdl.Header.numTags-1 do
begin
pMdl :=Mdl.Links[i];
if pMdl <> nil then
begin
Position :=Mdl.tags[Mdl.frame * Mdl.Header.numTags + i].Position;
Rotation :=Mdl.Tags[Mdl.Frame * Mdl.Header.numTags + i].Rotation;
m[0] := Rotation[0, 0];
m[1] := Rotation[0, 1];
m[2] := Rotation[0, 2];
m[3] := 0;
m[4] := Rotation[1, 0];
m[5] := Rotation[1, 1];
m[6] := Rotation[1, 2];
m[7] := 0;
m[8] := Rotation[2, 0];
m[9] := Rotation[2, 1];
m[10]:= Rotation[2, 2];
m[11]:= 0;
m[12] := position[0];
m[13] := position[1];
m[14] := position[2];
m[15] := 1;
glPushMatrix();
glMultMatrixf(@m);
DrawSkeleton(pMdl^);
glPopMatrix();
end;
end;
end;
{---------------------------------------------------------}
{--- Loads the skins for the model from the .skin file ---}
{---------------------------------------------------------}
procedure TMD3Model.LoadSkin(Imagepath, filename : String);
var F : TextFile;
I : Integer;
S : String;
MeshName, ImageName : String;
begin
if FileExists(Imagepath + filename) then
begin
AssignFile(F,Imagepath + filename);
Reset(F);
while EOF(F) = FALSE do
begin
Readln(F, S);
if Length(S) > 1 then
begin
if Pos(',', S)+1 < Length(S) then // there must be something after the comma
begin
MeshName :=Copy(S, 1, Pos(',', S)-1);
if Copy(MeshName, 1, 4) <> 'tag_' then // tags dont have skins
begin
ImageName :=Copy(S, Pos(',', S)+1, Length(S)); // get the full image and path name
ImageName :=StrRScan(PChar(S), '/'); // get name from last / (i.e only filename)
ImageName :=Copy(ImageName, 2, Length(ImageName)); // lose the starting /
// if its a TGA or JPG, then load the skin
if (pos('.JPG', UpperCase(ImageName)) > 0) OR (pos('.TGA', UpperCase(ImageName)) > 0) then
begin
// Find the right mesh item to assign the skin to
for I :=0 to header.numMeshes-1 do
begin
// check it the two names are the same
if UpperCase(CharArrToStr(meshes[i].MeshHeader.Name)) = Uppercase(meshname) then
begin
LoadTexture(ImagePath + ImageName, meshes[i].Texture, FALSE);
meshes[i].SetTexture :=TRUE;
end;
end;
end;
end;
end;
end;
end;
CloseFile(F);
end;
end;
{---------------------------------------------------------}
{--- Updates the active frame for the model ---}
{---------------------------------------------------------}
procedure TMD3Model.UpdateFrame(Time : glFLoat);
begin
Poll :=(Time - LastUpdate);
if Poll > 1/FPS then
begin
frame :=NextFrame;
Inc(NextFrame);
if NextFrame > EndFrame then
NextFrame :=StartFrame;
LastUpdate :=Time;
end;
end;
{--- Q3Player ---}
{---------------------------------------------------------}
{--- Draws the models associated with the Players ---}
{---------------------------------------------------------}
procedure Q3Player.Draw(time : glFLoat);
begin
Lower.UpdateFrame(time);
Upper.UpdateFrame(time);
Head.UpdateFrame(time);
Lower.DrawSkeleton(Lower);
end;
{---------------------------------------------------------}
{--- Loads animation for the player. (animation.cfg) ---}
{---------------------------------------------------------}
procedure Q3Player.LoadAnim(filename: String);
var F : Text;
S : String;
I, P, skip : Integer;
begin
if FileExists(filename) = FALSE then
exit;
AssignFile(F, filename);
Reset(F);
I :=0;
while EOF(F) = false do
begin
Readln(F, S);
if Pos('sex', S) > 0 then
else if Pos('headoffset', S) > 0 then
else if Pos('footsteps', S) > 0 then
else if (S <> '') AND (Pos('//', S) > 5) then
begin
// Extract the values of FirstFrame, numFrames, LoopingFrames, FPS from the String
P :=Pos(#9, S);
Anim[i].FirstFrame :=StrToInt(Copy(S, 1, P-1));
S :=Copy(S, P+1, Length(S));
P :=Pos(#9, S);
Anim[i].numFrames :=StrToInt(Copy(S, 1, P-1));
S :=Copy(S, P+1, Length(S));
P :=Pos(#9, S);
Anim[i].loopingFrames :=StrToInt(Copy(S, 1, P-1));
S :=Copy(S, P+1, Length(S));
P :=Pos(#9, S);
if P < 0 then P :=Length(S)+1;
Anim[i].FPS :=StrToInt(Copy(S, 1, P-1));
Inc(I);
end;
end;
CloseFile(F);
skip := anim[LEGS_WALKCR].firstFrame - anim[TORSO_GESTURE].firstFrame;
for I :=LEGS_WALKCR to MAX_ANIMATIONS do
Anim[I].firstFrame := Anim[I].firstFrame - skip;
for I :=0 to MAX_ANIMATIONS do
if Anim[I].numFrames > 0 then
Anim[I].numFrames :=Anim[I].numFrames - 1;
end;
{---------------------------------------------------------}
{--- Sets the new animation sequence for the player ---}
{---------------------------------------------------------}
procedure Q3Player.SetAnim(ani : Integer);
begin
if ani in [0..5] then
begin
Lower.FPS :=anim[ani].FPS;
Upper.FPS :=anim[ani].FPS;
Lower.StartFrame :=anim[ani].FirstFrame;
Upper.StartFrame :=anim[ani].FirstFrame;
Lower.EndFrame :=anim[ani].FirstFrame + anim[ani].numFrames;
Upper.EndFrame :=anim[ani].FirstFrame + anim[ani].numFrames;
animLower :=ani;
animUpper :=ani;
end
else if ani in [6..12] then
begin
Upper.FPS :=anim[ani].FPS;
Upper.NextFrame :=anim[ani].FirstFrame;
Upper.StartFrame :=anim[ani].FirstFrame;
Upper.EndFrame :=anim[ani].FirstFrame + anim[ani].numFrames;
animUpper :=ani;
end
else if ani in [13..24] then
begin
Lower.FPS :=anim[ani].FPS;
Lower.NextFrame :=anim[ani].FirstFrame;
Lower.StartFrame :=anim[ani].FirstFrame;
Lower.EndFrame :=anim[ani].FirstFrame + anim[ani].numFrames;
animLower :=ani;
end
end;
{---------------------------------------------------------}
{--- Loads a player model, skin and snimations ---}
{---------------------------------------------------------}
procedure Q3Player.LoadPlayer(path, skin: String);
begin
// Pre-calculate the normals
if aNorms[0,0,2] <> 1 then
InitNormals;
Lower.LoadModel(path + 'lower.md3');
Upper.LoadModel(path + 'upper.md3');
Head.LoadModel(path + 'head.md3');
Lower.LoadSkin(path, 'lower_' + skin + '.skin');
Upper.LoadSkin(path, 'upper_' + skin + '.skin');
Head.LoadSkin(path, 'head_' + skin + '.skin');
LoadAnim(path + 'animation.cfg');
Lower.startframe :=0; Lower.EndFrame :=0;
Upper.startframe :=0; Upper.EndFrame :=0;
Head.startframe :=0; Head.EndFrame :=0;
SetAnim(TORSO_STAND);
SetAnim(LEGS_WALK);
Lower.LinkModel('tag_torso', Upper);
Upper.LinkModel('tag_head', Head);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -