/** ******************************************************************************* @file /gui/engine/SceneGeom.cpp @brief Datove struktury pro geometrii sceny, vrcholy, site polygonu. @author Vajicek @version 0.1 ******************************************************************************/ // #include "gui/engine/SceneGeom.h" #include "gui/GUI.h" // #include #include /*****************************************************************************/ namespace gui{ #define CLIPPING_BOUND 5 // prozatimne #define NEAR_CLIP 1 #define FAR_CLIP (8*HEX_EDGE_LENGTH) /*TRay************************************************************************/ void TRay::set(P3F _start, P3F _dir, float _near_clip, float _far_clip) { CopyV3(start.p, _start.p); CopyV3(dir.p, _dir.p); near_clip = _near_clip; far_clip = _far_clip; } float TRay::dist2(P3F *x) { P3F vX; CopyV3(vX.p, x->p); SubV3(vX.p, start.p); float alfa = ScalMulV3(vX.p, dir.p); P3F Y; CopyV3(Y.p, dir.p); MulV3(Y.p, alfa); AddV3(Y.p, start.p); return ( sqr(x->x-Y.x) + sqr(x->y-Y.y) + sqr(x->z-Y.z) ); } bool TRay::zPlaneIntersect(P2F *inter, float z) { if (isZero(dir.z)) return false; float t = (z - start.z) / dir.z; // paprsek je poloprimka if (t < 0) return false; inter->x = start.x + t * dir.x; inter->y = start.y + t * dir.y; return true; } void TRay::getP3F(float t, P3F *p3f) { CopyV3(p3f->p, dir.p); MulV3(p3f->p, t); AddV3(p3f->p, start.p); } TRay::TRay(float sx, float sy, float sz, float dx, float dy, float dz, float _near_clip, float _far_clip){ SETV3(start.p, sx, sy, sz); SETV3(dir.p, dx, dy, dz); near_clip = _near_clip; far_clip = _far_clip; } TRay::TRay(){ } /*TPlane**********************************************************************/ int TPlane::Collision(P3F *p3f) { float a = ScalMulV3(p3f->p, dat.p); if (a + dat.u > 0) return PLANE_ABOVE; if (a + dat.u < 0) return PLANE_BELOW; return PLANE_IN; } void TPlane::set(P3F vert, P3F norm) { CopyV3(dat.p, norm.p); dat.u = -ScalMulV3(vert.p, norm.p); } bool TPlane::Collision(TRay *ray, float *t) { float temp = ScalMulV3(ray->dir.p, dat.p); if (isZero(temp)) return false; *t = -( ScalMulV3(ray->start.p, dat.p) + dat.u) / temp; if (*t < 0) return false; return true; } void TPlane::set(float a, float b, float c, float d) { SETP4(dat, a, b, c, d); } /*TFrustum********************************************************************/ #define FRUSTUM_BOUND 0.01 bool TFrustum::Vertex2Frustum(P3F *p3f, P3F *vert) { bool ret; P3F X; CopyV3(X.p, vert->p); SubV3(X.p, pos.p); float sp = ScalMulV3(X.p, dir.p); if (sp==0){ p3f->x = 2; p3f->y = 2; return false; } ret = ( (sp > near_clip-CLIPPING_BOUND) && (sp <= far_clip+CLIPPING_BOUND) ); p3f->z = sp; if (sp < 0) sp = -sp; MulV3(X.p, (1.0f/sp) ); p3f->y = ScalMulV3(down.p, X.p); p3f->x = ScalMulV3(right.p, X.p); return ret; } inline bool TFrustum::IsIn(P3F *p3f) { P3F _p3f; return ( Vertex2Frustum(&_p3f, p3f) && (_p3f.x >= (-1.0f-FRUSTUM_BOUND)) && (_p3f.x <= (1.0f+FRUSTUM_BOUND)) && (_p3f.y >= (-1.0f-FRUSTUM_BOUND)) && (_p3f.y <= (1.0f+FRUSTUM_BOUND)) ); } inline bool pointAboveLine(P2F *x, P2F *A, P2F *B) { if (A->x == B->x) return true; return ( (B->y-A->y)/(B->x-A->x)*(x->x-A->x)+A->y <= x->y ); } void TFrustum::calculateAABB() { // dva rohy pocitaneho aabb P3F lowcorn, highcorn; SETP3(lowcorn, (float)MAXINT, (float)MAXINT, (float)MAXINT); SETP3(highcorn, -(float)MAXINT, -(float)MAXINT, -(float)MAXINT); P3F corn, lowdir, highdir, lowdown, highdown, lowright, highright; // lowdir = near_clip * dir CopyV3(lowdir.p, dir.p); MulV3(lowdir.p, near_clip); // highdir = far_clip * dir CopyV3(highdir.p, dir.p); MulV3(highdir.p, far_clip); // lowdown = near_clip * down CopyV3(lowdown.p, down.p); MulV3(lowdown.p, near_clip); // highdown = far_clip * down CopyV3(highdown.p, down.p); MulV3(highdown.p, far_clip); // lowright = near_clip * right CopyV3(lowright.p, right.p); MulV3(lowright.p, near_clip); // highright = far_clip * right CopyV3(highright.p, right.p); MulV3(highright.p, far_clip); for (int i = 0; i < 8; i++){ CopyV3(corn.p, pos.p); if (i%2) { AddV3(corn.p, lowdir.p); if ((i/2)%2) { AddV3(corn.p, lowright.p); } else { SubV3(corn.p, lowright.p); } if ((i/4)%2) { AddV3(corn.p, lowdown.p); } else { SubV3(corn.p, lowdown.p); } } else { AddV3(corn.p, highdir.p); if ((i/2)%2) { AddV3(corn.p, highright.p); } else { SubV3(corn.p, highright.p); } if ((i/4)%2) { AddV3(corn.p, highdown.p); } else { SubV3(corn.p, highdown.p); } } lowcorn.x = MIN(lowcorn.x, corn.x); lowcorn.y = MIN(lowcorn.y, corn.y); lowcorn.z = MIN(lowcorn.z, corn.z); highcorn.x = MAX(highcorn.x, corn.x); highcorn.y = MAX(highcorn.y, corn.y); highcorn.z = MAX(highcorn.z, corn.z); } aabbCenter.x = (lowcorn.x + highcorn.x) / 2.0f; aabbCenter.y = (lowcorn.y + highcorn.y) / 2.0f; aabbCenter.z = (lowcorn.z + highcorn.z) / 2.0f; aabbDim.x = (highcorn.x - lowcorn.x); aabbDim.y = (highcorn.y - lowcorn.y); aabbDim.z = (highcorn.z - lowcorn.z); } bool TFrustum::IsIn(TAABB *aabb) { // return Collision(aabb); P3F vmin, vmax; for (int i = 0; i < 6; ++i) { // X axis if (planes[i].dat.x > 0) { vmin.x = aabb->mins.x; vmax.x = aabb->maxs.x; } else { vmin.x = aabb->maxs.x; vmax.x = aabb->mins.x; } // Y axis if (planes[i].dat.y > 0) { vmin.y = aabb->mins.y; vmax.y = aabb->maxs.y; } else { vmin.y = aabb->maxs.y; vmax.y = aabb->mins.y; } // Z axis if (planes[i].dat.z > 0) { vmin.z = aabb->mins.z; vmax.z = aabb->maxs.z; } else { vmin.z = aabb->maxs.z; vmax.z = aabb->mins.z; } if (ScalMulV3(planes[i].dat.p, vmin.p) + planes[i].dat.u > 0) return false; } return true; } void TFrustum::calculatePlanes() { P3F p3f, negdir, p3fb; float alfa; // normaly smeruju ven z objemu frusta CopyV3(negdir.p, dir.p); MulV3(negdir.p, -1.0f); // rovina nejbliz kamery CopyV3(p3f.p, dir.p); MulV3(p3f.p, near_clip); AddV3(p3f.p, pos.p); planes[0].set(p3f, negdir); // rovina nejvzdalenejsi od kamery CopyV3(p3f.p, dir.p); MulV3(p3f.p, far_clip); AddV3(p3f.p, pos.p); CopyV3(p3fb.p, negdir.p); MulV3(p3fb.p, -1.0f); planes[1].set(p3f, p3fb); // horni rovina CopyV3(p3f.p, dir.p); AddV3(p3f.p, up.p); alfa = ScalMulV3(dir.p, dir.p) / ScalMulV3(p3f.p, p3f.p); MulV3(p3f.p, alfa); SubV3(p3f.p, dir.p); planes[2].set(pos, p3f); // dolni rovina CopyV3(p3f.p, dir.p); AddV3(p3f.p, down.p); alfa = ScalMulV3(dir.p, dir.p) / ScalMulV3(p3f.p, p3f.p); MulV3(p3f.p, alfa); SubV3(p3f.p, dir.p); planes[3].set(pos, p3f); // leva rovina CopyV3(p3f.p, dir.p); AddV3(p3f.p, left.p); alfa = ScalMulV3(dir.p, dir.p) / ScalMulV3(p3f.p, p3f.p); MulV3(p3f.p, alfa); SubV3(p3f.p, dir.p); planes[4].set(pos, p3f); // horni rovina CopyV3(p3f.p, dir.p); AddV3(p3f.p, right.p); alfa = ScalMulV3(dir.p, dir.p) / ScalMulV3(p3f.p, p3f.p); MulV3(p3f.p, alfa); SubV3(p3f.p, dir.p); planes[5].set(pos, p3f); } /*AABB************************************************************************/ void TAABB::addAABB( TAABB* aabb ){ P3F max, min; // max.x = MAX( (aabb->aabbCenter.x + aabb->aabbDim.x/2), (aabbCenter.x + aabbDim.x/2) ); max.y = MAX( (aabb->aabbCenter.y + aabb->aabbDim.y/2), (aabbCenter.y + aabbDim.y/2) ); max.z = MAX( (aabb->aabbCenter.z + aabb->aabbDim.z/2), (aabbCenter.z + aabbDim.z/2) ); // min.x = MIN( (aabb->aabbCenter.x - aabb->aabbDim.x/2), (aabbCenter.x - aabbDim.x/2) ); min.y = MIN( (aabb->aabbCenter.y - aabb->aabbDim.y/2), (aabbCenter.y - aabbDim.y/2) ); min.z = MIN( (aabb->aabbCenter.z - aabb->aabbDim.z/2), (aabbCenter.z - aabbDim.z/2) ); // aabbCenter.x = (max.x + min.x)/2; aabbCenter.y = (max.y + min.y)/2; aabbCenter.z = (max.z + min.z)/2; aabbDim.x = (max.x - min.x); aabbDim.y = (max.y - min.y); aabbDim.z = (max.z - min.z); } void TAABB::copyAABB(TAABB* aabb){ // CopyV3( aabbCenter.p, aabb->aabbCenter.p ); CopyV3( aabbDim.p, aabb->aabbDim.p ); } void TAABB::calculateAABB(){ } bool TAABB::Collision(TAABB *aabb) { return ( ( myabs(aabb->aabbCenter.x-aabbCenter.x) <= (aabb->aabbDim.x+aabbDim.x)/2 ) && ( myabs(aabb->aabbCenter.y-aabbCenter.y) <= (aabb->aabbDim.y+aabbDim.y)/2 ) && ( myabs(aabb->aabbCenter.z-aabbCenter.z) <= (aabb->aabbDim.z+aabbDim.z)/2 ) ); } bool TAABB::Collision(TAABB *aabb, float *ratio) { float xVol = MIN( (aabb->aabbDim.x + aabbDim.x)/2 - (myabs(aabb->aabbCenter.x - aabbCenter.x)), MIN(aabb->aabbDim.x, aabbDim.x)); float a = aabb->aabbDim.x; float b = aabbDim.x; float c = aabb->aabbCenter.x; float d = aabbCenter.x; float yVol = MIN( (aabb->aabbDim.y + aabbDim.y)/2 - (myabs(aabb->aabbCenter.y - aabbCenter.y)), MIN(aabb->aabbDim.y, aabbDim.y)); float zVol = MIN( (aabb->aabbDim.z + aabbDim.z)/2 - (myabs(aabb->aabbCenter.z - aabbCenter.z)), MIN(aabb->aabbDim.z, aabbDim.z)); float myVol = aabbDim.x * aabbDim.y * aabbDim.z; if ( (xVol < 0) || (yVol < 0) || (zVol < 0) || (myVol == 0) ) { ratio = 0; return false; } *ratio = (xVol * yVol * zVol) / myVol; return true; } bool TAABB::isIn(P3F *p3f) { return ( ( myabs(p3f->x-aabbCenter.x) <= (aabbDim.x)/2 ) && ( myabs(p3f->y-aabbCenter.y) <= (aabbDim.y)/2 ) && ( myabs(p3f->z-aabbCenter.z) <= (aabbDim.z)/2 ) ); } bool TAABB::Collision(TRay* ray, float *t) { float t1, xi, yi, zi ; *t = ray->far_clip*ray->far_clip; bool ret=false; if (ray->dir.x != 0) { // x near t1 = (aabbCenter.x-aabbDim.x/2-ray->start.x)/ray->dir.x; if (t1 > ray->near_clip ) { yi = ray->start.y + t1 * ray->dir.y; zi = ray->start.z + t1 * ray->dir.z; if ( (yi >= aabbCenter.y-aabbDim.y/2) && (yi <= aabbCenter.y+aabbDim.y/2) && (zi >= aabbCenter.z-aabbDim.z/2) && (zi <= aabbCenter.z+aabbDim.z/2) ) { *t = ray->dist2(&aabbCenter); return true; } } // x far t1 = (aabbCenter.x+aabbDim.x/2-ray->start.x)/ray->dir.x; if (t1 > ray->near_clip) { yi = ray->start.y + t1 * ray->dir.y; zi = ray->start.z + t1 * ray->dir.z; if ( (yi >= aabbCenter.y-aabbDim.y/2) && (yi <= aabbCenter.y+aabbDim.y/2) && (zi >= aabbCenter.z-aabbDim.z/2) && (zi <= aabbCenter.z+aabbDim.z/2) ) { *t = ray->dist2(&aabbCenter); return true; } } } // if (ray->dir.x != 0) if (ray->dir.y != ray->near_clip) { // y near t1 = (aabbCenter.y-aabbDim.y/2-ray->start.y)/ray->dir.y; if (t1 > 0) { xi = ray->start.x + t1 * ray->dir.x; zi = ray->start.z + t1 * ray->dir.z; if ( (xi >= aabbCenter.x-aabbDim.x/2) && (xi <= aabbCenter.x+aabbDim.x/2) && (zi >= aabbCenter.z-aabbDim.z/2) && (zi <= aabbCenter.z+aabbDim.z/2) ) { *t = ray->dist2(&aabbCenter); return true; } } // y far t1 = (aabbCenter.y+aabbDim.y/2-ray->start.y)/ray->dir.y; if (t1 > ray->near_clip) { xi = ray->start.x + t1 * ray->dir.x; zi = ray->start.z + t1 * ray->dir.z; if ( (xi >= aabbCenter.x-aabbDim.x/2) && (xi <= aabbCenter.x+aabbDim.x/2) && (zi >= aabbCenter.z-aabbDim.z/2) && (zi <= aabbCenter.z+aabbDim.z/2) ) { *t = ray->dist2(&aabbCenter); return true; } } } // if (ray->dir.y != 0) if (ray->dir.z != 0) { // z near t1 = (aabbCenter.z-aabbDim.z/2-ray->start.z)/ray->dir.z; if (t1 > ray->near_clip) { xi = ray->start.x + t1 * ray->dir.x; yi = ray->start.y + t1 * ray->dir.y; if ( (xi >= aabbCenter.x-aabbDim.x/2) && (xi <= aabbCenter.x+aabbDim.x/2) && (yi >= aabbCenter.y-aabbDim.y/2) && (yi <= aabbCenter.y+aabbDim.y/2) ) { *t = ray->dist2(&aabbCenter); return true; } } // z far t1 = (aabbCenter.z+aabbDim.z/2-ray->start.z)/ray->dir.z; if (t1 > ray->near_clip) { xi = ray->start.x + t1 * ray->dir.x; yi = ray->start.y + t1 * ray->dir.y; if ( (xi >= aabbCenter.x-aabbDim.x/2) && (xi <= aabbCenter.x+aabbDim.x/2) && (yi >= aabbCenter.y-aabbDim.y/2) && (yi <= aabbCenter.y+aabbDim.y/2) ) { *t = ray->dist2(&aabbCenter); return true; } } } // if (ray->dir.z != 0) /// pokud je kamera uvnitr aabb, tak kolize nastala if ( isIn(&ray->start) ){ *t = ray->far_clip*ray->far_clip; return true; } return false; } void TAABB::calculateMinsMaxs() { P3F dim2; CopyV3(dim2.p, aabbDim.p) MulV3(dim2.p, 0.5f); CopyV3(mins.p, aabbCenter.p); SubV3(mins.p, dim2.p); CopyV3(maxs.p, aabbCenter.p); AddV3(maxs.p, dim2.p); } void TAABB::drawAABB(){ float d = aabbDim.z/2; float w = aabbDim.x/2; float h = aabbDim.y/2; glBegin( GL_LINE_STRIP ); // glColor3f(1,1,1); glVertex3f( aabbCenter.x - w, aabbCenter.y + h, aabbCenter.z - d); glVertex3f( aabbCenter.x - w, aabbCenter.y + h, aabbCenter.z + d); glVertex3f( aabbCenter.x - w, aabbCenter.y - h, aabbCenter.z + d); glVertex3f( aabbCenter.x - w, aabbCenter.y - h, aabbCenter.z - d); glVertex3f( aabbCenter.x - w, aabbCenter.y + h, aabbCenter.z - d); glVertex3f( aabbCenter.x + w, aabbCenter.y + h, aabbCenter.z - d); glVertex3f( aabbCenter.x + w, aabbCenter.y + h, aabbCenter.z + d); glVertex3f( aabbCenter.x + w, aabbCenter.y - h, aabbCenter.z + d); glVertex3f( aabbCenter.x + w, aabbCenter.y - h, aabbCenter.z - d); glVertex3f( aabbCenter.x + w, aabbCenter.y + h, aabbCenter.z - d); glVertex3f( aabbCenter.x + w, aabbCenter.y + h, aabbCenter.z + d); glVertex3f( aabbCenter.x - w, aabbCenter.y + h, aabbCenter.z + d); glVertex3f( aabbCenter.x - w, aabbCenter.y - h, aabbCenter.z + d); glVertex3f( aabbCenter.x + w, aabbCenter.y - h, aabbCenter.z + d); glVertex3f( aabbCenter.x + w, aabbCenter.y - h, aabbCenter.z - d); glVertex3f( aabbCenter.x - w, aabbCenter.y - h, aabbCenter.z - d); glEnd(); } /*****************************************************************************/ TMesh* AddMeshToObject(T3DObject* o, int flags){ // o->mesh = (TMesh*)KExtArrayRealloc(o->mesh, sizeof(TMesh), o->mesh_c + 1, o->mesh_c); // o->mesh[o->mesh_c].obj = o; o->mesh[o->mesh_c].iFlag = flags; o->mesh[o->mesh_c].first = o->poly_c; o->mesh[o->mesh_c].last = o->poly_c; o->mesh[o->mesh_c].mat = NOMATERIAL; o->mesh[o->mesh_c].display_list = -1; // o->mesh_c ++; // return &(o->mesh[o->mesh_c-1]); } TVertex* AddVertexToObject(T3DObject* o, float x, float y, float z) { // o->vert = (TVertex*)KExtArrayRealloc(o->vert, sizeof(TVertex), o->vert_c + 1, o->vert_c); // o->vert[o->vert_c].position.x = x; o->vert[o->vert_c].position.y = y; o->vert[o->vert_c].position.z = z; // o->poly[o->poly_c - 1].last = o->vert_c; // o->vert_c ++; // return &(o->vert[o->vert_c-1]); } TPolygon* AddPolygonToObject(T3DObject* o, TMesh* m) { // o->poly = (TPolygon*)KExtArrayRealloc(o->poly, sizeof(TPolygon), o->poly_c + 1, o->poly_c); // o->poly[o->poly_c].submat = NOMATERIAL; o->poly[o->poly_c].lmap_id= 0; o->poly[o->poly_c].first = o->vert_c; o->poly[o->poly_c].last = o->vert_c; // o->poly[o->poly_c].udata = 0; // o->poly[o->poly_c].mesh = m; // o->mesh[o->mesh_c - 1].last = o->poly_c; // o->poly_c ++; // return &(o->poly[o->poly_c-1]); } void Destroy3DObject(T3DObject* obj){ for(int k = 0; k < obj->mesh_c; k++) { // if(obj->mesh[obj->mesh_c].display_list != -1) // glDeleteLists( obj->mesh[k].display_list, 1); } if(obj->mesh)KMemFree(obj->mesh); if(obj->poly)KMemFree(obj->poly); if(obj->vert)KMemFree(obj->vert); if(obj)KMemFree(obj); } int CollideMesh(TMesh* m,TRay* r,P3F* intersect,TPolygon** p){ TPolygon* polygon; T3DObject* o = m->obj; P3F *a, *b, *c; float x[3]; for(int i = m->first; i <= m->last; i++){ //kolize s itym polygonem polygon = o->poly + i; //trojuhelniky if((polygon->last - polygon->first) == 2){ a = &( o->vert[polygon->first].position ); b = &( o->vert[polygon->first+1].position ); c = &( o->vert[polygon->first+2].position ); P3F v1, v2, q0; SETV3(v1.p, b->x - a->x, b->y - a->y, b->z - a->z); SETV3(v2.p, c->x - a->x, c->y - a->y, c->z - a->z); CopyV3(q0.p, r->start.p); SubV3(q0.p, a->p); // Linear3x3Solve(v1.p, v2.p, r->dir.p, q0.p, x); if( (x[0]>=0) && (x[1]>=0) && (x[0] + x[1])<=1 ){ CopyV3(intersect->p, r->dir.p ); MulV3(intersect->p, -x[2]); AddV3(intersect->p, r->start.p); *p = polygon; return 1; } } else{ //nereseno } } return 0; } //extern void Clone(TMesh* src,TMesh* dest); //extern void Clone(T3DObject* src,T3DObject* dest); //extern T3DObject* Create3DObject(); //extern int Collide(T3DObject* o,TRay* r,P3F* intersect,TPolygon** p); //extern int CollideMesh(TMesh* m,TRay* r,P3F* intersect,TPolygon** p); }//namespace /*****************************************************************************/