/// LSU EE X70X GPU Prog / Microarch -*- c++ -*- // /// Quick and dirty code for ball / rectangle physics. pVect vec_pos(pVect v) { return pVect(max(v.x,0.0f),max(v.y,0.0f),max(v.z,0.0f)); } pVect vec_neg(pVect v) { return pVect(min(v.x,0.0f),min(v.y,0.0f),min(v.z,0.0f)); } struct Bounding_Box { Bounding_Box(){ initialized = false; } Bounding_Box operator = (Bounding_Box b) { initialized = true; ll = b.ll; ur = b.ur; return *this; } Bounding_Box operator += (Bounding_Box b) { if ( !initialized ) return operator = (b); set_min(ll.x,b.ll.x); set_min(ll.y,b.ll.y); set_min(ll.z,b.ll.z); set_max(ur.x,b.ur.x); set_max(ur.y,b.ur.y); set_max(ur.z,b.ur.z); return *this; } bool initialized; pCoor ll, ur; }; class Tile : public Phys { public: Tile(bool &cuda_stale, pCoor ll, pVect ay, pVect ax) :Phys(PT_Tile),cuda_stale(cuda_stale),marker(NULL) { read_only = true; set(ll,ay,ax); } ~Tile(){ }; void set(pCoor ll, pVect ayp, pVect axp) { ay = ayp; ax = axp; pt_00 = ll; nz.set(cross(ax,ay)); nx.set(ax); lx = nx.magnitude; ny.set(ay); ly = ny.magnitude; cuda_stale = true; bb.ll = pt_00 + vec_neg(ay) + vec_neg(ax); bb.ur = pt_00 + vec_pos(ay) + vec_pos(ax); m_to_local = pMatrix_Rows(nx,ny,nz) * pMatrix_Translate(-ll); } float max_z_get(double delta_t){ return bb.ur.z; } float min_z_get(double delta_t){ return bb.ll.z; } Bounding_Box bounding_box_get(){return bb;} bool& cuda_stale; // Transformation to local coordinate space. pMatrix m_to_local; // Length of tile along local x and y axes. float lx, ly; pCoor pt_00; // Global coordinate corresponding to local coord (0,0,0). // Local space axes. pVect ay, ax; pNorm nx, ny, nz; Bounding_Box bb; pColor color; void *marker; Ball *ball_tested; }; class Tile_Manager { public: Tile_Manager(){ phys_list = NULL; cuda_stale = true; }; void init(Phys_List *pl){ phys_list = pl; } void clear(){ tiles.clear(); } void render(bool simple = false); void render_simple(); void render_shadow_volume(pCoor light_pos); Tile* new_tile(pCoor ll, pVect ay, pVect ax, pColor color); Tile* new_tile(pCoor ll, pVect ay, pVect ax); int occ() { return tiles.size(); } private: World* w; vector<Tile*> tiles; Phys_List *phys_list; bool cuda_stale; }; Tile* Tile_Manager::new_tile(pCoor ll, pVect ay, pVect ax, pColor color) { Tile* const rv = new_tile(ll,ay,ax); rv->color = color; return rv; } Tile* Tile_Manager::new_tile(pCoor ll, pVect ay, pVect ax) { Tile* const rv = new Tile(cuda_stale,ll,ay,ax); tiles.push_back( rv ); rv->idx = phys_list->size(); phys_list->push_back(rv); return rv; } void Tile_Manager::render(bool simple) { glBegin(GL_TRIANGLES); for ( Tile* tile: tiles ) { if ( !simple ) { glColor3fv(tile->color); glNormal3fv(tile->nz); } glVertex3fv(tile->pt_00 + tile->ay); glVertex3fv(tile->pt_00); glVertex3fv(tile->pt_00 + tile->ax); glVertex3fv(tile->pt_00 + tile->ax); glVertex3fv(tile->pt_00+tile->ax+tile->ay); glVertex3fv(tile->pt_00 + tile->ay); } glEnd(); } void Tile_Manager::render_simple(){ render(true); } void Tile_Manager::render_shadow_volume(pCoor light_pos) { const float height = 1000; for ( Tile* tile: tiles ) { pCoor pt_11 = tile->pt_00+tile->ax+tile->ay; pCoor pt_10 = tile->pt_00+tile->ax; pCoor pt_01 = tile->pt_00+tile->ay; pNorm l_to_01(light_pos,pt_01); pCoor pt_01_2 = light_pos + height * l_to_01; pCoor pt_00_2 = light_pos + height * pNorm(light_pos,tile->pt_00); pCoor pt_10_2 = light_pos + height * pNorm(light_pos,pt_10); pCoor pt_11_2 = light_pos + height * pNorm(light_pos,pt_11); const bool facing_light = dot(tile->nz,l_to_01) < 0; if ( facing_light ) glFrontFace(GL_CW); else glFrontFace(GL_CCW); glBegin(GL_TRIANGLE_STRIP); glVertex3fv(tile->pt_00); glVertex3fv(pt_00_2); glVertex3fv(pt_10); glVertex3fv(pt_10_2); glVertex3fv(pt_11); glVertex3fv(pt_11_2); glVertex3fv(pt_01); glVertex3fv(pt_01_2); glVertex3fv(tile->pt_00); glVertex3fv(pt_00_2); glEnd(); } glFrontFace(GL_CCW); } bool tile_sphere_intersect (Tile *tile, pCoor ball_pos, float radius, pCoor& tact_pos, pNorm& tact_dir, bool dont_compute_tact = false) { // Transform sphere position to tile's local coordinate space. // pCoor ball_loc = tile->m_to_local * ball_pos; // Distance from tile's plane to the ball. const float dist = ball_loc.z; if ( fabs(dist) > radius ) return false; // Get local y coordinate of ball and return if it's too far to touch. // const float loc_y = ball_loc.y; if ( loc_y < -radius ) return false; if ( loc_y > tile->ly + radius ) return false; // Get local x coordinate of ball and return if it's too far to touch. // const float loc_x = ball_loc.x; if ( loc_x < -radius ) return false; if ( loc_x > tile->lx + radius ) return false; // The return value here should be maybe, but true is good enough // for preparing a proximity list. if ( dont_compute_tact ) return true; // Find closest ball local x and y coordinates that are within tile. // const float loc_xc = clamp(loc_x, 0, tile->lx); const float loc_yc = clamp(loc_y, 0, tile->ly); // If ball local coordinates are within tile then pseudo ball is // on opposite side of tile. // if ( loc_x == loc_xc && loc_y == loc_yc ) { tact_pos = ball_pos - dist * tile->nz; tact_dir = dist > 0 ? -tile->nz : tile->nz; return true; } // Otherwise, ball is touching an edge or corner. tact_pos = tile->pt_00 + loc_xc * tile->nx + loc_yc * tile->ny; tact_dir = pVect(ball_pos,tact_pos); return tact_dir.mag_sq < radius * radius; } bool tile_sphere_intersect (Tile *tile, pCoor ball_pos, float radius) { pCoor dummyc; pNorm dummyn; return tile_sphere_intersect(tile,ball_pos,radius,dummyc,dummyn,true); }