Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Tree: 0f72ec239f
Fetching contributors…

Cannot retrieve contributors at this time

348 lines (267 sloc) 8.124 kB
#include "stage.hh"
#include "worldfile.hh"
#include <libgen.h> // for dirname(3)
#include <limits.h> // for _POSIX_PATH_MAX
#undef DEBUG
using namespace Stg;
using namespace std;
BlockGroup::BlockGroup( Model& mod )
: blocks(),
displaylist(0),
mod(mod)
{ /* empty */ }
BlockGroup::~BlockGroup()
{
Clear();
}
void BlockGroup::AppendBlock( const Block& block )
{
blocks.push_back( block );
}
void BlockGroup::Clear()
{
//FOR_EACH( it, blocks )
// delete *it;
blocks.clear();
}
void BlockGroup::AppendTouchingModels( std::set<Model*>& v )
{
FOR_EACH( it, blocks )
it->AppendTouchingModels( v );
}
Model* BlockGroup::TestCollision()
{
Model* hitmod = NULL;
FOR_EACH( it, blocks )
if( (hitmod = it->TestCollision()))
break; // bail on the earliest collision
return hitmod; // NULL if no collision
}
/** find the 3d bounding box of all the blocks in the group */
bounds3d_t BlockGroup::BoundingBox() const
{
// assuming the blocks currently fit in a square +/- one billion units
double minx, miny, maxx, maxy, minz, maxz;
minx = miny = minz = billion;
maxx = maxy = maxz = -billion;
FOR_EACH( it, blocks )
{
// examine all the points in the polygon
FOR_EACH( pit, it->pts )
{
if( pit->x < minx ) minx = pit->x;
if( pit->y < miny ) miny = pit->y;
if( pit->x > maxx ) maxx = pit->x;
if( pit->y > maxy ) maxy = pit->y;
}
if( it->local_z.min < minz ) minz = it->local_z.min;
if( it->local_z.max > maxz ) maxz = it->local_z.max;
}
return bounds3d_t( Bounds( minx,maxx), Bounds(miny,maxy), Bounds(minz,maxz));
}
// scale all blocks to fit into the bounding box of this group's model
void BlockGroup::CalcSize()
{
const bounds3d_t b = BoundingBox();
const Size size( b.x.max - b.x.min,
b.y.max - b.y.min,
b.z.max - b.z.min );
const Size offset( b.x.min + size.x/2.0, b.y.min + size.y/2.0, 0 );
// now scale the blocks to fit in the model's 3d bounding box, so
// that the original points are now in model coordinates
const Size modsize = mod.geom.size;
FOR_EACH( it, blocks )
{
// polygon edges
FOR_EACH( pit, it->pts )
{
pit->x = (pit->x - offset.x) * (modsize.x/size.x);
pit->y = (pit->y - offset.y) * (modsize.y/size.y);
}
// vertical bounds
it->local_z.min = (it->local_z.min - offset.z) * (modsize.z/size.z);
it->local_z.max = (it->local_z.max - offset.z) * (modsize.z/size.z);
}
}
void BlockGroup::Map( unsigned int layer )
{
FOR_EACH( it, blocks )
it->Map(layer);
}
void BlockGroup::UnMap( unsigned int layer )
{
FOR_EACH( it, blocks )
it->UnMap(layer);
}
void BlockGroup::DrawSolid( const Geom & geom )
{
glPushMatrix();
Gl::pose_shift( geom.pose );
FOR_EACH( it, blocks )
it->DrawSolid(false);
glPopMatrix();
}
void BlockGroup::DrawFootPrint( const Geom & geom )
{
FOR_EACH( it, blocks )
it->DrawFootPrint();
}
// tesselation callbacks used in BlockGroup::BuildDisplayListTess()------------
static void errorCallback(GLenum errorCode)
{
const GLubyte *estring;
estring = gluErrorString(errorCode);
fprintf (stderr, "Tessellation Error: %s\n", estring);
exit (0);
}
static void combineCallback(GLdouble coords[3],
GLdouble *vertex_data[4],
GLfloat weight[4],
GLdouble **new_vertex )
{
*new_vertex = new GLdouble[3];
memcpy( *new_vertex, coords, 3*sizeof(GLdouble));
// @todo: fix the leak of this vertex buffer. it's not a lot of
// data, and doesn't happen much, but it would be tidy.
}
// render each block as a polygon extruded into Z
void BlockGroup::BuildDisplayList()
{
static GLUtesselator *tobj = NULL;
if( ! mod.world->IsGUI() )
return;
if( displaylist == 0 )
{
CalcSize(); // todo: is this redundant? count calls per model to figure this out.
displaylist = glGenLists(1);
assert(displaylist !=0 );
// Stage polygons need not be convex, so we have to tesselate them for rendering in OpenGL.
tobj = gluNewTess();
assert(tobj != NULL);
// these use the standard GL calls
gluTessCallback(tobj, GLU_TESS_VERTEX,
(GLvoid (*) ()) &glVertex3dv);
gluTessCallback(tobj, GLU_TESS_EDGE_FLAG,
(GLvoid (*) ()) &glEdgeFlag);
gluTessCallback(tobj, GLU_TESS_BEGIN,
(GLvoid (*) ()) &glBegin);
gluTessCallback(tobj, GLU_TESS_END,
(GLvoid (*) ()) &glEnd);
// these are custom, defined above.
gluTessCallback(tobj, GLU_TESS_ERROR,
(GLvoid (*) ()) &errorCallback);
gluTessCallback(tobj, GLU_TESS_COMBINE,
(GLvoid (*) ()) &combineCallback);
}
std::vector<std::vector<GLdouble> > contours;
FOR_EACH( blk, blocks )
{
std::vector<GLdouble> verts;
FOR_EACH( it, blk->pts )
{
verts.push_back( it->x );
verts.push_back( it->y );
verts.push_back( blk->local_z.max );
}
contours.push_back( verts );
}
glNewList( displaylist, GL_COMPILE );
Gl::pose_shift( mod.GetGeom().pose );
// draw filled polys
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(0.5, 0.5);
mod.PushColor( mod.color );
gluTessBeginPolygon(tobj, NULL);
FOR_EACH( contour, contours )
{
gluTessBeginContour(tobj);
for( size_t v=0; v<contour->size(); v+=3 )
gluTessVertex(tobj, &(*contour)[v], &(*contour)[v]);
gluTessEndContour(tobj);
}
gluTessEndPolygon(tobj);
FOR_EACH( blk, blocks )
blk->DrawSides();
mod.PopColor();
// now outline the polys
glDisable(GL_POLYGON_OFFSET_FILL);
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glDepthMask(GL_FALSE);
Color c = mod.color;
c.r /= 2.0;
c.g /= 2.0;
c.b /= 2.0;
mod.PushColor( c );
gluTessBeginPolygon(tobj, NULL);
FOR_EACH( contour, contours )
{
gluTessBeginContour(tobj);
for( size_t v=0; v<contour->size(); v+=3 )
gluTessVertex(tobj, &(*contour)[v], &(*contour)[v]);
gluTessEndContour(tobj);
}
gluTessEndPolygon(tobj);
FOR_EACH( blk, blocks )
blk->DrawSides();
glDepthMask(GL_TRUE);
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
mod.PopColor();
glEndList();
}
void BlockGroup::CallDisplayList()
{
if( displaylist == 0 || mod.rebuild_displaylist )
{
BuildDisplayList();
mod.rebuild_displaylist = 0;
}
glCallList( displaylist );
}
void BlockGroup::LoadBlock( Worldfile* wf, int entity )
{
AppendBlock( Block( this, wf, entity ));
//CalcSize(); // adjust the blocks so they fit in our bounding box
}
void BlockGroup::LoadBitmap( const std::string& bitmapfile, Worldfile* wf )
{
PRINT_DEBUG1( "attempting to load bitmap \"%s\n", bitmapfile );
std::string full;
if( bitmapfile[0] == '/' )
full = bitmapfile;
else
{
char* workaround_const = strdup(wf->filename.c_str());
full = std::string(dirname(workaround_const)) + "/" + bitmapfile;
free( workaround_const );
}
char buf[512];
snprintf( buf, 512, "[Image \"%s\"", bitmapfile.c_str() );
fputs( buf, stdout );
fflush( stdout );
PRINT_DEBUG1( "attempting to load image %s", full );
Color col( 1.0, 0.0, 1.0, 1.0 );
std::vector<std::vector<point_t> > polys;
if( polys_from_image_file( full,
polys ) )
{
PRINT_ERR1( "failed to load polys from image file \"%s\"",
full.c_str() );
return;
}
FOR_EACH( it, polys )
AppendBlock( Block( this,
*it,
Bounds(0,1) ));
CalcSize();
fputs( "]", stdout );
}
void BlockGroup::Rasterize( uint8_t* data,
unsigned int width,
unsigned int height,
meters_t cellwidth,
meters_t cellheight )
{
FOR_EACH( it, blocks )
it->Rasterize( data, width, height, cellwidth, cellheight );
}
Jump to Line
Something went wrong with that request. Please try again.