#include "std.h" #include "md2model.h" #include "md2norms.h" static Vector *normals; static float white[]={1,1,1}; extern gxRuntime *gx_runtime; extern gxGraphics *gx_graphics; struct MD2Model::Rep{ struct md2_header{ int magic; int version; int skinWidth; int skinHeight; int frameSize; int numSkins; int numVertices; int numTexCoords; int numTriangles; int numGlCommands; int numFrames; int offsetSkins; int offsetTexCoords; int offsetTriangles; int offsetFrames; int offsetGlCommands; int offsetEnd; }; struct md2_vertex{ unsigned char x,y,z,n; }; struct md2_texcoord{ unsigned short s,t; }; struct md2_triangle{ unsigned short verts[3],tex_coords[3]; }; struct Frame{ Vector scale,trans; vector verts; }; struct TexCoords{ float u,v; }; int ref_cnt; int num_verts,num_frames; vector frames; vector tex_coords; gxMesh *mesh; Box box; ModelModel::Rep( const string &file ): ref_cnt(1),mesh(0){ filebuf in; Header header; if( !in.open( file.c_str(),ios_base::in|ios_base::binary ) ) return; if( in.sgetn( (char*)&header,sizeof(header) )!=sizeof(header) ) return; if( header.magic!='2PDI' || header.version!=8 ) return; //read tex coords in.pubseekpos( header.offsetTexCoords ); TexCoord *coords=d_new TexCoord[header.numTexCoords]; in.sgetn( (char*)coords,header.numTexCoords*sizeof(TexCoord) ); vector verts; map info_map; //build triangles vector triangles; in.pubseekpos( header.offsetTriangles ); triangles.resize( header.numTriangles ); for( k=0;k::iterator it=info_map.find( i ); if( it==info_map.end() ){ info_map[i]=triangles[k].v[j]=verts.size(); verts.push_back( i ); }else{ triangles[k].v[j]=it->second; } } } delete coords; //load frames string tt="MD2 Frames:"+itoa( header.numFrames ); gx_runtime->debugLog( tt.c_str() ); in.pubseekpos( header.offsetFrames ); frames.resize( header.numFrames ); MD2Vertex *md2_verts=d_new MD2Vertex[header.numVertices]; for( k=0;kcreateMesh( verts.size(),triangles.size(),0 ); mesh->lock(); for( k=0;ksetTriangle( k,t.v[0],t.v[2],t.v[1] ); } mesh->unlock(); //calculate bounding box. for( k=0;k vertices; }; struct TexCoord{ short s,t; }; struct VertInfo{ unsigned short index; unsigned char u,v; VertInfo( unsigned short i,char u,char v ):index(i),u(u),v(v){ } bool operator<( const VertInfo &t )const{ if( index frames; gxMesh *mesh; Box box; Rep( const string &file ); ~Rep(); void render( MD2Model *model,float render_t,int render_a,int render_b ); }; MD2Model::Rep::Rep( const string &file ): ref_cnt(1),mesh(0){ filebuf in; if( !in.open( file.c_str(),ios_base::in|ios_base::binary ) ){ return; } if( in.sgetn( (char*)&header,sizeof(header) )!=sizeof(header) ){ return; } if( header.magic!='2PDI' || header.version!=8 ){ return; } int k; //read tex coords in.pubseekpos( header.offsetTexCoords ); TexCoord *coords=d_new TexCoord[header.numTexCoords]; in.sgetn( (char*)coords,header.numTexCoords*sizeof(TexCoord) ); vector verts; map info_map; //build triangles vector triangles; in.pubseekpos( header.offsetTriangles ); triangles.resize( header.numTriangles ); for( k=0;k::iterator it=info_map.find( i ); if( it==info_map.end() ){ info_map[i]=triangles[k].v[j]=verts.size(); verts.push_back( i ); }else{ triangles[k].v[j]=it->second; } } } delete coords; //load frames string tt="MD2 Frames:"+itoa( header.numFrames ); gx_runtime->debugLog( tt.c_str() ); in.pubseekpos( header.offsetFrames ); frames.resize( header.numFrames ); MD2Vertex *md2_verts=d_new MD2Vertex[header.numVertices]; for( k=0;kcreateMesh( verts.size(),triangles.size(),0 ); mesh->lock(); for( k=0;ksetTriangle( k,t.v[0],t.v[2],t.v[1] ); } mesh->unlock(); //calculate bounding box. for( k=0;kfreeMesh( mesh ); } void MD2Model::Rep::render( MD2Model *model,float render_t,int render_a,int render_b ){ const Frame &frame_a=frames[render_a]; const Vector &scale_a=frame_a.scale; const Vector &trans_a=frame_a.trans; const Frame &frame_b=frames[render_b]; const Vector &scale_b=frame_b.scale; const Vector &trans_b=frame_b.trans; mesh->lock(); int k; for( k=0;ksetVertex( k,&t.x,&n.x,white,tex_coords ); } mesh->unlock(); model->enqueue( mesh,0,frame_a.vertices.size(),0,header.numTriangles ); } MD2Model::MD2Model( const string &f ): rep( d_new Rep( f ) ), anim_mode(0),anim_time(0), render_a(0),render_b(0),render_t(0){ } MD2Model::MD2Model( const MD2Model &t ): Model(t),rep( t.rep ), anim_mode(0),anim_time(0), render_a(0),render_b(0),render_t(0){ ++rep->ref_cnt; } MD2Model::~MD2Model(){ if( !--rep->ref_cnt ) delete rep; } void MD2Model::startMD2Anim( int first,int last,int mode,float speed ){ if( !speed && !mode ){ anim_mode=0;return; } if( first<0 ) first=0; else if( first>=rep->header.numFrames ) first=rep->header.numFrames-1; if( last<0 ) last=0; else if( last>=rep->header.numFrames ) last=rep->header.numFrames-1; if( first==last ){ anim_mode=0;render_a=render_b=first;render_t=0;return; } if( last0 ? first : last; anim_mode=mode; } void MD2Model::animate( float e ){ Model::animate( e ); if( !anim_mode ) return; anim_time=anim_time+anim_speed * e; if( anim_time=anim_last ){ switch( anim_mode ){ case ANIM_MODE_LOOP: anim_time-=anim_len; break; case ANIM_MODE_PINGPONG: anim_time=anim_last-(anim_time-anim_last); anim_speed=-anim_speed; break; default: anim_time=anim_last; anim_mode=0; break; } } render_a=floor(anim_time);render_b=render_a+1; if( anim_mode==ANIM_MODE_LOOP && render_b==anim_last ) render_b=anim_first; render_t=anim_time-render_a; } void MD2Model::render( const RenderContext &rc ){ static Frustum f; new( &f ) Frustum( rc.getWorldFrustum(),-getRenderTform() ); if( !f.cull( rep->box ) ) return; rep->render( this,render_t,render_a,render_b ); } int MD2Model::getMD2AnimLength()const{ return rep->frames.size(); } bool MD2Model::getValid()const{ return rep->mesh!=0; }