/** ******************************************************************************* @file /gui/model/ModelRep.cpp @brief Datove struktury pro reprezenaci modelovych dat @author Vajicek @version 0.1 ******************************************************************************/ #include "gui/model/ModelRep.h" // #include "common/Log.h" #include "gui/common/mymath.h" #include "gui/model/reader_ase.h" #include "gui/engine/TextureManager.h" #include "gui/engine/Animation.h" using namespace std; namespace gui{ /////////////////////////////////////////////////////////////////////////////// TModel::TModel(){ initModel(false, true); } TModel::TModel(int lod, int hierarchy){ initModel(lod, hierarchy); } TModel::~TModel(){ freeModel(); } void TModel::initModel(int lod, int hierarchy){ this->lod_count = -1; this->hierarchy = NULL; this->hierarchy_c=0; this->lod_level = NULL; this->hard_parent = NULL; //lod if(lod){ this->lod_count = 0; } } void TModel::freeModel(){ std::vector::iterator obj_it; std::vector::iterator matr_it; std::vector::iterator kf_it; void* st[40]; int sst; //pokud neni softkopii, smaz data if(!this->hard_parent) { //uvolni geometrii for( obj_it = this->data.begin(); obj_it != this->data.end(); obj_it++){ Destroy3DObject(*obj_it); } sst = 0; for( matr_it = this->matr.begin(); matr_it != this->matr.end(); matr_it++){ st[sst] = (void*)*matr_it; sst ++; } //uvolni materialy PMaterial mat; while(sst){ mat = (PMaterial)st[sst-1]; sst--; for(int i = 0; i < mat->submat_c; i++){ assert(sst<40); st[sst] = (void*)&(mat->submat[i]); sst++; } if(mat->mmap_c){ for(int j = 0; j < mat->mmap_c; j++){ KReleaseString(mat->mmap[j].bitmap_file); } KMemFree(mat->mmap); } KMemFree(mat); } //uvolni keyframery PKeyframer kf; for( kf_it = this->keyframers.begin(); kf_it != this->keyframers.end(); kf_it++){ kf = *kf_it; for(int l = 0; l < kf->anim_object_nodes_c; l++){ if( kf->anim_object_nodes[l].pos_track ) KMemFree(kf->anim_object_nodes[l].pos_track ); if( kf->anim_object_nodes[l].rot_track ) KMemFree(kf->anim_object_nodes[l].rot_track ); if( kf->anim_object_nodes[l].scl_track ) KMemFree(kf->anim_object_nodes[l].scl_track ); } if(kf->anim_object_nodes) KMemFree( kf->anim_object_nodes ); if(kf) KMemFree( kf ); } } //uvolni hierarchie PMeshNode mn; for(vector::iterator mn_it = this->nodes.begin(); mn_it != this->nodes.end(); mn_it++) { mn = *mn_it; if(mn->childs) KMemFree(mn->childs); KMemFree(mn); } //uvolnit koreny hierarchyii if(this->hierarchy_c > 0) KMemFree(this->hierarchy); if(this->lod_count > 0){ for(int t = 0; t < this->lod_count; t++){ if(this->lod_level[t].hierarchy_c) KMemFree(this->lod_level[t].hierarchy); } KMemFree(this->lod_level); } //uvolni vsechny instance } void TModel::loadGeometry(void* data){ size_t geom_count = this->data.size(); //data load_ASE((char*)data, this, ASE_NEW|ASE_GEOMETRY|ASE_HIERARCHY|ASE_TEXTUREUPDOWN); if( geom_count == this->data.size() ) THROW(E_8K_GUI, "TModel::loadGeometry(): no geometry loaded!"); //nahraj textury TTextureManager::tm->prepareModel(this, 0); //aabb calculateAABB(&aabb); } void TModel::loadAnimation(void* data){ size_t anim_count = this->keyframers.size(); //nahraj animace load_ASE((char*)data, this, ASE_ANIMATION|ASE_APPEND|ASE_HIERARCHY|ASE_TEXTUREUPDOWN); if( anim_count == this->keyframers.size() ) THROW(E_8K_GUI, "TModel::loadAnimation(): no animation loaded!"); //predzpracuj animaci CreateTableForModel(this, (int)keyframers.size()-1); } TModel* TModel::softCopyModel(){ TModel* m; m = new TModel( (this->lod_count != LOD_OFF), 0); //zkopirovat odkazy na material for(vector::iterator mat_it = this->matr.begin(); mat_it != this->matr.end(); mat_it++) m->matr.push_back(*mat_it); //zkopirovat odkzay na geometrii for(vector::iterator obj_it = this->data.begin(); obj_it != this->data.end(); obj_it++) m->data.push_back(*obj_it); //zkopirovat odkzay na keyframery for(vector::iterator kf_it = this->keyframers.begin(); kf_it != this->keyframers.end(); kf_it++) m->keyframers.push_back(*kf_it); //zkopirovat lody if( this->lod_count != LOD_OFF ){ //vyrob lody m->lod_level = (TLODLevel*)KMemAlloc( this->lod_count * sizeof(TLODLevel) ); m->lod_count = this->lod_count; //natvrdo zkopiruju memcpy(m->lod_level, this->lod_level, this->lod_count * sizeof(TLODLevel)); for(int l = 0; l < m->lod_count; l++) { //vyrob pamet pro hierarchii m->lod_level[l].hierarchy = (PMeshNode*)KMemAlloc(this->lod_level[l].hierarchy_c * sizeof(PMeshNode)); //zkopiruj hierarchii for(int j = 0; j < this->lod_level[l].hierarchy_c; j++) m->lod_level[l].hierarchy[j] = copyHierarchy(this->lod_level[l].hierarchy[j], NULL, &(m->nodes)); } } //zkopirovat hierarchii if( this->hierarchy_c ){ //vyrob pamet pro hierarchii m->hierarchy = (PMeshNode*)KMemAlloc(this->hierarchy_c * sizeof(PMeshNode)); m->hierarchy_c = this->hierarchy_c; //zkopiruj hierarchii for(int j = 0; j < this->hierarchy_c; j++) m->hierarchy[j] = copyHierarchy(this->hierarchy[j], NULL, &(m->nodes)); } m->hard_parent = this; return m; } /** pomocna funkce na kopirovani hierarchie*/ PMeshNode TModel::copyHierarchy(PMeshNode from, PMeshNode parent, std::vector* vmn){ PMeshNode dest = (PMeshNode)KMemAlloc(sizeof(TMeshNode)); vmn->push_back(dest); //zkopiruj a nastav slozky memcpy(dest, from, sizeof(TMeshNode));//natvrdo zkopiruj dest->parent = parent; //zkopiruj potomky if(from->childs_c){ dest->childs = (PMeshNode*)KMemAlloc(from->childs_c * sizeof(PMeshNode)); dest->childs_c = from->childs_c; for(int i = 0; i < from->childs_c; i++){ dest->childs[i] = copyHierarchy(from->childs[i], dest, vmn); } } return dest; } TModelInstance* TModel::instantiateModel(){ std::vector inst_nodes; TModelInstance* inst = (TModelInstance*)KMemAlloc(sizeof(TModelInstance)); // inst->lod_count = LOD_OFF; inst->model_class = NULL; inst->lod_level = NULL; inst->hierarchy_c = 0; inst->hierarchy = NULL; inst->nodes_c = 0; inst->nodes = NULL; //zkopirovat lody if( this->lod_count != LOD_OFF ){ //vyrob lody inst->lod_level = (TLODLevel*)KMemAlloc( this->lod_count * sizeof(TLODLevel) ); inst->lod_count = this->lod_count; //natvrdo zkopiruju memcpy(inst->lod_level, this->lod_level, this->lod_count * sizeof(TLODLevel)); for(int l = 0; l < this->lod_count; l++) { //vyrob pamet pro hierarchii inst->lod_level[l].hierarchy = (PMeshNode*)KMemAlloc(this->lod_level[l].hierarchy_c * sizeof(PMeshNode)); //zkopiruj hierarchii for(int j = 0; j < this->lod_level[l].hierarchy_c; j++) inst->lod_level[l].hierarchy[j] = copyHierarchy(this->lod_level[l].hierarchy[j], NULL, &(inst_nodes)); } } //zkopirovat hierarchii if( this->hierarchy_c ){ //vyrob pamet pro hierarchii inst->hierarchy = (PMeshNode*)KMemAlloc(this->hierarchy_c * sizeof(PMeshNode)); inst->hierarchy_c = this->hierarchy_c; //zkopiruj hierarchii for(int j = 0; j < this->hierarchy_c; j++) inst->hierarchy[j] = copyHierarchy(this->hierarchy[j], NULL, &(inst_nodes)); } //zkopirovani nodu inst->nodes = (PMeshNode*)KMemAlloc( inst_nodes.size() * sizeof(PMeshNode)); // inst->nodes_c = 0; for(vector::iterator mn_it = inst_nodes.begin(); mn_it != inst_nodes.end(); mn_it++) inst->nodes[inst->nodes_c++] = *mn_it; // inst->model_class = this; return inst; } P3DObject TModel::addGeometry() { P3DObject o; // o = (T3DObject*)KMemAlloc(sizeof(T3DObject)); o -> mesh_c = 0; o -> mesh = NULL; o -> vert_c = 0; o -> vert = NULL; o -> poly_c = 0; o -> poly = NULL; this->data.push_back(o); // return o; } TLODLevel* TModel::addLODLevel(double dist){ this->lod_level = (TLODLevel*)KExtArrayRealloc(this->lod_level, sizeof(TLODLevel), this->lod_count + 1, this->lod_count); this->lod_count++; this->lod_level[this->lod_count - 1].dist = (float)dist; this->lod_level[this->lod_count - 1].object = NULL; this->lod_level[this->lod_count - 1].hierarchy = NULL; this->lod_level[this->lod_count - 1].hierarchy_c = 0; return &(this->lod_level[this->lod_count - 1]); } TMeshNode* TModel::findMeshNode(char* mesh_nodename){ for(vector::iterator mn_it = this->nodes.begin(); mn_it != this->nodes.end(); mn_it++) { if( !strcmp((*mn_it)->name,mesh_nodename) ) return *mn_it; } return NULL; } TMeshNode* TModel::addMeshNodToModel(TMeshNode* parent){ PMeshNode mn; mn = (PMeshNode)KMemAlloc(sizeof(TMeshNode)); this->nodes.push_back(mn); //do korene hierarchie if(parent == NULL){ //vlozit do LODovy hierarchie if(this->lod_count != LOD_OFF){ this->lod_level[this->lod_count - 1].hierarchy = (PMeshNode*)KExtArrayRealloc(this->lod_level[this->lod_count - 1].hierarchy, sizeof(PMeshNode), this->lod_level[this->lod_count - 1].hierarchy_c + 1, this->lod_level[this->lod_count - 1].hierarchy_c); this->lod_level[this->lod_count - 1].hierarchy[this->hierarchy_c] = mn; this->lod_level[this->lod_count - 1].hierarchy_c++; } //vlozit do neLOdovy hierarchie else{ this->hierarchy = (PMeshNode*)KExtArrayRealloc( this->hierarchy, sizeof(PMeshNode), this->hierarchy_c + 1, this->hierarchy_c); this->hierarchy[this->hierarchy_c] = mn; this->hierarchy_c++; } } //jako potomek else{ parent->childs = (PMeshNode*)KExtArrayRealloc(parent->childs, sizeof(PMeshNode), parent->childs_c + 1, parent->childs_c); parent->childs[parent->childs_c] = mn; parent->childs_c++; } // mn->childs_c = 0; mn->childs = NULL; SETP3(mn->translate, 0, 0, 0); SETP3(mn->rotate.ax, 1, 0, 0); mn->rotate.ang = 0; mn->parent = parent; return mn; } int TModel::removeMeshNodFromModel(TMeshNode* mesh){ PMeshNode mn; assert(mesh); int p; //odstraneni z uzlu if(mesh->parent){ //nalezni pozici u rodice for(p = 0 ; (p < mesh->parent->childs_c) && (mesh->parent->childs[p] != mesh) ; p++); assert( (p >= 0) || (p < mesh->parent->childs_c) ); //poradi meshe v seznamu //posun zbytek o jedna dopredu memcpy(mesh->parent->childs + p, mesh->parent->childs + p + 1, (this->hierarchy_c - p - 1)); //zmensi pamet mesh->parent->childs = (PMeshNode*)KExtArrayRealloc( mesh->parent->childs, sizeof(PMeshNode), mesh->parent->childs_c - 1, mesh->parent->childs_c); mesh->parent->childs_c--; } //odstraneni z korene hierarchie else{ //z lod urovne if(this->lod_count != LOD_OFF){ for(int j = 0; j < this->lod_count; j++){ for(int k = 0; k < this->lod_level[j].hierarchy_c; k++) if(this->lod_level[j].hierarchy[k] == mesh){ memcpy(this->lod_level[j].hierarchy + k, this->lod_level[j].hierarchy + k + 1, (this->hierarchy_c - k - 1)); this->lod_level[j].hierarchy = (PMeshNode*)KExtArrayRealloc( this->lod_level[j].hierarchy, sizeof(PMeshNode), this->lod_level[j].hierarchy_c - 1, this->lod_level[j].hierarchy_c); this->hierarchy_c--; break; } } } //z nelod else{ for(p = 0 ; (p < this->hierarchy_c) && (this->hierarchy[p] != mesh) ; p++); assert( (p >= 0) || (p < this->hierarchy_c) ); memcpy(this->hierarchy + p, this->hierarchy + p + 1, (this->hierarchy_c - p - 1)); this->hierarchy = (PMeshNode*)KExtArrayRealloc( this->hierarchy, sizeof(PMeshNode), this->hierarchy_c - 1, this->hierarchy_c); this->hierarchy_c--; } } //odstreneni z vektrou + dealokace for(vector::iterator mn_it = this->nodes.begin(); mn_it != this->nodes.end(); mn_it++) { mn = *mn_it; if(mn == mesh){ this->nodes.erase(mn_it); if(mn->childs) KMemFree(mn->childs); KMemFree(mn); break; } } return 0; } TKeyframer* TModel::addFramer(){ TKeyframer* kf; kf = (TKeyframer*)KMemAlloc(sizeof(TKeyframer)); kf -> anim_object_nodes_c = 0; kf -> anim_object_nodes = NULL; strcpy(kf -> framer_name, ""); this->keyframers.push_back(kf); return kf; } TKeyframer* TModel::findFramer(char* name){ //not implemented yet return NULL; } void TModel::resetPosition(){ for(vector::iterator n_it = nodes.begin(); n_it != nodes.end(); n_it++) { CopyV3((*n_it)->rotate.ax.p, (*n_it)->initial_rotate.ax.p); CopyV3((*n_it)->translate.p, (*n_it)->initial_translate.p); CopyV3((*n_it)->scale.p, (*n_it)->initial_scale.p); } } TMaterial* TModel::addMaterialToModel(){ PMaterial mat = (PMaterial)KMemAlloc(sizeof(TMaterial)); this->matr.push_back(mat); mat->submat_c = 0; mat->submat = NULL; mat->mmap_c = 0; mat->mmap = NULL; // return mat; } TMaterial* TModel::findMaterial(const char* name){ return NULL; } void TModel::calculateAABB(TAABB* aabb){ int f = 1; MX4 tr; TAABB a; SetIdentityMX4(tr); if( lod_count != LOD_OFF ){ for( int j = 0; j < lod_count; j++){ for( int i = 0; i < lod_level[j].hierarchy_c; i++){ if( !ISHELPER(lod_level[j].hierarchy[i]) ){ CalculateAABB( lod_level[j].hierarchy[i], tr, &a); if(f){ aabb->copyAABB( &a ); f = 0; } else{ aabb->addAABB( &a ); } } }//for hierarchy }//for LODs } else if( hierarchy_c ){ for( int i = 0; i < hierarchy_c; i++){ if( !ISHELPER(hierarchy[i]) ){ CalculateAABB( hierarchy[i], tr, &a); if(f){ aabb->copyAABB( &a ); f = 0; } else{ aabb->addAABB( &a ); } } }//for hierarchy } else { // for( std::vector::iterator obj_it = data.begin(); obj_it != data.end(); obj_it++) { P3DObject o = *obj_it; for( int i = 0; i < o->mesh_c; i++){ if(f){ CalculateAABB(o->mesh+i, tr, aabb); f = 1; } else{ CalculateAABB(o->mesh+i, tr, &a); aabb->addAABB( &a ); } } }//for objects } } /////////////////////////////////////////////////////////////////////////////// void DestroyInstance(TModelInstance* in){ assert(in); //uvolni hierarchie for(int i = 0; i < in->nodes_c; i++) { if(in->nodes[i]->childs) KMemFree(in->nodes[i]->childs); KMemFree(in->nodes[i]); } //uvolnit koreny hierarchyii if(in->hierarchy_c > 0) KMemFree(in->hierarchy); if(in->lod_count > 0){ for(int t = 0; t < in->lod_count; t++){ if(in->lod_level[t].hierarchy_c) KMemFree(in->lod_level[t].hierarchy); } KMemFree(in->lod_level); } if(in->nodes) KMemFree(in->nodes); KMemFree(in); } TMeshNode* FindMeshNode(TModelInstance* inst,char* mesh_nodename){ for(int i = 0; i < inst->nodes_c; i++){ if( !strcmp(inst->nodes[i]->name,mesh_nodename) ) return inst->nodes[ i ]; } return NULL; } void ResetPosition(TModelInstance* in){ for(int i = 0; i< in->nodes_c; i++){ in->nodes[i]->rotate.ang = in->nodes[i]->initial_rotate.ang; CopyV3(in->nodes[i]->rotate.ax.p, in->nodes[i]->initial_rotate.ax.p); CopyV3(in->nodes[i]->translate.p, in->nodes[i]->initial_translate.p); CopyV3(in->nodes[i]->scale.p, in->nodes[i]->initial_scale.p); } } /////////////////////////////////////////////////////////////////////////////// void Tranform(MX4 tr1, P3F* translate, AXISANG* rotate, P3F* scale) { MX4 tr2, tr3; AATOMX(tr2, (float)Deg2Rad(rotate->ang), rotate->ax.x, rotate->ax.y, rotate->ax.z); SETV3( (tr2+12), translate->x, translate->y, translate->z); MulMatrixMX4(tr3, tr2, tr1); SetScaleMX4(tr2,scale->x,scale->y,scale->z); MulMatrixMX4(tr1, tr2, tr3); } void CalculateAABB(TMeshNode* mn, MX4 tr1, TAABB* aabb){ MX4 tr2; TAABB a; //kopie CopyMX4(tr2,tr1); //transformace2 Tranform(tr2, &(mn->translate), &(mn->rotate), &(mn->scale)); //vypocet pro tento mesh CalculateAABB(&(mn->obj->mesh[mn->mesh]), tr2, aabb); //vypocet pro potomky if( mn->childs_c ){ for( int i = 0; i < mn->childs_c; i++){ CalculateAABB( mn->childs[i], tr2, &a); aabb->addAABB( &a ); } } } void CalculateAABB(TMesh* m, MX4 tr, TAABB* aabb){ P3F max,min; P4F pos, trpos; int f = 1; TVertex* vit; TPolygon* pit; // int plast = (m->last+1); for( int p = m->first; p < plast ; p++){ pit = m->obj->poly + p; vit = m->obj->vert + pit->first; int vlast = pit->last+1; for( int i = pit->first; i < vlast ; i++){ //transformace SETV4(pos.p, vit->position.x, vit->position.y, vit->position.z, 1); APPLYVECTORMX4(pos.p, tr,trpos.p); if(f){ SETV3( min.p, trpos.x, trpos.y, trpos.z); SETV3( max.p, trpos.x, trpos.y, trpos.z); f=0; } else{ if(trpos.x < min.x)min.x = trpos.x; if(trpos.y < min.y)min.y = trpos.y; if(trpos.z < min.z)min.z = trpos.z; if(trpos.x > max.x)max.x = trpos.x; if(trpos.y > max.y)max.y = trpos.y; if(trpos.z > max.z)max.z = trpos.z; } vit++; } } aabb->aabbCenter.x = (max.x + min.x)/2; aabb->aabbCenter.y = (max.y + min.y)/2; aabb->aabbCenter.z = (max.z + min.z)/2; aabb->aabbDim.x = max.x - min.x; aabb->aabbDim.y = max.y - min.y; aabb->aabbDim.z = max.z - min.z; } void CalculateAABB(TModelInstance* inst, MX4 tr, TAABB* aabb){ int f = 1; TAABB a; if( inst->lod_count != LOD_OFF ){ for( int j = 0; j < inst->lod_count; j++){ for( int i = 0; i < inst->lod_level[j].hierarchy_c; i++){ if( !ISHELPER(inst->lod_level[j].hierarchy[i]) ){ CalculateAABB( inst->lod_level[j].hierarchy[i], tr, &a); if(f){ aabb->copyAABB( &a ); f = 0; } else{ aabb->addAABB( &a ); } } }//for hierarchy }//for LODs } else if( inst->hierarchy_c ){ for( int i = 0; i < inst->hierarchy_c; i++){ if( !ISHELPER(inst->hierarchy[i]) ){ CalculateAABB( inst->hierarchy[i], tr, &a); if(f){ aabb->copyAABB( &a ); f = 0; } else{ aabb->addAABB( &a ); } } }//for hierarchy } else { // for( std::vector::iterator obj_it = inst->model_class->data.begin(); obj_it != inst->model_class->data.end(); obj_it++) { P3DObject o = *obj_it; for( int i = 0; i < o->mesh_c; i++){ if(f){ CalculateAABB(o->mesh+i, tr, aabb); f = 1; } else{ CalculateAABB(o->mesh+i, tr, &a); aabb->addAABB( &a ); } } }//for objects } } void CalculateAABB(T3DObject* o, TAABB* aabb){ P3F max,min; TVertex* it = o->vert; // CopyV3(max.p, o->vert[0].position.p); CopyV3(min.p, o->vert[0].position.p); // for( int i = 0 ; i < o->vert_c; i++){ if(it->position.x < min.x)min.x = it->position.x; if(it->position.y < min.y)min.y = it->position.y; if(it->position.z < min.z)min.z = it->position.z; if(it->position.x < max.x)max.x = it->position.x; if(it->position.y < max.y)max.y = it->position.y; if(it->position.z < max.z)max.z = it->position.z; it++; } aabb->aabbCenter.x = (max.x + min.x)/2; aabb->aabbCenter.y = (max.y + min.y)/2; aabb->aabbCenter.z = (max.z + min.z)/2; aabb->aabbDim.x = max.x - min.x; aabb->aabbDim.y = max.y - min.y; aabb->aabbDim.z = max.z - min.z; } /////////////////////////////////////////////////////////////////////////////// TAnim_object* AddFramerObjectNode(TKeyframer* k, TMeshNode* mn){ TAnim_object* on; k->anim_object_nodes = (TAnim_object*)KExtArrayRealloc( k->anim_object_nodes, sizeof(TAnim_object), k->anim_object_nodes_c + 1, k->anim_object_nodes_c); on = k->anim_object_nodes + k->anim_object_nodes_c; k->anim_object_nodes_c ++; on->mesh = mn; strcpy(on->mesh_name, mn->name); on->pos_track_c = 0; on->rot_track_c = 0; on->scl_track_c = 0; on->pos_track = 0; on->rot_track = 0; on->scl_track = 0; return on; } /////////////////////////////////////////////////////////////////////////////// TMaterial* AddSubMaterialToMaterial(TMaterial* mat){ assert(mat); TMaterial* submat; mat->submat = (TMaterial*)KExtArrayRealloc(mat->submat, sizeof(TMaterial), mat->submat_c + 1, mat->submat_c); submat = mat->submat + mat->submat_c; mat->submat_c ++; submat->submat_c = 0; submat->submat = NULL; submat->mmap_c = 0; submat->mmap = NULL; return submat; } TMaterialMap* AddMaterialMapToMaterial(TMaterial* mat){ TMaterialMap* mmap; mat->mmap = (TMaterialMap*)KExtArrayRealloc(mat->mmap, sizeof(TMaterialMap), mat->mmap_c + 1, mat->mmap_c); mmap = mat->mmap + mat->mmap_c; mat->mmap_c ++; mmap->bitmap_file = NULL; return mmap; } }//namespace /******************************************************************************/