/** ******************************************************************************* @file /gui/engine/Scene.cpp @brief Zakladni trida pro reprezentaci 3D sceny Makro DEBUG_DRAW_AABB aktivuje vykreslovani AABB u TSceneModelObject-u. @author Vajicek+Pavel @version 0.1 ******************************************************************************/ #include "gui/engine/Scene.h" // #include "common/types.h" #include "common/exc.h" #include "gui/engine/Camera.h" #include "gui/model/DrawModel.h" #include "gui/common/mymath_ext.h" #include "gui/GUI.h" // #include #include namespace gui{ /* limitni parametry pro stavbu QuadTree */ #define MAX_LEAF_SIZE 10 #define MAX_LEAF_DEPTH 10 #define BB_BOUND 0.1f /*TSceneFog****************************************************************/ TSceneFog::TSceneFog(float s, float e, float d){ iFogOn = 1; this->setColor(1, 1, 1, 1); fFogStart = s; fFogEnd = e; fFogDensity = d; } void TSceneFog::apply(){ glFogi(GL_FOG_MODE, GL_LINEAR); glFogf(GL_FOG_START, fFogStart); glFogf(GL_FOG_END, fFogEnd); glFogfv(GL_FOG_COLOR, f4FogColor); glClearColor(f4FogColor[0], f4FogColor[1], f4FogColor[2], f4FogColor[3]); glFogf(GL_FOG_DENSITY, fFogDensity); } void TSceneFog::setColor(float r, float g, float b, float a){ SETV4(f4FogColor, r, g, b, a); } /*TLightSource****************************************************************/ TLightSource::TLightSource(KHANDLE name, HWID id){ if(id > GL_MAX_LIGHTS) THROW(E_8K_GUI, "Exceed maximum number of renderer lights\n"); SETP4(p4fPosition,0,0,0,1); SETP4(p4fAmbient,0,0,0,1); SETP4(p4fDiffuse,1,1,1,1); SETP4(p4fSpecular,1,1,1,1); SETP3(p3fAttenuation,1,0,0); SETP3(p3fSpotDirection,0,0,1); fSpotExponent=0; fSpotCutoff=180; iEnabled=1; hId = id; hName = name; } // void TLightSource::setupRendererLight(){ glLightfv(GL_LIGHT0+hId,GL_AMBIENT, p4fAmbient.p); glLightfv(GL_LIGHT0+hId,GL_DIFFUSE, p4fDiffuse.p); glLightfv(GL_LIGHT0+hId,GL_SPECULAR, p4fSpecular.p); glLightfv(GL_LIGHT0+hId,GL_POSITION, p4fPosition.p); glLightfv(GL_LIGHT0+hId,GL_SPOT_DIRECTION, p3fSpotDirection.p); glLightf(GL_LIGHT0+hId,GL_SPOT_EXPONENT, fSpotExponent); glLightf(GL_LIGHT0+hId,GL_SPOT_CUTOFF, fSpotCutoff); // glLightf(GL_LIGHT0+hId,GL_CONSTANT_ATTENUATION, p3fAttenuation.p[0]); glLightf(GL_LIGHT0+hId,GL_LINEAR_ATTENUATION, p3fAttenuation.p[1]); glLightf(GL_LIGHT0+hId,GL_QUADRATIC_ATTENUATION, p3fAttenuation.p[2]); if(iEnabled) { glEnable(GL_LIGHT0+hId); } else { glDisable(GL_LIGHT0+hId); } } // TLightSource::~TLightSource() { glDisable(GL_LIGHT0+hId); } /*TSceneObject*****************************************************************/ ///virtualni funkce volana vsemi potomky udrzuje konzistenci mezi ruznymi reprezentacemi void TSceneObject::positionUpdated(){ } void TSceneObject::setPositionMX4(MX4 mx4) { CopyMX4(mx4Pos,mx4); positionUpdated(); } void TSceneObject::getPositionMX4(MX4 mx4) { CopyMX4(mx4, mx4Pos); } void TSceneObject::moveTo(float x,float y,float z){ P4F pos,tpos; SETP4(pos,0,0,0,1); //zjisten pozice ApplyVectorMX4(pos.p,mx4Pos,tpos.p); //relativni translace moveBy(x-tpos.x,y-tpos.y,z-tpos.z); } void TSceneObject::moveBy(float x,float y,float z){ MX4 trans,v; SetTransMX4(trans,x,y,z); MulMatrixMX4(v,trans,mx4Pos); CopyMX4(mx4Pos,v); positionUpdated(); } void TSceneObject::rotateTo(float x,float y,float z){ float orig[]={0, 0, 0}; // Transform(mx4Pos, orig); SetIdentityMX4(mx4Pos); moveTo(orig[0], orig[1], orig[2]); rotateBy(x, y, z); } void TSceneObject::rotateBy(float x,float y,float z){ MX4 rotx; MX4 roty; MX4 rotz; // SetRotXMX4(rotx,x); SetRotYMX4(roty,y); SetRotZMX4(rotz,z); // MX4 v; MulMatrixMX4(v,rotx,roty); MulMatrixMX4(rotx,v,rotz); //zapojeni do celkovy transformace MulMatrixMX4(v,rotx,mx4Pos); CopyMX4(mx4Pos,v); // positionUpdated(); } void TSceneObject::uniformScale(float scl){ MX4 m,n; SetScaleMX4(m,scl,scl,scl); MulMatrixMX4(n, m, mx4Pos); CopyMX4(mx4Pos,n); } void TSceneObject::setPosition(P3F* pos){ setPosition(pos->x, pos->y, pos->z); } void TSceneObject::setPosition(float x, float y, float z) { SETV3((mx4Pos + 12), x, y, z); positionUpdated(); } void TSceneObject::setPosition(P3F* pos, P3F* dir, P3F* up){ MX4 m; P3F T,N, B; VectMulV3(N.p, up->p, dir->p); VectMulV3(B.p, N.p, dir->p); CopyV3(T.p, dir->p); NormalizeV3(T.p); NormalizeV3(N.p); NormalizeV3(B.p); SetMX4(m, T.x, T.y, T.z, 0, N.x, N.y, N.z, 0, B.x, B.y, B.z, 0, pos->x, pos->y, pos->z, 1); setPositionMX4(m); } void TSceneObject::getPosition(P3F* pos){ SETV3(pos->p, 0, 0, 0); // Transform(mx4Pos, &(pos->x), &(pos->y), &(pos->z)); } void TSceneObject::setOrientation(P3F* dir, P3F* up) { setOrientation( dir->x, dir->y, dir->z, up->x, up->y, up->z); } void TSceneObject::setOrientation(float dx, float dy, float dz, float ux, float uy, float uz) { P3F bn, up, d; // SETV3(up.p, ux, uy, uz); SETV3(d.p, dx, dy, dz); // VectMulV3(bn.p, d.p, up.p); // VectMulV3(up.p, bn.p, d.p); // NormalizeV3(up.p); NormalizeV3(bn.p); NormalizeV3(d.p); // SetMX4( mx4Pos, bn.x, bn.y, bn.z, 0, d.x, d.y, d.z, 0, up.x, up.y, up.z, 0, mx4Pos[12], mx4Pos[13], mx4Pos[14], mx4Pos[15]); positionUpdated(); } void TSceneObject::drawObject() { #ifdef DEBUG_DRAW_AABB drawAABB(); #endif } TSceneObject::TSceneObject() : TSelectableObject() { SetIdentityMX4(mx4Pos); transparent = false; fade = FADE_UNDEF; tag = -1; tag2 = -1; myscene = NULL; //statistika TSceneObject::iSceneObjects++; } TSceneObject::~TSceneObject() { //statistika TSceneObject::iSceneObjects--; } int TSceneObject::getRealFade() { if (fade != FADE_UNDEF) return fade; if (myscene) return myscene->getFadeFromTag(tag, tag2); return 0; } int TSceneObject::iSceneObjects = 0; /*TModelSceneObject***********************************************************/ TModelSceneObject::TModelSceneObject(TModel *mid) { inst = mid?mid->instantiateModel():NULL; dwDrawFlag = RIGID_TRANSFORM | DRAW_MATERIAL_TEXTURE; iRenderTime = -1; selected = false; } TModelSceneObject::~TModelSceneObject(){ DestroyInstance(inst); } void TModelSceneObject::drawObject() { int _fade = fade; _fade = getRealFade(); //nastaveni osvetleni GLboolean flashon; if (_fade == FADE_4) return; else if (_fade == FADE_0) glEnable(GL_LIGHT0); else if (_fade == FADE_1) glEnable(GL_LIGHT2); else if (_fade == FADE_2) glEnable(GL_LIGHT3); glGetBooleanv(GL_LIGHT1, &flashon); if (_fade != FADE_0) glDisable(GL_LIGHT1); //vlastni vykreslovani glMatrixMode(GL_MODELVIEW); glPushMatrix(); glMultMatrixf(mx4Pos); DrawModel_v4(inst, dwDrawFlag); glPopMatrix(); TSceneObject::drawObject(); //zruseni osvetleni if (_fade == FADE_0) glDisable(GL_LIGHT0); else if (_fade == FADE_1) glDisable(GL_LIGHT2); else if (_fade == FADE_2) glDisable(GL_LIGHT3); if (flashon) glEnable(GL_LIGHT1); } void TModelSceneObject::calculateMatrix() { AATOMX(mx4Pos, axisangRotate.ang, axisangRotate.ax.x, axisangRotate.ax.y, axisangRotate.ax.z); SETV3( (mx4Pos+12), p3fTranslate.x, p3fTranslate.y, p3fTranslate.z); } void TModelSceneObject::positionUpdated() { QUATER q; // TSceneObject::positionUpdated(); // MXTOTR_ROT(mx4Pos, &p3fTranslate, &q); QTOAA(&q, &(axisangRotate.ax), &(axisangRotate.ang)); } void TModelSceneObject::calculateAABB() { CalculateAABB(inst, mx4Pos, this); } bool TModelSceneObject::Collision(TRay* ray, float *t) { return TAABB::Collision(ray, t); } /*TQuadNode****************************************************************************/ void TQuadNode::addObject(TSceneObject* so) { so->calculateAABB(); so->calculateMinsMaxs(); if (!bTreeBuilt) { if ( objs.empty() && tobjs.empty() ) copyAABB(so); else addAABB(so); if (so->transparent) tobjs.push_back(so); else objs.push_back(so); } else { placeObject(so); } } TSceneObject *TQuadNode::remFromScene(TSceneObject* so) { if (bIsLeaf){ // hledam scene objekt mezi nepruhlednymi Tsceneobjs::iterator it; it = objs.begin(); while( it != objs.end() ){ if ( (*it) == so ) { objs.erase(it); return so; } it++; } // kdyz nenajdu objekt mezi nepruhlednymi, tak hledam mezi pruhlednymi it = tobjs.begin(); while( it != tobjs.end() ){ if ( (*it) == so ) { tobjs.erase(it); return so; } it++; } } else { for (int i = 0; i < 4; i++) if (so->Collision(Childs[i]) ) Childs[i]->remFromScene(so); return so; } return NULL; } int lad; void TQuadNode::drawObject(TFrustum *fr, bool transparent) { // v koreni zvetsim RenderTime if ( (quadrNodeDepth == 1) && (!transparent) ) { lad = 0; iRenderTime++; if (iRenderTime >= MAXINT - 1) iRenderTime = 0; } // pokud nejsem videt v kamere tak skoncim if ( !(fr->IsIn(this)) ) return; if (bIsLeaf){ lad++; // pokud jsem list tak nakreslim vsechny objekty v sobe Tsceneobjs::iterator it; if (transparent){ for(it = tobjs.begin();it != tobjs.end(); it++) { if (((*it)->iRenderTime != iRenderTime) && (fr->IsIn( (*it) ))){ (*it)->iRenderTime = iRenderTime; (*it)->drawObject(); } } } else { for(it = objs.begin(); it != objs.end(); it++) { if (((*it)->iRenderTime != iRenderTime) && (fr->IsIn( (*it) ))){ (*it)->iRenderTime = iRenderTime; (*it)->drawObject(); } } } // if (transparent) {...} else } else { Childs[0]->drawObject(fr, transparent); Childs[1]->drawObject(fr, transparent); Childs[2]->drawObject(fr, transparent); Childs[3]->drawObject(fr, transparent); } } void TQuadNode::drawObject(TFrustum *fr) { // nakreslim nepruhledne objekty drawObject(fr, false); // nakreslim pruhledne objekty drawObject(fr, true); } void TQuadNode::placeObject(TSceneObject* so) { if (!bIsLeaf){ for (int i = 0; i < 4; i++) if ( so->Collision(Childs[i]) ) Childs[i]->placeObject(so); } else { if (so->transparent) tobjs.push_back(so); else objs.push_back(so); } } void TQuadNode::buildTree() { int i; TAABB chaabb[4]; if (quadrNodeDepth==1) { // upravim z-ovou slozku aabb pro pripad ze by nejake pohyblive objekty vylezly z obalky statickych aabbCenter.z = (low_node_height + high_node_height)/2.0f; aabbDim.z = high_node_height - low_node_height; } // spocita i alternativni definici AABB TAABB::calculateMinsMaxs(); size_t f = objs.size(); if (( (objs.size()+tobjs.size()) > MAX_LEAF_SIZE) && (aabbDim.x >= 2 * min_leaf_dim) && (aabbDim.y >= 2 * min_leaf_dim) && (quadrNodeDepth < MAX_LEAF_DEPTH)){ bIsLeaf = false; Childs[0] = new TQuadNode(); Childs[0]->quadrNodeDepth=quadrNodeDepth + 1; Childs[1] = new TQuadNode(); Childs[1]->quadrNodeDepth=quadrNodeDepth + 1; Childs[2] = new TQuadNode(); Childs[2]->quadrNodeDepth=quadrNodeDepth + 1; Childs[3] = new TQuadNode(); Childs[3]->quadrNodeDepth=quadrNodeDepth + 1; // levy horni Childs[0]->aabbCenter.x = aabbCenter.x - aabbDim.x / 4; Childs[0]->aabbCenter.y = aabbCenter.y - aabbDim.y / 4;; Childs[0]->aabbCenter.z = aabbCenter.z; Childs[0]->aabbDim.x = aabbDim.x / 2 + BB_BOUND; Childs[0]->aabbDim.y = aabbDim.y / 2 + BB_BOUND; Childs[0]->aabbDim.z = aabbDim.z; // levy dolni Childs[1]->aabbCenter.x = aabbCenter.x - aabbDim.x / 4; Childs[1]->aabbCenter.y = aabbCenter.y + aabbDim.y / 4; Childs[1]->aabbCenter.z = aabbCenter.z; Childs[1]->aabbDim.x = aabbDim.x / 2 + BB_BOUND; Childs[1]->aabbDim.y = aabbDim.y / 2 + BB_BOUND; Childs[1]->aabbDim.z = aabbDim.z; // pravy horni Childs[2]->aabbCenter.x = aabbCenter.x + aabbDim.x / 4; Childs[2]->aabbCenter.y = aabbCenter.y - aabbDim.y / 4; Childs[2]->aabbCenter.z = aabbCenter.z; Childs[2]->aabbDim.x = aabbDim.x / 2 + BB_BOUND; Childs[2]->aabbDim.y = aabbDim.y / 2 + BB_BOUND; Childs[2]->aabbDim.z = aabbDim.z; // pravy dolni Childs[3]->aabbCenter.x = aabbCenter.x + aabbDim.x / 4; Childs[3]->aabbCenter.y = aabbCenter.y + aabbDim.y / 4; Childs[3]->aabbCenter.z = aabbCenter.z; Childs[3]->aabbDim.x = aabbDim.x / 2 + BB_BOUND; Childs[3]->aabbDim.y = aabbDim.y / 2 + BB_BOUND; Childs[3]->aabbDim.z = aabbDim.z; Tsceneobjs::iterator it; // rozdelim nepruhledne objekty for(it = objs.begin(); it != objs.end(); it++) { for (i = 0; i < 4; i++){ if ((*it)->Collision(Childs[i]) ) { Childs[i]->objs.push_back((*it)); } } } // rozdelim pruhledne objekty for(it = tobjs.begin(); it != tobjs.end(); it++) { for (i = 0; i < 4; i++){ if ( (*it)->Collision(Childs[i]) ) { Childs[i]->tobjs.push_back( (*it) ); } } } // smazu objekty, ktere jsem rozdelil objs.clear(); tobjs.clear(); for (i = 0; i < 4; i++) Childs[i]->buildTree(); } if (quadrNodeDepth == 1) bTreeBuilt = true; } void TQuadNode::destroyTree() { if (bIsLeaf) { objs.clear(); tobjs.clear(); } else { for(int i = 0 ; i < 4 ; i++) { Childs[i]->destroyTree(); delete Childs[i]; Childs[i] = NULL; } // bIsLeaf = true; // koren if (quadrNodeDepth == 1) { bTreeBuilt = false; } } } bool TQuadNode::Collision(TRay* ray, float *t, TSceneObject **mso) { float temp, tmin; bool coli; int iHighestPriority; if (TAABB::Collision(ray, &temp) ) { if (bIsLeaf) { coli = false; tmin = ray->far_clip; *mso = NULL; iHighestPriority = -1; Tsceneobjs::iterator it; // nepruhledne objekty for(it = objs.begin(); it != objs.end(); it++) { if ((*it)->selectable && ((*it)->getRealFade() == FADE_0) && (*it)->Collision(ray, &temp) ){ if ( (( temp < tmin ) && ((*it)->iPriorityOfSelection >=iHighestPriority)) || ( (*it)->iPriorityOfSelection > iHighestPriority) ) { coli = true; tmin = temp; (*mso) = (*it); iHighestPriority = (*it)->iPriorityOfSelection; } } // if } // for // pruhledne objekty for(it = tobjs.begin(); it != tobjs.end(); it++) { if ((*it)->selectable && ((*it)->getRealFade() == FADE_0) && (*it)->Collision(ray, &temp) ){ if ( (( temp < tmin ) && ((*it)->iPriorityOfSelection >=iHighestPriority)) || ( (*it)->iPriorityOfSelection > iHighestPriority) ) { coli = true; tmin = temp; (*mso) = (*it); iHighestPriority = (*it)->iPriorityOfSelection; } } // if } // for *t = tmin; return coli; } else { TSceneObject *mso2; coli = false; tmin = ray->far_clip; *mso = NULL; iHighestPriority = -1; for (int i = 0; i < 4; i++){ if ( Childs[i]->Collision(ray, &temp, &mso2) ) { if ( (( temp < tmin ) && (mso2->iPriorityOfSelection >=iHighestPriority)) || ( mso2->iPriorityOfSelection > iHighestPriority) ) { coli = true; tmin = temp; (*mso) = mso2; iHighestPriority = mso2->iPriorityOfSelection; } } // if } // for *t = tmin; return coli; } // if (bIsLeaf) else } // if (Collision(ray, t) ) else return false; } void TQuadNode::reinstalObject(TSceneObject* so) { remFromScene(so); so->calculateAABB(); so->calculateMinsMaxs(); placeObject(so); } TQuadNode::TQuadNode() { bIsLeaf = true; quadrNodeDepth = 1; for(int i = 0 ; i < 4 ; i++) Childs[i] = NULL; low_node_height = -1; high_node_height = 1; min_leaf_dim = 1; } void TQuadNode::init() { bIsLeaf = true; quadrNodeDepth = 1; for(int i = 0 ; i < 4 ; i++) Childs[i] = NULL; low_node_height = -1; high_node_height = 1; min_leaf_dim = 1; } void TQuadNode::setBounds(float _low_node_height, float _high_node_height, float _min_leaf_dim) { low_node_height = _low_node_height; high_node_height = _high_node_height; min_leaf_dim = _min_leaf_dim; } void TQuadNode::findSceneObject(TSceneObject* so) { // for(Tsceneobjs::iterator it = objs.begin(); it != objs.end(); it++) { if(*it == so){ printf("%p! found ya!\n", so); } } // if(!bIsLeaf) { Childs[0]->findSceneObject(so); Childs[1]->findSceneObject(so); Childs[2]->findSceneObject(so); Childs[3]->findSceneObject(so); } } bool TQuadNode::bTreeBuilt; int TQuadNode::iRenderTime; float TQuadNode::high_node_height; float TQuadNode::low_node_height; float TQuadNode::min_leaf_dim; /*TScene**********************************************************************/ TScene::TScene(int _x, int _y, int _width, int _height) : TButton(AO_HIDDEN, _x, _y, _width, _height) { iRenderTime = -1; bTreeBuilt = false; fog = NULL; } void TScene::init() { TQuadNode::init(); iRenderTime = -1; bTreeBuilt = false; fog = NULL; } TLightSource* TScene::getLight(KHANDLE name){ Tlightsources::iterator it; TLightSource* ls; it=vLightSources.begin(); while(it!=vLightSources.end()){ ls=(*it); if(ls->hName == name){ return ls; } it++; } return NULL; } void TScene::addLightSource(TLightSource* ls){ vLightSources.push_back(ls); } // TLightSource* TScene::remLightSource(KHANDLE name){ Tlightsources::iterator it; TLightSource* ls; it=vLightSources.begin(); while(it!=vLightSources.end()){ ls=(*it); if(ls->hName == name){ vLightSources.erase(it); return ls; } it++; } return NULL; } // void TScene::setupLights(){ Tlightsources::iterator it; TLightSource* ls; it=vLightSources.begin(); while(it!=vLightSources.end()){ ls=(*it); ls->setupRendererLight(); it++; } } void TScene::destroyScene() { // uvolneni mlhy if(fog) delete fog; // uvolni svetla for(Tlightsources::iterator it= vLightSources.begin();it!=vLightSources.end();it++) delete (*it); vLightSources.clear(); // uvolni staticke a dynamicke objekty TQuadNode::destroyTree(); } void TScene::drawScene(TCamera* cam) { TFrustum fr; //nastaveni polohy kamery cam->setCam(); //svetla setupLights(); //viditelnej jehlan cam->getFrustum(&fr); //vykresleni stromu sceny protinajici se s jehlanem TQuadNode::drawObject(&fr); } //obecne nastaveni pro 3d scenu, ostatni se dela v konktretnim potomkovi void TScene::setupScene() { //matice glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); //vlastnosti glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glDepthFunc(GL_LEQUAL); //vyrez active objectu glViewport(x,SCREEN_HEIGHT-height-y,width,height); } void TScene::resetScene(){ //cela obrazovka glViewport(0,0,SCREEN_WIDTH,SCREEN_HEIGHT); //vlastnosti glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glDepthFunc(GL_ALWAYS); //matice glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } void TScene::addObject(TSceneObject *so) { so->myscene = this; TQuadNode::addObject(so); } void TScene::reinstalObject(TSceneObject *so) { so->myscene = this; TQuadNode::reinstalObject(so); } int TScene::getFadeFromTag(int tag, int tag2) { return FADE_0; } }//namespace /*****************************************************************************/