//------------------------------------------------------------------------------ // Vector Field Rendering Object //------------------------------------------------------------------------------ #include "dgl/gVectorField.h" #include "core/fileStream.h" #include "dgl/dgl.h" #include "math/mRect.h" #include "core/color.h" #include "core/frameAllocator.h" #include "util/safeDelete.h" #define NUM_VERTS mFieldResolution.x * mFieldResolution.y #define NUM_IDXS mFieldResolution.x * 2 #define NUM_STRIPS mFieldResolution.y - 1 #define INDEX(x, y) (x + y * mFieldResolution.x) #define VERT(x, y) mFieldVerts[INDEX(x,y)] //------------------------------------------------------------------------------ VectorField::VectorField() { nullField(); } //------------------------------------------------------------------------------ VectorField::VectorField( const Point2I &resolution, F32 maxX /* = 1.f */, F32 maxY /* = 1.f */, TextureCoordFlip flip /* = Flip_None */, VectorFieldInitFn initFn /* = NULL */ ) { nullField(); allocVectorField( resolution ); initVectorField( maxX, maxY, flip, initFn ); } //------------------------------------------------------------------------------ VectorField::VectorField( const char *fileName ) { nullField(); loadField( fileName ); } //------------------------------------------------------------------------------ VectorField::~VectorField() { destroyVectorField(); } //------------------------------------------------------------------------------ void VectorField::destroyVectorField() { SAFE_DELETE_ARRAY( mVectorField ); SAFE_DELETE_ARRAY( mFieldIndices ); SAFE_DELETE_ARRAY( mFieldVerts ); #ifdef ENABLE_FIELD_VISUALIZE SAFE_DELETE_ARRAY( mUnflippedVecField ); #endif } //------------------------------------------------------------------------------ void VectorField::allocVectorField( const Point2I &resolution ) { destroyVectorField(); mFieldResolution = resolution; mVectorField = new Point2F[NUM_VERTS]; // Create index buffer mFieldIndices = new U16[NUM_IDXS]; bool up = false; U32 x = 0, y = 0; // It would be way more efficent if we did one index buffer with degenerate // polys but you know what, I hate writing that stuff, and after 3 hours on a // friday night, I'm going with the easy way. for( int i = 0; i < NUM_IDXS; i++ ) { mFieldIndices[i] = INDEX(x, y); if( up ) { x++; y--; } else y++; up = !up; } #ifdef ENABLE_FIELD_VISUALIZE mUnflippedVecField = new Point2F[NUM_VERTS]; #endif } //------------------------------------------------------------------------------ void FN_CDECL defaultInitFn( const int x, const int y, const Point2I &resolution, const F32 maxX, const F32 maxY, Point2F *outVec ) { outVec->x = ( (F32)x / ( (F32)resolution.x - 1.f ) ) * maxX; outVec->y = ( (F32)y / ( (F32)resolution.y - 1.f ) ) * maxY; } void VectorField::initVectorField( F32 maxX /* = 1.f */, F32 maxY /* = 1.f */, TextureCoordFlip flip /* = Flip_None */, VectorFieldInitFn initFn /* = NULL */ ) { mMax.x = maxX; mMax.y = maxY; // Create the vertex buffer to render the field mFieldVerts = new Point2F[NUM_VERTS]; // Initialize all this stuff at once since we are working in the same space for( int x = 0; x < mFieldResolution.x; x++ ) { for( int y = 0; y < mFieldResolution.y; y++ ) { // Vertices defaultInitFn( x, y, mFieldResolution, maxX, maxY, &VERT(x, y) ); // Initialize the texture coordinates to their normal values defaultInitFn( x, y, mFieldResolution, maxX, maxY, &getVector( x, y ) ); // If provided, pass the normal values on to a custom function if( initFn != NULL ) (*initFn)( x, y, mFieldResolution, maxX, maxY, &getVector( x, y ) ); } } #ifdef ENABLE_FIELD_VISUALIZE dMemcpy( mUnflippedVecField, mVectorField, sizeof(Point2F) * NUM_VERTS ); #endif // Flip? if( flip != Flip_None ) { FrameAllocatorMarker marker; // Ben = teh win // Make this easy, create a copy of the coord array Point2F *fieldCopy = (Point2F *)marker.alloc( sizeof(Point2F) * NUM_VERTS ); dMemcpy( fieldCopy, mVectorField, sizeof(Point2F) * NUM_VERTS ); for( int i = 0; i < NUM_VERTS; i++ ) { if( flip & Flip_X ) mVectorField[i].x = fieldCopy[NUM_VERTS - i - 1].x; if( flip & Flip_Y ) mVectorField[i].y = fieldCopy[NUM_VERTS - i - 1].y; } } } //------------------------------------------------------------------------------ #define WRITEPOINT2X( p, s ) s->write( p.x ); s->write( p.y ); #define READPOINT2X( p, s ) s->read( &p.x ); s->read( &p.y ); void VectorField::serialize( Stream *stream ) const { WRITEPOINT2X( mFieldResolution, stream ); for( int x = 0; x < mFieldResolution.x; x++ ) { for( int y = 0; y < mFieldResolution.y; y++ ) { WRITEPOINT2X( getVector( x, y ), stream ); } } } //------------------------------------------------------------------------------ void VectorField::unserialize( Stream *stream ) { READPOINT2X( mFieldResolution, stream ); allocVectorField( mFieldResolution ); for( int x = 0; x < mFieldResolution.x; x++ ) { for( int y = 0; y < mFieldResolution.y; y++ ) { READPOINT2X( getVector( x, y ), stream ); } } } //------------------------------------------------------------------------------ bool VectorField::loadField( const char *fileName ) { FileStream fs; if( !fs.open( fileName, FileStream::Read ) ) return false; unserialize( &fs ); return true; } //------------------------------------------------------------------------------ bool VectorField::saveField( const char *fileName ) const { FileStream fs; if( !fs.open( fileName, FileStream::Write ) ) return false; serialize( &fs ); return true; } //------------------------------------------------------------------------------ void VectorField::renderField( bool texture /* = false */ ) const { glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); gluOrtho2D( 0.0, mMax.x, 0.0, mMax.y ); glMatrixMode( GL_MODELVIEW ); glPushMatrix(); glLoadIdentity(); glEnableClientState( GL_VERTEX_ARRAY ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); if( texture ) glEnableClientState( GL_TEXTURE_COORD_ARRAY ); glColor4f( 1.f, 1.f, 1.f, 1.f ); for( int i = 0; i < NUM_STRIPS; i++ ) { glTexCoordPointer( 2, GL_FLOAT, 0, &mVectorField[i * mFieldResolution.x] ); glVertexPointer( 2, GL_FLOAT, 0, &mFieldVerts[i * mFieldResolution.x] ); glDrawElements( GL_QUAD_STRIP, NUM_IDXS, GL_UNSIGNED_SHORT, mFieldIndices ); } if( texture ) glDisableClientState( GL_TEXTURE_COORD_ARRAY ); glDisableClientState( GL_VERTEX_ARRAY ); glDisable(GL_BLEND); glMatrixMode( GL_MODELVIEW ); glPopMatrix(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); } #ifdef ENABLE_FIELD_VISUALIZE void VectorField::visualizeField( F32 alpha /* = 1.0f */ ) const { glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); gluOrtho2D( 0.0, mMax.x, 0.0, mMax.y ); glMatrixMode( GL_MODELVIEW ); glPushMatrix(); glLoadIdentity(); glDisable( GL_TEXTURE_2D ); glEnable( GL_BLEND ); // Draw the field in wireframe, apparently it's a back facing poly...whatever GLint mode[2]; glGetIntegerv( GL_POLYGON_MODE, mode ); glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); glEnableClientState( GL_VERTEX_ARRAY ); glColor4f( 1.f, 1.f, 1.f, alpha ); for( int i = 0; i < NUM_STRIPS; i++ ) { glVertexPointer( 2, GL_FLOAT, 0, &mFieldVerts[i * mFieldResolution.x] ); glDrawElements( GL_QUAD_STRIP, NUM_IDXS, GL_UNSIGNED_SHORT, mFieldIndices ); } glDisableClientState( GL_VERTEX_ARRAY ); glPolygonMode( GL_FRONT, mode[0] ); glPolygonMode( GL_BACK, mode[1] ); // Draw the vectors glBegin( GL_LINES ); glColor4f( 0.f, 1.f, 0.f, 1.f ); for( int i = 0; i < NUM_VERTS; i++ ) { // Base point glVertex2fv( (F32 *)&mFieldVerts[i] ); glVertex2fv( (F32 *)&mUnflippedVecField[i]); } glEnd(); // Draw the verts glPointSize( 3.f ); glEnable( GL_POINT_SMOOTH ); glBegin( GL_POINTS ); glColor4f( 1.f, 0.f, 0.f, alpha ); for( int i = 0; i < NUM_VERTS; i++ ) glVertex2fv( (F32 *)&mFieldVerts[i] ); glEnd(); glDisable( GL_POINT_SMOOTH ); glPointSize( 1.f ); glDisable( GL_BLEND ); glMatrixMode( GL_MODELVIEW ); glPopMatrix(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); } #endif