336 lines
8.9 KiB
C++
Executable File
336 lines
8.9 KiB
C++
Executable File
//------------------------------------------------------------------------------
|
|
// 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 |