tge/engine/dgl/gVectorField.cc
2025-02-17 23:17:30 -06:00

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