Archived

This topic is now archived and is closed to further replies.

Fuzztrek

Loading an MD2 without DrawPrimitiveUP

Recommended Posts

Hello All, I''ve been following the tutorial on gamedev for loading a MD2 file, but it is very slow, and I think this may be attributed to the fact that it uses DrawPrimitiveUP (I know for sure that I shouldn''t be using drawPrimitiveUP). Is there another tutorial or way of render MD2 files that is better? I am too clueless to figure out how to get the data into a vertex buffer :''( Thanks in advance! ¬_¬

Share this post


Link to post
Share on other sites
actually you could use an vertex-buffer like an real vertex-array. You could also check out the DX SDK, I''m sure you will also find something interesting there.

I currently have no code about this topic, but the link to the tutorial above should explain all you need

Share this post


Link to post
Share on other sites
You can look at this tutorial of mine ... I think it''s a pretty decent explanation of the most basic functionality of vertex buffers, maybe it will help? (Excuse the website that accompanies it ... I''m just using the site as filespace, that content was all done when I was in 7th grade)
Anyway, here''s the link:

http://www.geocities.com/jimzaphos/Vertexbuf.htm

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I think you guys are missing the point...correct me if I''m wrong, but he knows how to use a vertex buffer, he just has some structures filled with vertices (the md2''s), and he doesn''t know exactly what FVF to use, etc for them?

p.s. Fuzztrek i sent you an email at hotmail asking if you need anyone to help w/ your engine...

Share this post


Link to post
Share on other sites
Hey,

Yeah the AP is pretty much right. I know how to use VertexBuffers (to some extent.. I dont'' know everything about them but I know how to do the basics. As always, i could learn more) and I do know what FVF to use. Maybe it would help if I posted some code:

These are all of the structures.

  
//These are some restriction for MD2

//You can alter the values if you like to...

const int MAX_TRIANGLES = 4096;
const int MAX_VERTS = 2048;
const int MAX_FRAMES = 512;
const int MAX_MD2SKINS = 32;
const int MAX_SKINNAME = 64;

// The 13 structs

struct make_index_list
{
int a, b, c;
float a_s, a_t, b_s, b_t, c_s, c_t;
};

struct make_vertex_list
{
float x, y, z;
};

struct make_frame_list
{
make_vertex_list *vertex;
};

struct vec3_t
{
float v[3];
};

struct dstvert_t
{
short s, t;
};

struct dtriangle_t
{
short index_xyz[3];
short index_st[3];
};

struct dtrivertx_t
{
BYTE v[3];
BYTE lightnormalindex;
};

//We use that to identify one animation

//The only variably which is important for us is "name", it is filled with the names

//of the animation frames, p.ex. "run1", or "attack2". More below


struct daliasframe_t
{
float scale[3];
float translate[3];
char name[16];
dtrivertx_t verts[1];
};

//Here all information for the model is saved. Most is unimportant, the important

//stuff is commented..

//This struct is read first from file...


struct SMD2Header
{
int ident;
int version;
int skinwidth;
int skinheight;
int framesize;
int num_skins;
int num_xyz; //Vertex count

int num_st;
int num_tris; //Triangle count

int num_glcmds;
int num_frames; //Numer of frames/animations within the file

int ofs_skins;
int ofs_st;
int ofs_tris;
int ofs_frames;
int ofs_glcmds;
int ofs_end;
};

struct trivert_t
{
vec3_t v;
int lightnormalindex;
};

struct frame_t
{
vec3_t mins, maxs;
char name[16];
trivert_t v[MAX_VERTS];
};

// The vertex we use for D3D

struct MODELVERTEX
{
D3DXVECTOR3 m_vecPos; //Position

D3DCOLOR m_dwDiffuse; //Color

D3DXVECTOR2 m_vecTex; //texturecoordinates

};

//This is the definition for the vertex declared above (FVF=flexible vertex format)

#define D3DFVF_MODELVERTEX ( D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0) )

struct SMesh
{
//std::vector is declared in "vector" and it is a comfortable wrapper for dynamic arrays

std::vector<MODELVERTEX> vertex;
};


And here is the loading function:

  
// Load the mesh

HRESULT D3D_mesh::Load(char * Filename){

FILE * model = NULL;
char g_skins[MAX_MD2SKINS][64];
dstvert_t base_st[MAX_VERTS];
BYTE buffer[MAX_VERTS * 4 + 128];
SMD2Header modelHeader;
dtriangle_t tri;
daliasframe_t * out;
int i = 0;

// Load mesh in binary mode

if((model = fopen(Filename, "rb")) == NULL){

LogError("<li>Mesh failed opening mesh");
return E_FAIL;
}

// Read header

fread(&modelHeader, 1, sizeof(SMD2Header), model);
modelHeader.framesize = (int)&((daliasframe_t *)0)->verts[modelHeader.num_xyz];

// Create some variables according to the header

pro_Frames = modelHeader.num_frames;
pro_Vertices = modelHeader.num_xyz;
pro_Triangles = modelHeader.num_tris;
pro_index_list = new make_index_list[modelHeader.num_tris];
pro_frame_list = new make_frame_list[modelHeader.num_frames];

for(i = 0; i < modelHeader.num_frames; i++)
pro_frame_list[i].vertex = new make_vertex_list[modelHeader.num_xyz];

// Read skin (texture) info

fread(g_skins, 1, modelHeader.num_skins * MAX_SKINNAME, model);

// Read index for model

fread(base_st, 1, modelHeader.num_st * sizeof(base_st[0]), model);

int max_tex_u = 0, max_tex_v = 0;

for(i = 0; i < modelHeader.num_tris; i++){

// Read vertices

fread(&tri, 1, sizeof(dtriangle_t), model);
(pro_index_list)[i].a = tri.index_xyz[2];
(pro_index_list)[i].b = tri.index_xyz[1];
(pro_index_list)[i].c = tri.index_xyz[0];

// Read texture coordinates

(pro_index_list)[i].a_s = base_st[tri.index_st[2]].s;
(pro_index_list)[i].a_t = base_st[tri.index_st[2]].t;
(pro_index_list)[i].b_s = base_st[tri.index_st[1]].s;

(pro_index_list)[i].b_t = base_st[tri.index_st[1]].t;
(pro_index_list)[i].c_s = base_st[tri.index_st[0]].s;
(pro_index_list)[i].c_t = base_st[tri.index_st[0]].t;

max_tex_u = max(max_tex_u, base_st[tri.index_st[0]].s);
max_tex_u = max(max_tex_u, base_st[tri.index_st[1]].s);
max_tex_u = max(max_tex_u, base_st[tri.index_st[2]].s);

max_tex_v = max(max_tex_v, base_st[tri.index_st[0]].t);
max_tex_v = max(max_tex_v, base_st[tri.index_st[1]].t);
max_tex_v = max(max_tex_v, base_st[tri.index_st[2]].t);

}

// Recalculate texture coords

for(i = 0; i < modelHeader.num_tris; i++){

pro_index_list[i].a_s /= max_tex_u;
pro_index_list[i].b_s /= max_tex_u;
pro_index_list[i].c_s /= max_tex_u;

pro_index_list[i].a_t /= max_tex_v;
pro_index_list[i].b_t /= max_tex_v;
pro_index_list[i].c_t /= max_tex_v;
}

int j;

// Read vertex data of all animation frames

for(i = 0; i < modelHeader.num_frames; i++){

out = (daliasframe_t *)buffer;
fread(out, 1, modelHeader.framesize, model);

for(j = 0; j < modelHeader.num_xyz; j++){

(pro_frame_list)[i].vertex[j].x = out->verts[j].v[0] * out->scale[0] + out->translate[0];
(pro_frame_list)[i].vertex[j].y = out->verts[j].v[1] * out->scale[1] + out->translate[1];
(pro_frame_list)[i].vertex[j].z = out->verts[j].v[2] * out->scale[2] + out->translate[2];
}
}

fclose(model);
Init();

LogInfo("<li>Mesh %s created", Filename);
return S_OK;
}

// Init

HRESULT D3D_mesh::Init(){

int i, j = 0;

// For each animation we use a SMesh

for(i = 0; i < GetNumFrames(); i++){

MODELVERTEX pVertex;
D3DXCOLOR LightColor(1.0f, 1.0f, 1.0f, 1.0f);

// Now we copy the vertex data to pro_data

for(j = 0; j < GetNumTriangles(); j++){

pVertex.m_vecPos.x = pro_frame_list[i].vertex[pro_index_list[j].a].x;
pVertex.m_vecPos.y = pro_frame_list[i].vertex[pro_index_list[j].a].z;
pVertex.m_vecPos.z = pro_frame_list[i].vertex[pro_index_list[j].a].y;
pVertex.m_vecTex.x = pro_index_list[j].a_s;
pVertex.m_vecTex.y = pro_index_list[j].a_t;
pVertex.m_dwDiffuse = LightColor;
pro_data[i].vertex.push_back(pVertex);

pVertex.m_vecPos.x = pro_frame_list[i].vertex[pro_index_list[j].b].x;
pVertex.m_vecPos.y = pro_frame_list[i].vertex[pro_index_list[j].b].z;
pVertex.m_vecPos.z = pro_frame_list[i].vertex[pro_index_list[j].b].y;
pVertex.m_vecTex.x = pro_index_list[j].b_s;
pVertex.m_vecTex.y = pro_index_list[j].b_t;
pVertex.m_dwDiffuse = LightColor;
pro_data[i].vertex.push_back(pVertex);

pVertex.m_vecPos.x = pro_frame_list[i].vertex[pro_index_list[j].c].x;
pVertex.m_vecPos.y = pro_frame_list[i].vertex[pro_index_list[j].c].z;
pVertex.m_vecPos.z = pro_frame_list[i].vertex[pro_index_list[j].c].y;
pVertex.m_vecTex.x = pro_index_list[j].c_s;
pVertex.m_vecTex.y = pro_index_list[j].c_t;
pVertex.m_dwDiffuse = LightColor;
pro_data[i].vertex.push_back(pVertex);
}
}

pro_lpGMain->GetDevice()->CreateVertexBuffer(sizeof(SMesh), D3DUSAGE_WRITEONLY, D3DFVF_MODELVERTEX, D3DPOOL_MANAGED, &pro_VB);

unsigned char *vb_verts;
pro_VB->Lock(0, 0, &vb_verts, 0);

memcpy(vb_verts, pro_data, sizeof(pro_data));
pro_VB->Unlock();

return S_OK;
}


And here is the render function:

  
// Render :D

HRESULT D3D_mesh::Render(int frame){

// Check for invalid frame number

if(frame >= GetNumFrames()-1)
return E_FAIL;

// Set vertex shader

pro_lpGMain->GetDevice()->SetVertexShader(D3DFVF_MODELVERTEX);
pro_lpGMain->GetDevice()->SetStreamSource(0, pro_VB, sizeof(SMesh));

pro_lpGMain->GetDevice()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, GetNumTriangles());

return S_OK;
}


Note that I''ve edited the code so that it uses a vertex buffer. This does not work at all.. I''m probably loading it with the wrong thing or something. It was just an attempt and I''ve probably fried some memory in my graphics card, but oh well

Anyway.. Thanks for replying, and no I do not need any help AP, though thanks for asking. I didn''t recieve an e-mail in my hotmail account.. very odd eh?

Thanks again!

fuzztrek

¬_¬

Share this post


Link to post
Share on other sites
Alright! I found some delphi code that I *think* loads the mesh into a vertex buffer. Unfortunatly I do not know exactly what''s going on, but I''m going to post the code and see if its what I think it is.

Render code:

  
procedure TForm1.RenderFrame;

var
_nxt : cardinal;

begin
// Clear the back buffer to a black color.

D3DDEV8.Clear(0, NIL, D3DCLEAR_ZBUFFER or D3DCLEAR_TARGET,
$FF000080, 1.0, 0);

// Begin the scene.

D3DDEV8.BeginScene;

// Lighting ?

D3DDEV8.SetRenderState(D3DRS_LIGHTING, Ord(CheckBox1.Checked));

// Set texture (skin)

D3DDEV8.SetTexture(0, G_Text0);

// Render MD2

if G_Mesh0.ok then
begin
// animation

inc(G_Anim, G_FPS_FRAMETIME);
while (G_Anim > (G_TIM_FREQ div G_Speed)) do
begin
inc(G_Frame);
if G_Frame > G_LastFrame then G_Frame := G_FirstFrame;
dec(G_Anim, (G_TIM_FREQ div G_Speed));
end;

_nxt := G_Frame + 1;
if _nxt > G_LastFrame then _nxt := G_FirstFrame;

// Fill VertexBuffer with current frame data

MD2_SetFrameInt(G_Mesh0, G_Mesh0VB, G_Frame, _nxt,
G_Anim / (G_TIM_FREQ div G_Speed));

// Render current frame

MD2_RenderCurrentFrame(G_Mesh0, G_Mesh0VB);
end;

// End the scene.

D3DDEV8.EndScene;

// Display scene.

D3DDEV8.Present(NIL, NIL, 0, NIL);
end;


"Change mesh" code:


  
procedure TForm1.ChangeMesh(_fn: string);

// Load MD2


var
_i : longint;

begin
// free previous mesh

MD2_Free(G_Mesh0);
MD2_FreeVB(G_Mesh0VB);

// Load new one

G_Mesh0 := MD2_Load(_fn);
if not G_Mesh0.ok then hHalt(Format(ERR01, [_fn]));
G_Mesh0VB := MD2_CreateVB(G_Mesh0);
if not G_Mesh0VB.ok then hHalt(ERR02);

// Retrieve animation data

G_Anims := MD2_GetAnimData(G_Mesh0);
ComboBox1.Clear;
for _i := 0 to G_Anims.count -1 do ComboBox1.Items.Add(g_Anims.anim[_i].name);
ComboBox1.ItemIndex := 0;
G_FirstFrame := 0;
G_LastFrame := G_Mesh0.header.numFrames - 1;
G_Frame := G_FirstFrame;

// Reset camera

G_CDistance := C_DEFAULT_CAM_DISTANCE;
G_CHeight := C_DEFAULT_CAM_HEIGHT;
end;


Hmm... unfortunatly this doesn''t actually have any loading code in it. It seems that you must update the vertex buffer every time you render, which means i''ll need a dynamic one right?

I can''t believe how many MD2 loaders there are for openGL, and hardly any for directX (ones that includes source). I mean, there are hardly any (skinned) x-file tutorials out there.

Sigh. Anyway.. maybe it will give people some ideas? I find it very interesting, but I might have to start learning about the MD2 file format more so I can figure out what to load into the vertex buffer and what not to.

Fuzztrek

¬_¬

Share this post


Link to post
Share on other sites
-
  pro_lpGMain->GetDevice()->CreateVertexBuffer(sizeof(SMesh), D3DUSAGE_WRITEONLY, D3DFVF_MODELVERTEX, D3DPOOL_MANAGED, &pro_VB);  

The 1st parameter should be the size of the WHOLE buffer in bytes. When you use sizeof( SMesh ), it'll typically return 16 bytes, which is the size of the vector object.

You should use : sizeof( MODELVERTEX ) * pro_date.vertex.size()

-

  memcpy(vb_verts, pro_data, sizeof(pro_data));  


pro_data - as far as I see - is an array ( dynamic? ) that contains vertex data for ALL frames. The data for each frame is stored in another vector, so this memcpy definitely won't work.
Additionally, the sizeof( pro_data ) will not get you the total size, it'll get you the size of an empty pro_data struct/class.

-
  pro_lpGMain->GetDevice()->SetStreamSource(0, pro_VB, sizeof(SMesh));  


sizeof( SMesh ) returns the size of std::vector ( 16 bytes ), not your vertex type.
The 3rd parameter here is called the stride, which is the size of each vertex in bytes.
You should use sizeof( MODELVERTEX ) instead.

- When you're loading the vertices, you didn't take into account that the quake2's coordinate system is very different.
Its y axis increases to the right ( == D3D's x axis )
Its x axis increases out of the screen ( == -ve D3D's z axis )
Its z axis increases upwards ( == D3D's y axis )


-
  pro_lpGMain->GetDevice()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, GetNumTriangles())  


If we assumed the memcpy above worked, your buffer would contain all the animation frames of the md2, and then this call should've rendered them ( all the frames at once, which is wrong. You should render one frame at once ).

Additionally, the vertices are NOT stored as triangle strips, they're plain triangle lists.
In fact, the md2 format stores vertices in 2 ways : unoptimized and optimized.
The unoptimized vertex storage is the one you typically loaded. The optimized way of storing vertices is done through the usage of the glCommands, but that's a bit advanced.
By the way, By optmized I mean it's optimized for GL not D3D.


It seems you need to study the md2 format a little more, search for some reference ( I can find you one or two, only if you fail to find one yourself )

I have some source code that USED TO load md2 files, I have no idea if it's currently operational; I attempted to update it sometime ago and then I just abandoned it ( before finishing the update ).
If you fail to find any decent source, tell me and I'll post it here or mail it to you ( mail would be better )

[edited by - Coder on November 2, 2002 2:36:55 PM]

Share this post


Link to post
Share on other sites
Hi there,

Thanks for replying coder, but I already know it doesn''t work I don''t really know what else to say, some of the info you gave me was helpful, and I''ll look into MD2 a little more.

thanks again!

fuzztrek

¬_¬

Share this post


Link to post
Share on other sites
I have not followed the discussion, but you couldn''t use the indicies given by the MD2 model for vertex-buffering <- just an note

I was trying this because I thought I could use multiple streams for my texture-coordinates, texture-indicies, vertex-coordinates and the vertex-indicies...

Share this post


Link to post
Share on other sites