radialobject.cpp
C++ source for Polychorons, 429 lines. Raw file
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#include "radialobject.h"
#include "interpolate.h"
#include "vector.h"
//---- ARGUMENTS
int radialObject_res = 27;
//---- getRadialObjectDistanceCube
// Returns the distances necessary for a cube
double getRadialObjectDistanceCube( double x, double y, double z, double time )
{
//- Calculate distance from each plane, nearest one wins
// double dist_x = x<=0.0001 ? 3 : sqrt( 1.0 + (y*y + z*z)/(x*x) ); // Distance from x = +/-1 plane
// double dist_y = y<=0.0001 ? 3 : sqrt( 1.0 + (x*x + z*z)/(y*y) );
// double dist_z = z<=0.0001 ? 3 : sqrt( 1.0 + (x*x + y*y)/(z*z) );
double dist_x = sqrt( 1.0 + (y*y + z*z)/(x*x) ); // Distance from x = +/-1 plane
double dist_y = sqrt( 1.0 + (x*x + z*z)/(y*y) );
double dist_z = sqrt( 1.0 + (x*x + y*y)/(z*z) );
if( dist_x < dist_y && dist_x < dist_z ) return dist_x; // x is smaller than both y and z
if( dist_y < dist_z ) return dist_y; // y is smaller than z
return dist_z; // must be z then
}
//---- getRadialObjectDistanceSphere
// Returns the distances necessary for a sphere given a directional vector
double getRadialObjectDistanceSphere( double x, double y, double z, double time )
{
return sqrt( x*x + y*y + z*z ); // Sphere is the size of the directional vector
}
//---- getRadialObjectDistanceTetra
double getRadialObjectDistanceTetra( double x, double y, double z, double time )
{
double nx, ny, nz;
double d1, d2, d3, d4;
nx = 0; ny = 2; nz = 0;
d1 = 1.0 / (nx*x + ny*y + nz*z );
if( d1 < 0 ) d1 = 9999;
// vector_rotate_z( &x, &y, &z, 0.33333333333333333333 );
// vector_rotate_z( &px, &py, &pz, 0.33333333333333333333 );
vector_rotate_z( &nx, &ny, &nz, 0.33333333333333333333 );
d2 = 1.0 / (nx*x + ny*y + nz*z );
if( d2 < 0 ) d2 = 9999;
vector_rotate_y( &x, &y, &z, 0.33333333333333333333 );
// vector_rotate_y( &px, &py, &pz, 0.33333333333333333333 );
// vector_rotate_y( &nx, &ny, &nz, 0.33333333333333333333 );
d3 = 1.0 / (nx*x + ny*y + nz*z );
if( d3 < 0 ) d3 = 9999;
vector_rotate_y( &x, &y, &z, 0.33333333333333333333 );
// vector_rotate_y( &px, &py, &pz, 0.33333333333333333333 );
// vector_rotate_y( &nx, &ny, &nz, 0.33333333333333333333 );
d4 = 1.0 / (nx*x + ny*y + nz*z );
if( d4 < 0 ) d4 = 9999;
if( d1 < d2 && d1 < d3 && d1 < d4 ) return d1;
if( d2 < d3 && d2 < d4 ) return d2;
if( d3 < d4 ) return d3;
return d4;
/*
if( d1 > d2 && d1 > d3 && d1 > d4 ) return d1 <= 0.001 ? 9999 : 1.0/d1;
if( d2 > d3 && d2 > d4 ) return d2 <= 0.001 ? 9999 : 1.0/d2;
if( d3 > d4 ) return d3 <= 0.001 ? 9999 : 1.0/d3;
return d4 <= 0.001 ? 9999 : 1.0/d4;
*/
}
//---- getRadialObjectDistanceTetraStar
double getRadialObjectDistanceTetraStar( double x, double y, double z, double time )
{
double d1 = getRadialObjectDistanceTetra( x, y, z, time );
double d2 = getRadialObjectDistanceTetra( -x, -y, -z, time );
/*
if( d1 > 2 ) d1 = 2;
if( d1 < -2 ) d1 = -2;
if( d2 > 2 ) d2 = 2;
if( d2 < -2 ) d2 = -2;
*/
return d1 > d2 ? d1*d1 : d2*d2;
}
//---- getRadialObjectDistanceBlob
// Returns the distances necessary for a sphere given a directional vector
double getRadialObjectDistanceBlob_baseMag = 1.2;
double getRadialObjectDistanceBlob_xMag = 0.15;
double getRadialObjectDistanceBlob_yMag = 0.20;
double getRadialObjectDistanceBlob_zMag = 0.23;
double getRadialObjectDistanceBlob_xWavelength = 3.3268;
double getRadialObjectDistanceBlob_yWavelength = 7.1212;
double getRadialObjectDistanceBlob_zWavelength = 10.7181;
double getRadialObjectDistanceBlob_xPhase = 0.2188;
double getRadialObjectDistanceBlob_yPhase = 0.3287;
double getRadialObjectDistanceBlob_zPhase = 0.1221;
double getRadialObjectDistanceBlob_xSpeed = 2.1311;
double getRadialObjectDistanceBlob_ySpeed = 3.2021;
double getRadialObjectDistanceBlob_zSpeed = 5.3211;
double getRadialObjectDistanceBlob( double x, double y, double z, double time )
{
return getRadialObjectDistanceBlob_baseMag +
getRadialObjectDistanceBlob_yMag * sin( x*getRadialObjectDistanceBlob_xWavelength + getRadialObjectDistanceBlob_xPhase + time * getRadialObjectDistanceBlob_xSpeed ) +
getRadialObjectDistanceBlob_yMag * sin( y*getRadialObjectDistanceBlob_yWavelength + getRadialObjectDistanceBlob_yPhase + time * getRadialObjectDistanceBlob_xSpeed ) +
getRadialObjectDistanceBlob_yMag * sin( z*getRadialObjectDistanceBlob_zWavelength + getRadialObjectDistanceBlob_zPhase + time * getRadialObjectDistanceBlob_xSpeed );
}
//---- getRadialObjectDistanceZNPill
// Returns the distances necessary for a ZN Pill logo shape
double getRadialObjectDistanceZNPill( double x, double y, double z, double time )
{
// works like a sphere but we subtract from x, y, z first which stretches the shape
double w = 5, h = 3, d = 1.5;
double ww = (w-1)*0.5;
double hh = (h-1)*0.5;
double dd = (d-1)*0.5;
if( x < -ww ) {x += ww;} else if( x < ww ) {x = 0;} else {x -= ww;}
if( y < -hh ) {y += hh;} else if( y < hh ) {y = 0;} else {y -= hh;}
if( z < -dd ) {z += dd;} else if( z < dd ) {z = 0;} else {z -= dd;}
// double d = getRadialObjectDistanceCube( x, y, z, time );
return sqrt( x*x + y*y + z*z ); // Sphere is the size of the directional vector
}
//---- getRadialObjectDistanceMultiple
double getRadialObjectDistanceMultiple( double x, double y, double z, double time, int ting )
{
switch( ting )
{
case 0:
return getRadialObjectDistanceCube( x, y, z, time );
case 1:
// return getRadialObjectDistanceZNPill( x, y, z, time );
case 2:
return getRadialObjectDistanceSphere( x, y, z, time );
}
return getRadialObjectDistanceBlob( x, y, z, time );
}
//---- getRadialObjectDistanceAlternating
// Given a direction vector and a time returns the distance from the origin
double getRadialObjectDistanceAlternating( double x, double y, double z, double time )
{
//- Depending on the time make it an interpolation of one of the shapes
double rate = /*sledgehammer*/2.791;//2.6728251515;//2.923; // changes <rate> times per second
double changetime = 0.75;//0.25 // Length of time it takes to change as a fraction of <rate>
int numshapes = 4; // Number of different shapes to flick between
int bit = ( (int)(time*rate) ); // changes by 1 <rate> times per second (integer phase)
double spare = time*rate - bit; // Fractional part of the phase
bit %= numshapes;
// bit = 0;
// spare = changetime*0.5 + 0.5*changetime*sin( time*0.239 );
// morphing, get two values and interpolate
if( spare < changetime )
{
double alpha = spare/changetime;
int prev = (bit+numshapes-1) % numshapes;
double d0 = getRadialObjectDistanceMultiple( x, y, z, time, prev );
double d1 = getRadialObjectDistanceMultiple( x, y, z, time, bit );
return interpolateSpringy( d0, d1, spare/changetime );
}
// one particular shape
else
{
return getRadialObjectDistanceMultiple( x, y, z, time, bit );
}
}
//---- drawCubicRadialObjectSide
// axis = 0 for x, 1 for y and 2 for z
// side = -1 for back and 1 for front
double drawCubicRadialObjectSide_x[ RADIALOBJECT_MAXRES+1 ][ RADIALOBJECT_MAXRES+1 ];
double drawCubicRadialObjectSide_y[ RADIALOBJECT_MAXRES+1 ][ RADIALOBJECT_MAXRES+1 ];
double drawCubicRadialObjectSide_z[ RADIALOBJECT_MAXRES+1 ][ RADIALOBJECT_MAXRES+1 ];
void drawCubicRadialObjectSide( int axis, int side, double time, GET_RADIALOBJECT_DISTANCE thing_fn )
{
int i, j;
//- Calculate points
switch( axis )
{
case 0:
for( j=0; j<=radialObject_res; j++ )
{
for( i=0; i<=radialObject_res; i++ )
{
// Point in plane
drawCubicRadialObjectSide_x[j][i] = side;
drawCubicRadialObjectSide_y[j][i] = side * 2.0 * ((i+0.0)/radialObject_res - 0.5);
drawCubicRadialObjectSide_z[j][i] = side * 2.0 * ((j+0.0)/radialObject_res - 0.5);
// Normalise
vector_normalise( &drawCubicRadialObjectSide_x[j][i], &drawCubicRadialObjectSide_y[j][i], &drawCubicRadialObjectSide_z[j][i] );
// Make shape
double d = thing_fn( drawCubicRadialObjectSide_x[j][i], drawCubicRadialObjectSide_y[j][i], drawCubicRadialObjectSide_z[j][i], time );
drawCubicRadialObjectSide_x[j][i] *= d;
drawCubicRadialObjectSide_y[j][i] *= d;
drawCubicRadialObjectSide_z[j][i] *= d;
}
}
break;
case 1:
for( j=0; j<=radialObject_res; j++ )
{
for( i=0; i<=radialObject_res; i++ )
{
// Point in plane
drawCubicRadialObjectSide_x[j][i] = side * 2.0 * ((i+0.0)/radialObject_res - 0.5);
drawCubicRadialObjectSide_y[j][i] = side;
drawCubicRadialObjectSide_z[j][i] = side * 2.0 * ((j+0.0)/radialObject_res - 0.5);
// Normalise
vector_normalise( &drawCubicRadialObjectSide_x[j][i], &drawCubicRadialObjectSide_y[j][i], &drawCubicRadialObjectSide_z[j][i] );
// Make shape
double d = thing_fn( drawCubicRadialObjectSide_x[j][i], drawCubicRadialObjectSide_y[j][i], drawCubicRadialObjectSide_z[j][i], time );
drawCubicRadialObjectSide_x[j][i] *= d;
drawCubicRadialObjectSide_y[j][i] *= d;
drawCubicRadialObjectSide_z[j][i] *= d;
}
}
break;
case 2:
for( j=0; j<=radialObject_res; j++ )
{
for( i=0; i<=radialObject_res; i++ )
{
// Point in plane
drawCubicRadialObjectSide_x[j][i] = side * 2.0 * ((i+0.0)/radialObject_res - 0.5);
drawCubicRadialObjectSide_y[j][i] = side * 2.0 * ((j+0.0)/radialObject_res - 0.5);
drawCubicRadialObjectSide_z[j][i] = side;
// Normalise
vector_normalise( &drawCubicRadialObjectSide_x[j][i], &drawCubicRadialObjectSide_y[j][i], &drawCubicRadialObjectSide_z[j][i] );
// Make shape
double d = thing_fn( drawCubicRadialObjectSide_x[j][i], drawCubicRadialObjectSide_y[j][i], drawCubicRadialObjectSide_z[j][i], time );
drawCubicRadialObjectSide_x[j][i] *= d;
drawCubicRadialObjectSide_y[j][i] *= d;
drawCubicRadialObjectSide_z[j][i] *= d;
}
}
break;
}
//- Draw the quads
// This can be made more efficient by keeping the distances calulated in the above for loops
double col;
for( j=0; j<radialObject_res; j++ )
{
for( i=0; i<radialObject_res; i++ )
{
glColor3f( (i+0.0)/radialObject_res, (j+0.0)/radialObject_res, 0 );
glBegin( GL_TRIANGLE_FAN );
col = vector_length(drawCubicRadialObjectSide_x[j][i],drawCubicRadialObjectSide_y[j][i],drawCubicRadialObjectSide_z[j][i]);
// glColor3f( col *= 0.5, col, col );
glColor3f( (0.25+0.25*drawCubicRadialObjectSide_x[j][i])*col, (0.25+0.25*drawCubicRadialObjectSide_y[j][i])*col, (0.25+0.25*drawCubicRadialObjectSide_z[j][i])*col );
glVertex3f( drawCubicRadialObjectSide_x[j ][i ], drawCubicRadialObjectSide_y[j ][i ], drawCubicRadialObjectSide_z[j ][i ] );
col = vector_length(drawCubicRadialObjectSide_x[j][i+1],drawCubicRadialObjectSide_y[j][i+1],drawCubicRadialObjectSide_z[j][i+1]);
// glColor3f( col *= 0.5, col, col );
glColor3f( (0.25+0.25*drawCubicRadialObjectSide_x[j][i+1])*col, (0.25+0.25*drawCubicRadialObjectSide_y[j][i+1])*col, (0.25+0.25*drawCubicRadialObjectSide_z[j][i+1])*col );
glVertex3f( drawCubicRadialObjectSide_x[j ][i+1], drawCubicRadialObjectSide_y[j ][i+1], drawCubicRadialObjectSide_z[j ][i+1] );
col = vector_length(drawCubicRadialObjectSide_x[j+1][i+1],drawCubicRadialObjectSide_y[j+1][i+1],drawCubicRadialObjectSide_z[j+1][i+1]);
// glColor3f( col *= 0.5, col, col );
glColor3f( (0.25+0.25*drawCubicRadialObjectSide_x[j+1][i+1])*col, (0.25+0.25*drawCubicRadialObjectSide_y[j+1][i+1])*col, (0.25+0.25*drawCubicRadialObjectSide_z[j+1][i+1])*col );
glVertex3f( drawCubicRadialObjectSide_x[j+1][i+1], drawCubicRadialObjectSide_y[j+1][i+1], drawCubicRadialObjectSide_z[j+1][i+1] );
col = vector_length(drawCubicRadialObjectSide_x[j+1][i],drawCubicRadialObjectSide_y[j+1][i],drawCubicRadialObjectSide_z[j+1][i]);
// glColor3f( col *= 0.5, col, col );
glColor3f( (0.25+0.25*drawCubicRadialObjectSide_x[j+1][i])*col, (0.25+0.25*drawCubicRadialObjectSide_y[j+1][i])*col, (0.25+0.25*drawCubicRadialObjectSide_z[j+1][i])*col );
glVertex3f( drawCubicRadialObjectSide_x[j+1][i ], drawCubicRadialObjectSide_y[j+1][i ], drawCubicRadialObjectSide_z[j+1][i ] );
glEnd();
}
}
}
//---- drawRadialObject
// Draws a radial object using a cubic scheme
void drawRadialObject( double time, GET_RADIALOBJECT_DISTANCE thing_fn )
{
//- Draw each side of a cube
drawCubicRadialObjectSide( 0, 1, time, thing_fn );
drawCubicRadialObjectSide( 0, -1, time, thing_fn );
drawCubicRadialObjectSide( 1, 1, time, thing_fn );
drawCubicRadialObjectSide( 1, -1, time, thing_fn );
drawCubicRadialObjectSide( 2, 1, time, thing_fn );
drawCubicRadialObjectSide( 2, -1, time, thing_fn );
}