Zaslal: nou
Popis: Trieda na načítanie a vykreslenie 3D modelu vo formáte MS3D
Jazyk: C++
Vloženo: 12.9.2007, 14:54
Stáhnout jako soubor
/////////////////////////////////// //MS3D.h #ifndef _MS3D_H_NOU_ #define _MS3D_H_NOU_ #ifndef byte typedef unsigned char byte; #endif // byte #ifndef word typedef unsigned short word; #endif // word #include "Matrix.h" // force one byte alignment #include <pshpack1.h> typedef struct { Bod position; char boneId; } ms3d_vertex; typedef struct { word vertexIndices[3]; Vector normal[3]; float s[3]; float t[3]; } ms3d_triangle; typedef struct { word numtriangles; word *triangleIndices; char materialIndex; } ms3d_group; typedef struct { float ambient[4]; float diffuse[4]; float specular[4]; float emissive[4]; float shininess; float transparency; char texture[128]; char alphamap[128]; unsigned int textura; } ms3d_material; typedef struct { float time; float rotation[3]; } ms3d_keyframe_rot; typedef struct { float time; float position[3]; } ms3d_keyframe_pos; typedef struct { char name[32]; char parentName[32]; float rotation[3]; float position[3]; word numKeyFramesRot; word numKeyFramesTrans; ms3d_keyframe_rot *keyFramesRot; ms3d_keyframe_pos *keyFramesTrans; int parent; Matrix relative; Matrix absolute; Matrix final; } ms3d_joint; #include <poppack.h> class MS3D { private: word poc_vertex; ms3d_vertex *vertex; word poc_triangle; ms3d_triangle *triangle; word poc_group; ms3d_group *group; word poc_material; ms3d_material *material; word poc_joint; ms3d_joint *joint; float cas; public: MS3D() {//konstruktor nastavi vsetko na nulu poc_vertex=0; vertex=NULL; poc_triangle=0; triangle=NULL; poc_group=0; group=NULL; poc_material=0; material=NULL; poc_joint=0; joint=NULL; cas=0; } ~MS3D() { delete vertex; delete triangle; delete group; delete material; delete joint; } int LoadData(char *path);//nacitavanie dat modelu int LoadTexture();//nacita textury vhodne pri strate kontextu okna void Setup();//nastavime zakladnu kotru void Animate(float time);//animujeme kosti void Draw(float time);//vykreslime }; #endif /////////////////////////////////// //MS3D.cpp #include "MS3D.h" #include <stdio.h> #include <string.h> #include "resource.h" int MS3D::LoadData(char *path) { FILE *fr; fr = fopen(path,"rb");//otvorime subor if(fr==NULL) return 0;//ak neotvorilo vratime 0 char hlavicka[11]; int verzia; fscanf(fr,"%10s",hlavicka);//nacitame hlavicku fread(&verzia,sizeof(int),1,fr);//aj verziu if(0!=strcmp(hlavicka,"MS3D000000") || verzia!=4)//ak sa nezhoduju vratime chybu return 0; int i,o; fread(&poc_vertex,sizeof(word),1,fr);//nacitame pocet vertexov modelu vertex = new ms3d_vertex[poc_vertex]; if(vertex==NULL)//testujeme na chybu pridelovania pamete { fprintf(stderr,"Nedostatok pamete na vertexy! %d\n",poc_vertex); return 0; } float poloha[3];//premenna na nacitavanie bodov for(i=0;i<poc_vertex;i++)//nacitavame vertexy { fseek(fr,sizeof(byte),SEEK_CUR);//preskocime pre nas nepotrebny udaj fread(poloha,sizeof(float),3,fr);//nacitame polohu vertexu fread(&(vertex+i)->boneId,sizeof(byte),1,fr); fseek(fr,sizeof(byte),SEEK_CUR);//zase preskok (vertex+i)->position(poloha);//nastavime polohu vertexu } fread(&poc_triangle,sizeof(word),1,fr);//nacitame pocet trojuholnikov triangle = new ms3d_triangle[poc_triangle]; if(triangle==NULL) { fprintf(stderr,"Nedostatok pamete na trojuholniky!"); return 0; } float normaly[3][3]; for(i=0;i<poc_triangle;i++) { fseek(fr,sizeof(word),SEEK_CUR);//preskocime pre nas nepotrebny udaj fread((triangle+i)->vertexIndices,sizeof(word),3,fr);//nacitame index vertexov fread(normaly,sizeof(float),3*3,fr);//nacitame normaly ((triangle+i)->normal+0)->Set(normaly[0]); ((triangle+i)->normal+1)->Set(normaly[1]); ((triangle+i)->normal+2)->Set(normaly[2]); fread((triangle+i)->s,sizeof(float),3,fr);//nacitame texturove koordinaty fread((triangle+i)->t,sizeof(float),3,fr);//nacitame texturove koordinaty fseek(fr,sizeof(byte)*2,SEEK_CUR);//preskocime pre nas nepotrebny udaj } fread(&poc_group,sizeof(word),1,fr);//nacitame pocet skupin group = new ms3d_group[poc_group]; if(group==NULL) { fprintf(stderr,"Nedostatok pamete na skupiny!"); return 0; } //nacitavanie hodnot skupin for(i=0;i<poc_group;i++) { fseek(fr,sizeof(byte)+sizeof(char)*32,SEEK_CUR);//preskocime flags a meno skupiny fread(&(group+i)->numtriangles,sizeof(word),1,fr);//nacitame pocet trojuholnikov v skupine (group+i)->triangleIndices = new word[(group+i)->numtriangles]; if((group+i)->triangleIndices==NULL) return 0; fread((group+i)->triangleIndices,sizeof(word),(group+i)->numtriangles,fr);//nacitame indexy fread(&(group+i)->materialIndex,sizeof(char),1,fr);//nacitanie indexu materialu } fread(&poc_material,sizeof(word),1,fr); material = new ms3d_material[poc_material]; if(material==NULL)return 0; //nacitame materialy for(i=0;i<poc_material;i++) { fseek(fr,sizeof(char)*32,SEEK_CUR);//preskocenie mena materialu fread((material+i)->ambient,sizeof(float),4,fr);//nacitanie ambient zlozky fread((material+i)->diffuse,sizeof(float),4,fr);//nacitanie difuse fread((material+i)->specular,sizeof(float),4,fr);//nacitame specular fread((material+i)->emissive,sizeof(float),4,fr);//nacitame emisive fread(&(material+i)->shininess,sizeof(float),1,fr);//nacitame shiness fread(&(material+i)->transparency,sizeof(float),1,fr);//nacitame priehladnost fseek(fr,sizeof(char),SEEK_CUR);//preskakujem mode fread((material+i)->texture,sizeof(char),128,fr);//nacitame texture name (material+i)->textura=1; fseek(fr,sizeof(char)*128,SEEK_CUR);//preskocime alpha mapu pretoze ju budem mat v jednej a zakomettujte tento ak odkomentujete dalsi //fread((materiali+i)->alphamap,sizeof(char),128,fr); //odkomentujte tento riadok ak chcete nacitavat alphamapu //fprintf(stderr,"%s\n",materiali->texture); } //nacitame kosti float animFPS; int poc_framov; fread(&animFPS,sizeof(float),1,fr);//nacitame pocet snimkov za sekundu fseek(fr,sizeof(float),SEEK_CUR); fread(&poc_framov,sizeof(int),1,fr);//a celkovy pocet snimkov cas=poc_framov/animFPS;//celkovy cas animacie fread(&poc_joint,sizeof(word),1,fr); joint = new ms3d_joint[poc_joint]; if(joint==NULL)return 0; //nacitame hodnoty kosti a animacie for(i=0;i<poc_joint;i++) { fseek(fr,sizeof(byte),SEEK_CUR); fread((joint+i)->name,sizeof(char),32,fr);//nacitame meno klbu fread((joint+i)->parentName,sizeof(char),32,fr);//nacitame meno rodicovskeho klbu fread((joint+i)->rotation,sizeof(float),3,fr);//nacitame zakladnu rotaciu fread((joint+i)->position,sizeof(float),3,fr);//nacitame zakladne posunutie fread(&(joint+i)->numKeyFramesRot,sizeof(unsigned short),1,fr);//nacitame pocet snimkov rotacie fread(&(joint+i)->numKeyFramesTrans,sizeof(unsigned short),1,fr);//nacitame pocet snimkov posunutia (joint+i)->keyFramesRot = new ms3d_keyframe_rot[(joint+i)->numKeyFramesTrans];//alokujeme pamet pre snimky (joint+i)->keyFramesTrans = new ms3d_keyframe_pos[(joint+i)->numKeyFramesTrans]; fread((joint+i)->keyFramesRot,sizeof(ms3d_keyframe_rot),(joint+i)->numKeyFramesRot,fr);//a nacitame ich fread((joint+i)->keyFramesTrans,sizeof(ms3d_keyframe_pos),(joint+i)->numKeyFramesTrans,fr); (joint+i)->parent=-1;//nastavieme rodica na -1 /*dalej otestujeme pomocou strcmp() kosti ci existuje rodic a nstavime index nanho do premenej parents*/ if((joint+i)->parentName[0]=='\0') continue;/*ak je meno rodica przdne tak preskocime porovnanavanie*/ for(o=i-1;o>=0;o--)//ideme odzadu pretoze redicovsky klb moze byt hned predosly { if(!strcmp((joint+o)->name,(joint+i)->parentName))//porovnavame meno rodica s menami klbov { (joint+i)->parent=o;//ak najdeme zhodu priradime cislo break;//a vyskocime z cyklu } } } fclose(fr);//zatvorime model if(!LoadTexture())return 0; Setup(); return 1; } int MS3D::LoadTexture() { TextureRes tex; for(int i=0;i<poc_material;i++) {//nahrame textury if((material+i)->texture[0]!='\0')//podmienka proti nacitavaniu nicoho (material+i)->textura=tex.LoadTex((material+i)->texture); if((material+i)->textura==NULL)return 0; } return 1; } void MS3D::Setup() { int i,o; Matrix mat; for(i=0;i<poc_joint;i++) { //vykoname tranformaciu podla zakladnych transformcii mat.Translate((joint+i)->position[0],(joint+i)->position[1],(joint+i)->position[2]); mat.Rotate((joint+i)->rotation[0],(joint+i)->rotation[1],(joint+i)->rotation[2]); (joint+i)->relative=mat;//nakopirujem si relativnu maticu if((joint+i)->parent!=-1)//ak ma kost rodica tak vynasobime tranformaciu rodica potomkovou mat=mat*(joint+((joint+i)->parent))->absolute; (joint+i)->absolute=mat;//a vysledok ulozime mat.Identity();//vyjednotkujeme maticu } for(i=0;i<poc_joint;i++) { mat=(joint+i)->absolute; mat.Inverse();//zinvertizujeme absolutnu maticku kosti for(o=0;o<poc_vertex;o++) { /*a nasledne tranformujeme vsetky body prisluchajuce danej kosti pomocou danej matice*/ if((vertex+o)->boneId==i) { (vertex+o)->position=mat*(vertex+o)->position; } } } } void MS3D::Animate(float time) { glPushMatrix(); int nasobky = time/cas; time=time-cas*nasobky; Matrix transform; float tran[3],rot[3]; for(int i=0;i<poc_joint;i++) { int prev=0,curr=0;//najdeme aktualny snimok while(((joint+i)->keyFramesTrans+curr)->time < time && curr<(joint+i)->numKeyFramesTrans)curr++; prev=curr; if(curr>0)prev--; float inter=(time-((joint+i)->keyFramesTrans+prev)->time);//zinterpolujeme medzi dvoma snimkami if(curr!=prev)inter/=((joint+i)->keyFramesTrans+curr)->time-((joint+i)->keyFramesTrans+prev)->time; tran[0]=((joint+i)->keyFramesTrans+curr)->position[0]-((joint+i)->keyFramesTrans+prev)->position[0]; tran[1]=((joint+i)->keyFramesTrans+curr)->position[1]-((joint+i)->keyFramesTrans+prev)->position[1]; tran[2]=((joint+i)->keyFramesTrans+curr)->position[2]-((joint+i)->keyFramesTrans+prev)->position[2]; if(curr==(joint+i)->numKeyFramesTrans)inter=0;//ak sem za poslednou snimkou tran[0]*=inter; tran[1]*=inter; tran[2]*=inter;//tak nulou vynulujeme tran[0]+=((joint+i)->keyFramesTrans+prev)->position[0];//a ostane len posledna snimka tran[1]+=((joint+i)->keyFramesTrans+prev)->position[1]; tran[2]+=((joint+i)->keyFramesTrans+prev)->position[2]; transform.Translate(tran[0],tran[1],tran[2]);//spravime translaciu podla aktualneho snimka prev=curr=0;//najdeme teraz rotaciu while(((joint+i)->keyFramesRot+curr)->time < time && curr<(joint+i)->numKeyFramesRot)curr++; prev=curr; if(curr>0)prev--; inter=(time-((joint+i)->keyFramesRot+prev)->time); if(curr!=prev)inter/=((joint+i)->keyFramesRot+curr)->time-((joint+i)->keyFramesRot+prev)->time; rot[0]=((joint+i)->keyFramesRot+curr)->rotation[0]-((joint+i)->keyFramesRot+prev)->rotation[0]; rot[1]=((joint+i)->keyFramesRot+curr)->rotation[1]-((joint+i)->keyFramesRot+prev)->rotation[1]; rot[2]=((joint+i)->keyFramesRot+curr)->rotation[2]-((joint+i)->keyFramesRot+prev)->rotation[2]; if(curr==(joint+i)->numKeyFramesRot)inter=0;//ak sem za poslednou snimkou rot[0]*=inter; rot[1]*=inter; rot[2]*=inter;//tak nulou vynulujeme rot[0]+=((joint+i)->keyFramesRot+prev)->rotation[0];//a ostane len posledna snimka rot[1]+=((joint+i)->keyFramesRot+prev)->rotation[1]; rot[2]+=((joint+i)->keyFramesRot+prev)->rotation[2]; transform.Rotate(rot[0],rot[1],rot[2]);//orotujeme (joint+i)->absolute=transform;//ulozime si posunutie oproti zakladu kvoli normalam transform=transform*(joint+i)->relative;//posuniem relativnu maticu o animaciu if((joint+i)->parent!=-1)//ak ma rodica tak nasobime finalnou maticou rodica transform=transform*(joint+((joint+i)->parent))->final; (joint+i)->final=transform;//ulozime si zanimovanu maticu transform.Identity();//zjednickujeme si maticu pre dalsie pouzitie } } void MS3D::Draw(float time) { Animate(time); int i,o; Matrix rela; for(i=0;i<poc_group;i++)//zacneme kreslit { glEnable(GL_LIGHTING); int material_cis = (group+i)->materialIndex; if((group+i)->materialIndex!=-1)//ak je nastaveny materialovy index tak nastavime material { glMaterialfv( GL_FRONT, GL_AMBIENT, (material+material_cis)->ambient); // Nastav ambient material glMaterialfv( GL_FRONT, GL_DIFFUSE, (material+material_cis)->diffuse); // Nastav diffuse material glMaterialfv( GL_FRONT, GL_SPECULAR, (material+material_cis)->specular); // Nastav specular material glMaterialfv( GL_FRONT, GL_EMISSION, (material+material_cis)->emissive); // Nastav emission material glMaterialf( GL_FRONT, GL_SHININESS, (material+material_cis)->shininess); // Nastav shininess material } else//inak nastavim standartne farby { float a[4]={0.1f,0.1f,0.1f,1}; float d[4]={1,1,1,1}; float g[4]={0,0,0,0}; glMaterialfv( GL_FRONT, GL_AMBIENT, a); // Nastav ambient material glMaterialfv( GL_FRONT, GL_DIFFUSE, d); // Nastav diffuse material glMaterialfv( GL_FRONT, GL_SPECULAR, g); // Nastav specular material glMaterialfv( GL_FRONT, GL_EMISSION, g); // Nastav emission material glMaterialf( GL_FRONT, GL_SHININESS, 64); } if((material+material_cis)->textura!=0)//ak existuje textura zvol ju { glEnable(GL_TEXTURE_2D);//povolime texturovanie glBindTexture(GL_TEXTURE_2D,(material+material_cis)->textura);// Zvolí texturu } else glDisable(GL_TEXTURE_2D);//ak nie je textura nebude texturovanie glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); int w,p[3],bone[3]; for(o=0;o<(group+i)->numtriangles;o++) { w = (group+i)->triangleIndices[o]; //priradime index trojholnika do w a ten nasledne vykreslime p[0] = (triangle+w)->vertexIndices[0];//nastavime si indexy vrcholov p[1] = (triangle+w)->vertexIndices[1]; p[2] = (triangle+w)->vertexIndices[2]; bone[0] = (vertex+p[0])->boneId;//a indexy kosti bone[1] = (vertex+p[1])->boneId; bone[2] = (vertex+p[2])->boneId; Bod v1,v2,v3;//transformujeme body podla animacnej kosti v1=(joint+bone[0])->final*(vertex+p[0])->position; v2=(joint+bone[1])->final*(vertex+p[1])->position; v3=(joint+bone[2])->final*(vertex+p[2])->position; Vector n1,n2,n3;//pretranformujeme normaly na osvetlenie n1=(joint+bone[0])->absolute**((triangle+w)->normal+0); n2=(joint+bone[1])->absolute**((triangle+w)->normal+1); n3=(joint+bone[2])->absolute**((triangle+w)->normal+2); glBegin(GL_TRIANGLES); glNormal3f(n1[0],n1[1],n1[2]);// Normála glTexCoord2f((triangle+w)->s[0], (triangle+w)->t[0]); glVertex3f(v1[0],v1[1],v1[2]); glNormal3f(n2[0],n2[1],n2[2]);// Normála glTexCoord2f((triangle+w)->s[1], (triangle+w)->t[1]); glVertex3f(v2[0],v2[1],v2[2]); glNormal3f(n3[0],n3[1],n3[2]);// Normála glTexCoord2f((triangle+w)->s[2], (triangle+w)->t[2]); glVertex3f(v3[0],v3[1],v3[2]); glEnd(); } } }
© 2006 Michal Tuláček, Syntax Highlight - GeSHi (thx bref)