See what's going on with flipcode!




This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Simple Untrained Neural Net Class
  Submitted by



I've been unable to leave neural nets alone ever since i saw fups tutorial*. I dont really know why, maybe its one of the few chances i get to combine my degree (genetics) with my passion (coding). This cotd came about when i got some pretty animated patterns, using untrained neural nets to render colored heightmaps (using tristrips in OpenGL) and decided to share it. The neural net class will become a library (for my own/other peoples non-com use), so i am interested in comments on the class design, more so perhaps than the implementation. But please bare in mind that this is a work in progress by a hobby coder :) One unusual aspect of the neural nets currently created by this class is the function they use sin as the response function instead of the usual sigmoidal response (fup explains sigmoidal response and its usage in his tut).

float Neuron::Calc(float *inputs)
{
	float out = 0;

//add up all (weight * input) pairs for (int x=0;x<num_inputs;x++) out += weights[x] * inputs[x];

//sigmoid reponse curve (broken) //return ( 1 / (sig_response + (float)exp( - (out / 10) )) ); //sinus response curve return sinf( out / sig_response); }



I think it is this sinus reposonse that gives these neural nets the properties that make them graph pretty patterns. I am hoping to test some net controlled AI (simple navigation) to make sure that the sinus response is appropriate for other uses than silly patterns. Feel free to try out the sigmoidal response, but i havent managed to get it to produce usefull results yet (the net doesn't generate enough varied output using sigmoidal output) The code is a VC5(yuk) workspace containing 3 demo projects of how to use the class. It requires glut libraries and headers which are not included. The source code is released under GNU, so dont be afraid. Comments welcome, Matt Barnett
gunther@dial.pipex.com Refs: * Neural Networks in plain english (by fup)
http://www.btinternet.com/~fup/nnt1.html

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/myerror.h] - (1,719 bytes)

/*=======================================

cMyError::Header File By Matt Barnett;

Description: Simple error reporting.

Usage:

cMyError cMyError1;

//quiet error printf() cMyError1.Error("vertex number %i is %s",vertex,stringproblem);

//message box and printf() //same as FatalError(); except it doesnt look so intimidating cMyError1.AlertError("feature not supported %s",stringfeature);

//call this to report a fatal error //just before you exit(-1); cMyError1.FatalError("Couldnt find file %s",stringlostfile); exit(-1);

=======================================*/


#ifndef _MYERROR_CLASS_H #define _MYERROR_CLASS_H

#include <windows.h> //comment for non Win32 platforms

#include <cstdio> //for printf //#define VERBOSE_CREATION //class debug

class cMyError { public: cMyError(); //constructor ~cMyError(); //destructon void FatalError(const char *strString, ...); //MessageBox and printf() void AlertError(const char *strString, ...); //exactly the same as FatalError (except title) void Error(const char *strString, ...); //printf() void Alert(const char *strString, ...); void Log(const char *strString, ...);

static void isFlowHere(const char *filename, int linenumber) { printf("Program flow reached %s %i\n",filename,linenumber); }

//static bool logall; };

//macros are shouted and they use a ; so the usage is ... // // CMYERROR_ISFLOWHERE // and not CMYERROR_ISFLOWHERE; // //which helps make it clear that its a macro we're calling // #define CMYERROR_ISFLOWHERE cMyError::isFlowHere(__FILE__,__LINE__);

#endif

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/myerror.cpp] - (5,097 bytes)

/*=======================================

cMyError::Implementation

*See header file for more information By Matt Barnett;

=======================================*/


#include "myerror.h" #include "leakdetect.h"

/*======================================= cMyError::Constructor =======================================*/

cMyError::cMyError() { #ifdef VERBOSE_CREATION printf("cMyError::Constructor::Empty\n"); #endif }

/*======================================= cMyError::Destructor =======================================*/

cMyError::~cMyError() {

#ifdef VERBOSE_CREATION printf("cMyError::Destructor::Empty\n"); #endif

}

/*========================================================= void cMyError::FatalError() ==========================================================*/

void cMyError::FatalError(const char *strString, ...) { char strText[256]; // This will hold our text to display va_list argumentPtr; // This will hold the pointer to the argument list float unitLength=0.0f; // This will store the length of the 3D Font in unit length if (strString == NULL) // Check if a string was given return; // Don't render anything then va_start(argumentPtr, strString); // Parse the arguments out of the string vsprintf(strText, strString, argumentPtr); // Now add the arguments into the full string va_end(argumentPtr); // This resets and frees the pointer to the argument list. MessageBox(NULL,strText,"Fatal Error!!!",MB_OK|MB_ICONSTOP); printf("FATAL ERROR: %s\n",strText); }

/*========================================================= void cMyError::AlertError() ==========================================================*/

void cMyError::AlertError(const char *strString, ...) { char strText[256]; // This will hold our text to display va_list argumentPtr; // This will hold the pointer to the argument list float unitLength=0.0f; // This will store the length of the 3D Font in unit length if (strString == NULL) // Check if a string was given return; // Don't render anything then va_start(argumentPtr, strString); // Parse the arguments out of the string vsprintf(strText, strString, argumentPtr); // Now add the arguments into the full string va_end(argumentPtr); // This resets and frees the pointer to the argument list. MessageBox(NULL,strText,"Non fatal error!",MB_OK|MB_ICONEXCLAMATION); printf("ERROR(loud): %s\n",strText); }

/*========================================================= void cMyError::Error() ==========================================================*/

void cMyError::Error(const char *strString, ...) { char strText[256]; // This will hold our text to display va_list argumentPtr; // This will hold the pointer to the argument list float unitLength=0.0f; // This will store the length of the 3D Font in unit length if (strString == NULL) // Check if a string was given return; // Don't render anything then va_start(argumentPtr, strString); // Parse the arguments out of the string vsprintf(strText, strString, argumentPtr); // Now add the arguments into the full string va_end(argumentPtr); // This resets and frees the pointer to the argument list. printf("ERROR(quiet): %s\n",strText); }

/*========================================================= void cMyError::Alert() ==========================================================*/

void cMyError::Alert(const char *strString, ...) { char strText[256]; // This will hold our text to display va_list argumentPtr; // This will hold the pointer to the argument list float unitLength=0.0f; // This will store the length of the 3D Font in unit length if (strString == NULL) // Check if a string was given return; // Don't render anything then va_start(argumentPtr, strString); // Parse the arguments out of the string vsprintf(strText, strString, argumentPtr); // Now add the arguments into the full string va_end(argumentPtr); // This resets and frees the pointer to the argument list. MessageBox(NULL,strText,"Information",MB_OK); printf("Alert(loud): %s\n",strText); } /*========================================================= void cMyError::Log() ==========================================================*/

void cMyError::Log(const char *strString, ...) { char strText[256]; // This will hold our text to display va_list argumentPtr; // This will hold the pointer to the argument list float unitLength=0.0f; // This will store the length of the 3D Font in unit length if (strString == NULL) // Check if a string was given return; // Don't render anything then va_start(argumentPtr, strString); // Parse the arguments out of the string vsprintf(strText, strString, argumentPtr); // Now add the arguments into the full string va_end(argumentPtr); // This resets and frees the pointer to the argument list. printf("Log: %s\n",strText); }

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/leakdetect.h] - (1,200 bytes)

/*=======================================

Memory leak detection header file

=======================================*/


//#define LEAKDBG #ifdef LEAKDBG #define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> #endif

#ifdef LEAKDBG #define meMalloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) #define meCalloc(c, s) _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__) #define meRealloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) #define meExpand(p, s) _expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) #define meFree(p) _free_dbg(p, _NORMAL_BLOCK) #define meMemSize(p) _msize_dbg(p, _NORMAL_BLOCK)

#define meNew new(_NORMAL_BLOCK, __FILE__, __LINE__) #define meDelete delete

// Set to dump leaks at the program exit. #define meInitMemoryCheck() \ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF)

#else #define meMalloc malloc #define meCalloc calloc #define meRealloc realloc #define meExpand _expand #define meFree free #define meMemSize _msize

#define meNew new #define meDelete delete

#define meInitMemoryCheck()

#endif

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/demos/matnn/testapp1/glut_test1.cpp] - (6,062 bytes)


/*---------------------------------------------
		
	MatNN library : Test App 1 (cpp)

* This is not an terrain poly pushing demo.

This shows a silly brainwave of the neural net. The nets are totally untrained (random weights).

The neural net (in this example) has 3 input neurons that take the x / y position of a 2d grid and the time/ticks returned by GetTickCount(); It has 3 outputs = RGB color which is also used as a height. We/me/i graph the response of the the net over a small 2d plane of x/y values, at a specific time (using GetTickCount() ) to create a pretty swirly jaggy heightmap thingy (tm)

keys : r = random neural net a = decrease response d = increase response

By Matt Barnett

(see References) * See matnn.h for more information ---------------------------------------------*/


//basic glut and math stuff for camera etc #include <ctime> #include <cstdio> #include <windows.h> #include <GL/glut.h>

#include "../../../imath/imath.h" #include "../../../matnn/matnn.h"

GLfloat grey[] = {0.2,0.2,0.2,1.0}; GLfloat above_origin[] = {0.0,0.0,3.0,1.0}; GLfloat white[] = {1.0,1.0,1.0,1.0}; GLfloat shiny[] = {50.0};

#define WINDOW_SIZE 1024 // #define SCALE_MOTION 100 //scale down by int x,y,mx,my,xs,ys;

int oldmx = 0; int oldmy = 0;

enum modetype { MODE_ROTATE,MODE_MOVE,MODE_CAM }; modetype mode; iquaternion4 camquat;

//globals for testing here using MatLayeredNeuralNetLib::NeuralNet; float resp = 0.45f; float inputs[3]; float outputs[3];

//change the number of hidden layers //(number of inputs, number of outputs, number of neurons in hidden layers, number of hidden layers) NeuralNet n1(3,3,4,3,inputs,outputs);

//------------------------ void drawaxes() { glDisable(GL_LIGHTING);

glBegin(GL_LINES); glColor3f(1.0,0.0,0.0);glVertex3f(-0.5,0.0,0.0);glVertex3f(1.2,0.0,0.0); glColor3f(0.0,1.0,0.0);glVertex3f(0.0,-0.5,0.0);glVertex3f(0.0,1.2,0.0); glColor3f(0.0,0.0,1.0);glVertex3f(0.0,0.0,-0.5);glVertex3f(0.0,0.0,1.2); glEnd(); }

void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity();

imatrix16 rm(camquat); glTranslatef(0.0,0.0,-0.8); glMultMatrixf(rm.m); //instert drawing here float floorsize = 1.5;

//if you want more tri-strips then decrease this value float floorstep = 0.025f;

float i,j;

float fftime = (float)GetTickCount() / 1500;

glPushMatrix(); glTranslatef((float)-floorsize/2,(float)-floorsize/2,0.0);

for (i=0;i<floorsize;i+=floorstep) { glBegin(GL_TRIANGLE_STRIP); for (j=0;j<floorsize;j+=floorstep) { inputs[0] = j; inputs[1] = i; inputs[2] = fftime; n1.RunNN();

glColor3f(outputs[0],outputs[1],outputs[2]); //rem this out and try one of the below //glVertex3f(i,j,outputs[2] / 9.0 ) //glVertex3f(i,j,0.0f); glVertex3f(i,j,(outputs[0]+outputs[1]+outputs[2]) / 35.0f);

inputs[0] = j+floorstep; inputs[1] = i+floorstep; inputs[2] = fftime; n1.RunNN();

glColor3f(outputs[0],outputs[1],outputs[2]); //rem this out and try one of the below (chose the same as above) //glVertex3f(i+floorstep,j+floorstep,outputs[2] / 9.0 ); //glVertex3f(i+floorstep,j+floorstep,0.0f); glVertex3f(i+floorstep,j+floorstep,(outputs[0]+outputs[1]+outputs[2]) / 35.0f);

} glEnd(); }

drawaxes(); glPopMatrix();

glPopMatrix(); glutSwapBuffers(); glutPostRedisplay(); }



void reshape(int w, int h) { glViewport(0,0,(GLsizei) w,(GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(90,(float)w/h,0.01,100.0); }



void motion(int x, int y) { mx = x;my = y;

xs = mx - oldmx; ys = oldmy - my;

oldmx = mx; oldmy = my;

iquaternion4 multquat;

if (mode == MODE_ROTATE) { } else if (mode == MODE_MOVE) {

} else if (mode == MODE_CAM) { multquat.makeEulerRotation( ivector3( (float)ys/SCALE_MOTION,-(float)xs/SCALE_MOTION,0.0 ) ); camquat.multiply(multquat); } }

void mouse(int button,int state,int x,int y) { oldmx = x; oldmy = y;

if (button == GLUT_LEFT_BUTTON) mode = MODE_ROTATE;

if (button == GLUT_RIGHT_BUTTON) mode = MODE_MOVE;

if (button == GLUT_MIDDLE_BUTTON) mode = MODE_CAM; }

void init(void) {

srand( (unsigned)time( NULL ) );

glEnable(GL_DEPTH_TEST); //glEnable(GL_LIGHTING); //glEnable(GL_LIGHT0); //glLightfv(GL_LIGHT0,GL_POSITION,above_origin); //glEnable(GL_BLEND); //glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); //glMaterialfv(GL_FRONT,GL_DIFFUSE,grey); //glMaterialfv(GL_FRONT,GL_SPECULAR,white); //glMaterialfv(GL_FRONT,GL_SHININESS,shiny); //glEnable(GL_POLYGON_OFFSET_FILL); //glPolygonOffset(0.1,0.1); //glDepthFunc(GL_LEQUAL); //glEnable(GL_DEPTH_TEST); //glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); //glEnable(GL_BLEND); //glEnable(GL_POLYGON_SMOOTH); //glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); glPointSize(2.0f);

inputs[0] = 0; inputs[1] = 0;

n1.SetResponse(resp); }

void key(GLubyte key, int x, int y) { switch (key) { case 'a':resp -= 0.05f;printf("response %f\n",resp);n1.SetResponse(resp); break;

case 'd':resp += 0.05f;printf("response %f\n",resp);n1.SetResponse(resp); break;

case 'r':im_random_seed_time();n1.Randomize();

break;

case '1':

break;

case '!':

break;

case 'l':

break;

case 'q':exit(0); break; } }

int main(int argc, char **argv) {

meInitMemoryCheck(); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(WINDOW_SIZE,WINDOW_SIZE); glutInitWindowPosition(100,10); glutCreateWindow("Matts test");

glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(key); glutMotionFunc(motion); glutMouseFunc(mouse);

init(); glutMainLoop();

return 0; }

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/demos/matnn/testapp1/glut_test2.cpp] - (5,270 bytes)


/*---------------------------------------------
		
	MatNN library : Test App 2 (cpp)

This one uses a neural net to control the position and color of some opengl points (large pointsize).

I guess this could be used to control a bunch of blended particles in an interesting way.

keys : r = random neural net a = decrease response d = increase response

By Matt Barnett

(see References) * See matnn.h for more information ---------------------------------------------*/


//basic glut and math stuff for camera etc #include <ctime> #include <cstdio> #include <windows.h> #include <GL/glut.h>

#include "../../../imath/imath.h" #include "../../../matnn/matnn.h"

GLfloat grey[] = {0.2,0.2,0.2,1.0}; GLfloat above_origin[] = {0.0,0.0,3.0,1.0}; GLfloat white[] = {1.0,1.0,1.0,1.0}; GLfloat shiny[] = {50.0};

#define WINDOW_SIZE 1024 // #define SCALE_MOTION 100 //scale down by int x,y,mx,my,xs,ys; int oldmx = 0; int oldmy = 0;

enum modetype { MODE_ROTATE,MODE_MOVE,MODE_CAM }; modetype mode; iquaternion4 camquat;

//globals for testing here using MatLayeredNeuralNetLib::NeuralNet; float resp = 1.0f; float inputs[6]; float outputs[6]; NeuralNet n1(6,6,6,2,inputs,outputs);

//------------------------ void drawaxes() { glDisable(GL_LIGHTING);

glBegin(GL_LINES); glColor3f(1.0,0.0,0.0);glVertex3f(-0.5,0.0,0.0);glVertex3f(1.2,0.0,0.0); glColor3f(0.0,1.0,0.0);glVertex3f(0.0,-0.5,0.0);glVertex3f(0.0,1.2,0.0); glColor3f(0.0,0.0,1.0);glVertex3f(0.0,0.0,-0.5);glVertex3f(0.0,0.0,1.2); glEnd(); }

void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity();

imatrix16 rm(camquat); glTranslatef(0.0,0.0,-1.7); glMultMatrixf(rm.m); //instert drawing here float floorsize = 1.5; float floorstep = 0.25f; float i,j,k,l,m;

float fftime = (float)GetTickCount() / 1000; //float bp1 = 0.0; //float bp2 = 1.0; //float bp3 = 0.0; glPushMatrix(); glTranslatef((float)-floorsize/2,(float)-floorsize/2,0.0); glBegin(GL_POINTS); for (i=0;i<floorsize;i+=floorstep) { for (j=0;j<floorsize;j+=floorstep) { for (k=0;k<floorsize;k+=floorstep) { for (l=0;l<floorsize;l+=floorstep) { // for (m=0;m<floorsize;m+=floorstep) // { inputs[0] = j; inputs[1] = i; inputs[2] = k; inputs[3] = l; inputs[4] = 0.0; inputs[5] = fftime; n1.RunNN();

glColor3f(outputs[0],outputs[1],outputs[2]); glVertex3f(outputs[3],outputs[4],outputs[5]); // } } } } } glEnd();

drawaxes(); glPopMatrix();

glPopMatrix(); glutSwapBuffers(); glutPostRedisplay(); }



void reshape(int w, int h) { glViewport(0,0,(GLsizei) w,(GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(90,(float)w/h,0.01,100.0); }



void motion(int x, int y) { mx = x;my = y;

xs = mx - oldmx; ys = oldmy - my;

oldmx = mx; oldmy = my;

iquaternion4 multquat;

if (mode == MODE_ROTATE) { } else if (mode == MODE_MOVE) {

} else if (mode == MODE_CAM) { multquat.makeEulerRotation( ivector3( (float)ys/SCALE_MOTION,-(float)xs/SCALE_MOTION,0.0 ) ); camquat.multiply(multquat); } }

void mouse(int button,int state,int x,int y) { oldmx = x; oldmy = y;

if (button == GLUT_LEFT_BUTTON) mode = MODE_ROTATE;

if (button == GLUT_RIGHT_BUTTON) mode = MODE_MOVE;

if (button == GLUT_MIDDLE_BUTTON) mode = MODE_CAM; }

void init(void) {

srand( (unsigned)time( NULL ) );

glEnable(GL_DEPTH_TEST); //glEnable(GL_LIGHTING); //glEnable(GL_LIGHT0); //glLightfv(GL_LIGHT0,GL_POSITION,above_origin); //glEnable(GL_BLEND); //glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); //glMaterialfv(GL_FRONT,GL_DIFFUSE,grey); //glMaterialfv(GL_FRONT,GL_SPECULAR,white); //glMaterialfv(GL_FRONT,GL_SHININESS,shiny); //glEnable(GL_POLYGON_OFFSET_FILL); //glPolygonOffset(0.1,0.1); //glDepthFunc(GL_LEQUAL); //glEnable(GL_DEPTH_TEST); //glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); //glEnable(GL_BLEND); //glEnable(GL_POLYGON_SMOOTH); //glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); glPointSize(15.0f); printf("%f",log(100) );

inputs[0] = 0; inputs[1] = 0;

n1.SetResponse(resp); }

void key(GLubyte key, int x, int y) { switch (key) { case 'a':resp -= 0.05f;printf("response %f\n",resp);n1.SetResponse(resp); break;

case 'd':resp += 0.05f;printf("response %f\n",resp);n1.SetResponse(resp); break;

case 'r':im_random_seed_time();n1.Randomize();

break;

case '1':

break;

case '!':

break;

case 'l':

break;

case 'q':exit(0); break; } }

int main(int argc, char **argv) { meInitMemoryCheck();

glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(WINDOW_SIZE,WINDOW_SIZE); glutInitWindowPosition(100,10); glutCreateWindow("Matts test");

glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(key); glutMotionFunc(motion); glutMouseFunc(mouse);

init(); glutMainLoop();

return 0; }

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/demos/matnn/testapp1/glut_test4.cpp] - (5,992 bytes)


/*---------------------------------------------
		
	MatNN library : Test App 4 (cpp)

This shows the copy constructor working. (4 different instances of a net are drawn, that were created by copy constructors)

It will show the assignment operator working aswell, when/if i decide its right to assign neural nets.

keys : r = random neural nets a = decrease response d = increase response

By Matt Barnett

(see References) * See matnn.h for more information ---------------------------------------------*/


//basic glut and math stuff for camera etc #include <ctime> #include <cstdio> #include <windows.h> #include <GL/glut.h>

#include "../../../imath/imath.h" #include "../../../matnn/matnn.h"

GLfloat grey[] = {0.2,0.2,0.2,1.0}; GLfloat above_origin[] = {0.0,0.0,3.0,1.0}; GLfloat white[] = {1.0,1.0,1.0,1.0}; GLfloat shiny[] = {50.0};

#define WINDOW_SIZE 1024 // #define SCALE_MOTION 100 //scale down by int x,y,mx,my,xs,ys; int oldmx = 0; int oldmy = 0;

enum modetype { MODE_ROTATE,MODE_MOVE,MODE_CAM }; modetype mode; iquaternion4 camquat;

//globals for testing here using MatLayeredNeuralNetLib::NeuralNet; float resp = 1.0f; float inputs[6]; float outputs[3];

NeuralNet *n0 = meNew NeuralNet(6,3,4,5,inputs,outputs); //on the heap, so that we can delete it showing that n1 is copyied properly (no crosslinks) NeuralNet n1 = *n0; //calls the copy ctor , (allowed) //------------------------ void drawaxes() { glDisable(GL_LIGHTING);

glBegin(GL_LINES); glColor3f(1.0,0.0,0.0);glVertex3f(-0.5,0.0,0.0);glVertex3f(1.2,0.0,0.0); glColor3f(0.0,1.0,0.0);glVertex3f(0.0,-0.5,0.0);glVertex3f(0.0,1.2,0.0); glColor3f(0.0,0.0,1.0);glVertex3f(0.0,0.0,-0.5);glVertex3f(0.0,0.0,1.2); glEnd(); }

void DrawBrainWave(NeuralNet &in,float floorsize,float floorstep,int x,int y) {

float i,j;

float fftime = (float)GetTickCount() / 1500; float bp1 = 0.0; float bp2 = 1.0; float bp3 = 0.0;

glPushMatrix(); glTranslatef((float)x,(float)y,0.0);

for (i=0;i<floorsize;i+=floorstep) { glBegin(GL_TRIANGLE_STRIP); for (j=0;j<floorsize;j+=floorstep) { inputs[0] = j; inputs[1] = i; inputs[2] = fftime; inputs[3] = bp1; inputs[4] = bp2; inputs[5] = bp3; in.RunNN();

glColor3f(outputs[0],outputs[1],outputs[2]); glVertex3f(i,j,outputs[2]); inputs[0] = j+floorstep; inputs[1] = i+floorstep; inputs[2] = fftime; inputs[3] = bp1; inputs[4] = bp2; inputs[5] = bp3; in.RunNN();

glColor3f(outputs[0],outputs[1],outputs[2]); glVertex3f(i+floorstep,j+floorstep,outputs[2]); } glEnd(); }

drawaxes(); glPopMatrix(); }

void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity();

imatrix16 rm(camquat); glTranslatef(0.0,0.0,-3.0); glMultMatrixf(rm.m);

glTranslatef((float)-1,(float)-1,0.0);

//instert drawing here DrawBrainWave(n1,1.5f,0.08f,0,0); DrawBrainWave(n2,1.5f,0.08f,2,2); DrawBrainWave(n3,1.5f,0.08f,0,2); DrawBrainWave(n4,1.5f,0.08f,2,0);

glutSwapBuffers(); glutPostRedisplay(); }



void reshape(int w, int h) { glViewport(0,0,(GLsizei) w,(GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(90,(float)w/h,0.01,100.0); }



void motion(int x, int y) { mx = x;my = y;

xs = mx - oldmx; ys = oldmy - my;

oldmx = mx; oldmy = my;

iquaternion4 multquat;

if (mode == MODE_ROTATE) { } else if (mode == MODE_MOVE) {

} else if (mode == MODE_CAM) { multquat.makeEulerRotation( ivector3( (float)ys/SCALE_MOTION,-(float)xs/SCALE_MOTION,0.0 ) ); camquat.multiply(multquat); } }

void mouse(int button,int state,int x,int y) { oldmx = x; oldmy = y;

if (button == GLUT_LEFT_BUTTON) mode = MODE_ROTATE;

if (button == GLUT_RIGHT_BUTTON) mode = MODE_MOVE;

if (button == GLUT_MIDDLE_BUTTON) mode = MODE_CAM; }

void init(void) {

srand( (unsigned)time( NULL ) );

glEnable(GL_DEPTH_TEST); //glEnable(GL_LIGHTING); //glEnable(GL_LIGHT0); //glLightfv(GL_LIGHT0,GL_POSITION,above_origin); //glEnable(GL_BLEND); //glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); //glMaterialfv(GL_FRONT,GL_DIFFUSE,grey); //glMaterialfv(GL_FRONT,GL_SPECULAR,white); //glMaterialfv(GL_FRONT,GL_SHININESS,shiny); //glEnable(GL_POLYGON_OFFSET_FILL); //glPolygonOffset(0.1,0.1); //glDepthFunc(GL_LEQUAL); //glEnable(GL_DEPTH_TEST); //glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); //glEnable(GL_BLEND); //glEnable(GL_POLYGON_SMOOTH); //glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); //here we delete n2 meDelete n0;

glPointSize(4.0f);

//wont compile (not allowed) //n1 = n2; inputs[0] = 0; inputs[1] = 0;

//n1.SetResponse(resp); }

void key(GLubyte key, int x, int y) { switch (key) { case 'a':resp -= 0.05f;printf("response %f\n",resp);n1.SetResponse(resp);n2.SetResponse(resp);n3.SetResponse(resp);n4.SetResponse(resp); break;

case 'd':resp += 0.05f;printf("response %f\n",resp);n1.SetResponse(resp);n2.SetResponse(resp);n3.SetResponse(resp);n4.SetResponse(resp); break;

case 'r':im_random_seed_time();n1.Randomize();n2.Randomize();n3.Randomize();n4.Randomize();

break;

case '1':

break;

case '!':

break;

case 'l':

break;

case 'q':exit(0); break; } }

int main(int argc, char **argv) { meInitMemoryCheck();

glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(WINDOW_SIZE,WINDOW_SIZE); glutInitWindowPosition(100,10); glutCreateWindow("Matts test");

glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(key); glutMotionFunc(motion); glutMouseFunc(mouse);

init(); glutMainLoop();

return 0; }

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/matnn/matnn_neuron.h] - (2,158 bytes)

/*---------------------------------------------
		
	MatNN library 

By Matt Barnett (see References)

----------- description -----------

This file just keeps some ugly private NeuralNet classes out of the main header

------------ classes ------------

Neuron NeuronLayer

------------ class design ------------

----------- References: -----------

* See matnn.h. ---------------------------------------------*/


//-------- headers etc ------- //---------------------------- #ifndef MATNN_NEURON_H_HEADER_132424623254 #define MATNN_NEURON_H_HEADER_132424623254

//---------------------------- //---------------------------- namespace MatLayeredNeuralNetLib { //private class for neurons (clients cant mess with neurons) class Neuron { friend class NeuronLayer;

private:

Neuron(Neuron ©); //copy Neuron &operator=(Neuron &rhs); //assign Neuron(int in_inputs,float &in_sig_response); ~Neuron();

inline float Calc(float *inputs); void RandomizeWeights(); inline void Mutate(float chance,float extent);

float *weights; //array of weights, owned by this neuron int num_inputs; float &sig_response; };

//private class for neuron layers (clients cant mess with layers) class NeuronLayer { friend class NeuralNet; friend class TrainableNeuralNet;

private:

NeuronLayer(NeuronLayer ©); //copy NeuronLayer &operator=(NeuronLayer &rhs); //assign NeuronLayer(int in_neurons,int in_num_inputs,float *finputs); ~NeuronLayer();

inline void RunLayer(); void Randomize(); inline int Mutate(float chance,float extent);

inline float GetOutput(int neuron_index) { return output[neuron_index]; } inline void SetResponse(float in_sig_response) { sig_response = in_sig_response; }

int num_neurons; float *input; //float array pointer (points to parent layers outputs); float *output; //float array pointer (owned by this layer) Neuron **neurons; //array of pointers to neurons float sig_response; }; }

#endif

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/matnn/matnn.h] - (5,490 bytes)

/*---------------------------------------------
		
	MatNN library 

By Matt Barnett (see References)

----------- usage -----------

I find that this is the section that i most often look for in other peoples docs, and neglect in my own.

Look at the examples for usage comments, or examin the public interface.

----------- description -----------

This is not really a library yet, but its designed so it can be extended (hence the namespace) , and is as general as possible. The Neural Net Specification (this is the same as the this library's pre-cursor, my other nn classes)

* Neurons are made in layers

input layer (any number of neurons) hidden layers (each has the same number of neurons) output layer (any number of neurons)

* Each layer (starting with the input layer) uses its neurons to calculate the outputs for all the neurons in this layer. This is stored in an array which the subsequent layer "knows".

* The inital layer has no neuon inputs, this is where the input from the "environment" enters the net. The input layer has a pointer to inputs that are specified by the client

----------- portability -----------

* Depends on imath.h (see imath.h) (needs OpenGL, this is bad for a class a general as this) * Error messages need windows, hack the error class to support non windows * Neural nets are written to text files for easy editing and portability

------------ class goals ------------

NeuralNet : Serves as a base class for more specific neural nets (basic neural net function) Will not contain any code for training/adjustment of the net.

------------ class design ------------

The design is such that, the net class constructs itself appropriatly for the given parameters and is then ready to run. This helps keep the rest of the interface small.

Neural nets are written to a formatted text file for storage. This makes it easy to understand / edit and should make it more portable. (ie no struct size depenence)

* No consideration given to const/non const neural nets/neurons/layers ( YET ! ) * There is no default constructor.

* Class design leaves some bounds checking to the client !!!!!!! (s/he simply has to stay within the bounds of his own arrays and be able to remeber/work out the size of the array, (only once) )

----------- References: -----------

* See imath.h, myerror.h ---------------------------------------------*/




//-------- headers etc ------- //---------------------------- #ifndef MATNN_MAIN_H_HEADER_012023254 #define MATNN_MAIN_H_HEADER_012023254

#include "../leakdetect.h"

#include <iostream>

//using std::cout; //using std::endl; #include <math.h> //fpu maths #include <cassert> //assert //#include <windows.h> //opengl needs windows (comment for non WIN32 platforms) //#include <gl/gl.h> #include "matnn_neuron.h" #include "../imath/imath.h" #include "../myerror.h"

//---------------------------- //----------------------------

//these limits are quite arbitrary //just to prevent the user making an insane //net just to test the memory handling (which isnt that hot) #define MATNN_MAX_HIDDEN_LAYERS 256 //256 seems a reasonable limit for these #define MATNN_MAX_IN_NEURONS 256 // #define MATNN_MAX_OUT_NEURONS 256 // #define MATNN_MAX_HIDDEN_NEURONS 256 //

namespace MatLayeredNeuralNetLib { class NeuralNet { //neural net public interface public: //the client is responsible for storage of input & output arrays //but they only need to be set once, and then the you change the input //just be fiddling the array. NeuralNet(NeuralNet ©); //copy NeuralNet &operator=(NeuralNet &rhs); //assign NeuralNet(int in_neurons,int out_neurons,int hidden_neurons,int hidden_layers,float *in_finput,float *in_foutput); ~NeuralNet();

void RunNN(); //runs the neural net void SetResponse(float in_sig_response); //alters the response constant for all neurons and layers in the net void SetInputOutput(float *in_finput,float *in_foutput); //alters input/output arrays (null checking) void Randomize(); //dangerous to call on a trained net (it totally randomises weights to -1.0 + 1.0)

protected: int num_input_neurons; int num_output_neurons; int num_hidden_neurons; int num_hidden_layers;

NeuronLayer *input_layer; //will point to the first layer NeuronLayer *output_layer; //will point to the last layer NeuronLayer **parray_hidden_layers; //an array of pointers for the hidden layers private: float *input; float *output;

float sig_response; }; class TrainableNeuralNet : public NeuralNet { public:

TrainableNeuralNet(int in_neurons,int out_neurons,int hidden_neurons,int hidden_layers,float *in_finput,float *in_foutput) : NeuralNet(in_neurons,out_neurons,hidden_neurons,hidden_layers,in_finput,in_foutput) {} ~TrainableNeuralNet() {} int Mutate(float mutation_chance,float mutation_extent); //returns the number of mutations that occured //ref or copy? //TrainableNeuralNet Clone() //TrainableNeuralNet Cross(TrainableNeuralNet &mate) //void Merge() }; }

#endif

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/matnn/matnn.cpp] - (10,226 bytes)

/*---------------------------------------------
		
	MatNN library : Implementation (cpp)

* See Header file for more information

By Matt Barnett (see References) ---------------------------------------------*/


#include "matnn.h"

//---------------------------- //---------------------------- using MatLayeredNeuralNetLib::Neuron; using MatLayeredNeuralNetLib::NeuronLayer; using MatLayeredNeuralNetLib::NeuralNet; using MatLayeredNeuralNetLib::TrainableNeuralNet;

//the constructors look a bit nasty because a reference to //the response variable/constant is passed down by the NeuralNet //owner class (this allows one copy per NeuralNet , and when it changes //there is no need to update each neuron/layer copy) // // MatNN::Neuron // //do not copy neurons //Neuron::Neuron(Neuron ©) //{ //} //Neuron &Neuron::operator=(Neuron &rhs) //{ // // return *this; //}

Neuron::Neuron(int in_inputs,float &in_sig_response) : sig_response(in_sig_response) { num_inputs = in_inputs;

//inputs = 0; //inputs = meNew Neuron * [num_inputs]; weights = 0; weights = meNew float [num_inputs];

RandomizeWeights(); }

void Neuron::RandomizeWeights() { //randomize each weight 0.0f - 1.0f for (int i=0;i<num_inputs;i++) { weights[i] = RANDOM_CLAMP; } }

void Neuron::Mutate(float chance,float extent) { //mutate one of my weights by +/- extent //int i = RANDOM_NUM * num_inputs; //weights[i] += RANDOM_CLAMP * extent; //mutate any/some/all neuron weights for (int i=0;i<num_inputs;i++) if (RANDOM_NUM < chance) weights[i] += RANDOM_CLAMP * extent; }

float Neuron::Calc(float *inputs) { float out = 0; for (int x=0;x<num_inputs;x++) { out += weights[x] * inputs[x]; }

//sigmoid reponse curve //return ( 1 / (sig_response + (float)exp( - (out / 10) )) ); //sinus response curve return im_sin( out / sig_response); }

Neuron::~Neuron() { //cleanup meDelete [] weights;weights = 0; }

// // MatNN::NeuronLayer // NeuronLayer::NeuronLayer(NeuronLayer ©) { num_neurons = copy.num_neurons;

//cannot be assigned yet!! //this must be fixed by the caller input = 0;

output = 0; output = meNew float [num_neurons]; neurons = 0; neurons = meNew Neuron * [num_neurons]; //same number of neurons as previous layer for (int i=0;i<num_neurons;i++) { //create neurons neurons[i] = 0; neurons[i] = meNew Neuron(copy.neurons[0]->num_inputs,sig_response); //one float input for each neuron in the environmental/input layer //copy over the weights from copy memcpy( neurons[i]->weights,copy.neurons[i]->weights,sizeof(float) * copy.neurons[0]->num_inputs ); } }

//No = //NeuronLayer &NeuronLayer::operator=(NeuronLayer &rhs) //{ // // return *this; //} NeuronLayer::NeuronLayer(int in_neurons,int in_num_inputs,float *finputs) { num_neurons = in_neurons;

input = 0; input = finputs;

output = 0; output = meNew float [num_neurons]; neurons = 0; neurons = meNew Neuron * [num_neurons]; for (int i=0;i<num_neurons;i++) { neurons[i] = 0; neurons[i] = meNew Neuron(in_num_inputs,sig_response); //one float input for each neuron in the environmental/input layer } if (!input) { printf("NeuronLayer::NeuronLayer() no input array specified!\n"); exit(0); } }

NeuronLayer::~NeuronLayer() { meDelete [] output; output = 0;

for (int i=0;i<num_neurons;i++) { meDelete neurons[i]; neurons[i] = 0; } meDelete [] neurons; neurons = 0; }

void NeuronLayer::RunLayer() { for (int x = 0;x<num_neurons;x++) { output[x] = neurons[x]->Calc(input); } }

void NeuronLayer::Randomize() { for (int x = 0;x<num_neurons;x++) neurons[x]->RandomizeWeights(); }

int NeuronLayer::Mutate(float chance,float extent) { int mutated = 0;

//if chance, then mutate for (int x = 0;x<num_neurons;x++) { if (RANDOM_NUM < chance) { neurons[x]->Mutate(chance,extent); mutated++; } }

return mutated; }

// // MatNN::NeuralNet // NeuralNet::NeuralNet(int in_neurons,int out_neurons,int hidden_neurons,int hidden_layers,float *in_finput,float *in_foutput) { Sleep(30); im_random_seed_time();

//sanity checks first if (num_hidden_layers < 0 || num_hidden_layers > MATNN_MAX_HIDDEN_LAYERS) { cMyError e;e.FatalError("hidden_layers must be 0 => < = %i!",MATNN_MAX_HIDDEN_LAYERS); exit(EXIT_FAILURE); }

if (in_neurons < 0 || in_neurons > MATNN_MAX_IN_NEURONS) { cMyError e;e.FatalError("in_neurons must be 0 => < = %i!",MATNN_MAX_IN_NEURONS); exit(EXIT_FAILURE); }

if (out_neurons < 0 || out_neurons > MATNN_MAX_OUT_NEURONS) { cMyError e;e.FatalError("out_neurons must be 0 => < = %i!",MATNN_MAX_OUT_NEURONS); exit(EXIT_FAILURE); }

if (hidden_neurons < 0 || hidden_neurons > MATNN_MAX_HIDDEN_NEURONS) { cMyError e;e.FatalError("hidden_neurons must be 0 => < = %i!",MATNN_MAX_HIDDEN_NEURONS); exit(EXIT_FAILURE); }

//get input & output pointers input = in_finput; output = in_foutput;

//grap those parameters num_input_neurons = in_neurons; num_output_neurons = out_neurons; num_hidden_neurons = hidden_neurons; num_hidden_layers = hidden_layers; //null em input_layer = 0; output_layer = 0; parray_hidden_layers = 0;

//create input layer input_layer = meNew NeuronLayer(num_input_neurons,num_input_neurons,input);

//an array of pointers to hidden layers if (num_hidden_layers) { parray_hidden_layers = meNew NeuronLayer * [num_hidden_layers]; if (!parray_hidden_layers) { cMyError e;e.FatalError("Could not allocate %i hidden layers!",num_hidden_layers); meDelete input_layer;

exit(EXIT_FAILURE); } }

//null each one and create it for (int i=0;i<num_hidden_layers;i++) { parray_hidden_layers[i] = 0;

if (i == 0) parray_hidden_layers[i] = meNew NeuronLayer(num_hidden_neurons, input_layer->num_neurons,input_layer->output); else parray_hidden_layers[i] = meNew NeuronLayer(num_hidden_neurons, parray_hidden_layers[i - 1]->num_neurons , parray_hidden_layers[i - 1]->output); }

//output layer attached to last hidden layer //or to input layer (special case) if (num_hidden_layers == 0) output_layer = meNew NeuronLayer(num_output_neurons , input_layer->num_neurons , input_layer->output); else output_layer = meNew NeuronLayer(num_output_neurons , parray_hidden_layers[num_hidden_layers - 1]->num_neurons , parray_hidden_layers[num_hidden_layers - 1]->output);



//anything reasonable is ok here //as long as the net has been constructed SetResponse(1.0f);

}

//No = //NeuralNet &NeuralNet::operator=(NeuralNet &rhs) //{ // return *this; //} NeuralNet::NeuralNet(NeuralNet ©) { //starting with the simple stuff sig_response = copy.sig_response; num_input_neurons = copy.num_input_neurons; num_output_neurons = copy.num_input_neurons; num_hidden_neurons = copy.num_hidden_neurons; num_hidden_layers = copy.num_hidden_layers;

//null layers input_layer = 0; output_layer = 0; parray_hidden_layers = 0; //get input & output pointers //its assumed that users want copied //nets to share input & output pointer //(this is the most obvious behaviour i think) input = copy.input; output = copy.output;

//after copying layers //we must fix the input pointer to the new net //create input layer as copy input_layer = meNew NeuronLayer(*copy.input_layer); input_layer->input = input;

//an array of pointers to hidden layers parray_hidden_layers = meNew NeuronLayer * [num_hidden_layers]; //null each one and create it as copy for (int i=0;i<num_hidden_layers;i++) { parray_hidden_layers[i] = 0; parray_hidden_layers[i] = meNew NeuronLayer(*copy.parray_hidden_layers[i]);

if (i == 0) parray_hidden_layers[i]->input = input_layer->output; else { parray_hidden_layers[i]->input = parray_hidden_layers[i - 1]->output; } } //output layer attached to last hidden layer(?? or input layer ??) as copy output_layer = meNew NeuronLayer(*copy.output_layer);

if (num_hidden_layers == 0) output_layer->input = input_layer->output; else output_layer->input = parray_hidden_layers[num_hidden_layers - 1]->output;

SetResponse(copy.sig_response); //that should do it }

NeuralNet::~NeuralNet() { //cleanup meDelete input_layer;input_layer = 0; meDelete output_layer;output_layer = 0;

//cleanup an array of pointers to allocated layers for (int i=0;i<num_hidden_layers;i++) { meDelete parray_hidden_layers[i]; parray_hidden_layers[i] = 0; }

meDelete [] parray_hidden_layers; parray_hidden_layers = 0; }

void NeuralNet::RunNN() { //run each layer input_layer->RunLayer(); for (int i=0;i<num_hidden_layers;i++) parray_hidden_layers[i]->RunLayer();

output_layer->RunLayer();

//copy output from last layer for (i=0;i<num_output_neurons;i++) output[i] = output_layer->GetOutput(i); }

void NeuralNet::SetResponse(float in_sig_response) { sig_response = in_sig_response; input_layer->SetResponse(in_sig_response); for (int i=0;i<num_hidden_layers;i++) parray_hidden_layers[i]->SetResponse(in_sig_response); output_layer->SetResponse(in_sig_response); }

void NeuralNet::SetInputOutput(float *in_finput,float *in_foutput) { if (!in_finput || !in_foutput) { cMyError e;e.AlertError("SetInputOutput(), dont pass null pointers!!");return; } input = in_finput;output = in_foutput; }

void NeuralNet::Randomize() { input_layer->Randomize(); for (int i=0;i<num_hidden_layers;i++) { parray_hidden_layers[i]->Randomize(); } output_layer->Randomize(); }

// // MatNN::TrainableNeuralNet // int TrainableNeuralNet::Mutate(float chance,float extent) { int mutated = 0;

mutated += input_layer->Mutate(chance,extent); for (int i=0;i<num_hidden_layers;i++) { mutated += parray_hidden_layers[i]->Mutate(chance,extent); } mutated += output_layer->Mutate(chance,extent);

return mutated; }

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/imath/imath_mq.h] - (13,443 bytes)

/*-----------------------------------------------------------------------
		
	Inline Math library : Matrix and Quaternion implementation
	
	* See imath.h for more information

By Matt Barnett (see References in imath.h) ------------------------------------------------------------------------*/


#ifndef _IMATH_MQ_IMP_HEADER_4778097634 #define _IMATH_MQ_IMP_HEADER_4778097634

//---------------------------- //---------------------------- class iquaternion4 { public: //quaternion data (w,x,y,z) union { float q[4]; struct { float w, x, y, z; }; }; //-------------- operators --- //---------------------------- inline float operator[](int subscript) { assert( subscript < 4 && subscript >= 0 ); return q[subscript]; }

//assignment inline const iquaternion4 &operator=(const iquaternion4 &right) { if (&right != this) { //check for self assign w = right.w; x = right.x; //copy right to left y = right.y; z = right.z; } return *this; //enables x = y = z } //---------------------------- //---------------------------- //------- construction etc --- //---------------------------- //default ctor inline iquaternion4() { makeMultiplicationIdentity(); } //ctor inline iquaternion4(float setw,float setx,float sety,float setz) { set(setw,setx,sety,setz); } //ctor inline iquaternion4(float angle,ivector3 &axis) { makeAngleAxisRotation(angle,axis); } //ctor explicit inline iquaternion4(ivector3 &euler) { makeEulerRotation(euler); }

//dtor(unnessesary) inline ~iquaternion4() { } //---------------------------- //---------------------------- //--------- void functions --- //---------------------------- inline void set(float setw,float setx,float sety,float setz) { w = setw; x = setx; y = sety; z = setz; } //dumps the quaternion componets inline const void cdump(const char *caption) { cout << caption << w << " " << x << " " << y << " " << z << endl; }

//theroy (identity quaternion) // //There are two identity quaternions. //In this context, we only use the one that multiplies with another quaternion //to give the same quaternion ( the multiplication identity ) inline void makeMultiplicationIdentity() { q[0] = 1.0; //w q[1] = 0.0; //x q[2] = 0.0; //y q[3] = 0.0; //z }

//from Ref 5. (* See imath.h) //(http://gamedev.net/reference/articles/article1691.asp#Q53) //Qr = Q1.Q2 = ( w1.w2 - v1.v2, w1.v2 + w2.v1 + v1 x v2 ) // //where v1 = (x,y,z) of Q1 // w1 = (w) of Q1 // v2 = (x,y,z) of Q2 // w2 = (w) of Q2 // //and both . and x are the standard vector dot and cross products. //its easy(ish) to follow that the multiply function //doesnt chane the quaternion if multiply is the identity inline void multiply(const iquaternion4 &multiply) { iquaternion4 temp; temp.x = ((w * multiply.x) + (x * multiply.w) + (y * multiply.z) - (z * multiply.y)); //for multiply == identity quaternion //x = 1 * x + 0 * w + 0 * y + 0 * z; //x = x temp.y = ((w * multiply.y) - (x * multiply.z) + (y * multiply.w) + (z * multiply.x)); temp.z = ((w * multiply.z) + (x * multiply.y) - (y * multiply.x) + (z * multiply.w)); temp.w = ((w * multiply.w) - (x * multiply.x) - (y * multiply.y) - (z * multiply.z)); *this = temp; }

inline void makeAngleAxisRotation(float angle,ivector3 &axis) { const float hangle(angle * 0.5f); const float sina(im_sin(hangle) ); x = (axis.x * sina); y = (axis.y * sina); z = (axis.z * sina); w = cos(hangle); }

//from Ref 5. (* See imath.h) //(more or less unchanged from what that articles has) //(http://gamedev.net/reference/articles/article1691.asp#Q60) //" The following more or less comes from: // http://vered.rose.utoronto.ca/people/david_dir/GEMS/GEMS.html " inline void makeEulerRotation(ivector3 &angles) { //Pitch->X axis, Yaw->Y axis, Roll->Z axis const float sinPitch(im_sin(angles.y*0.5f)); const float cosPitch(im_cos(angles.y*0.5f));

const float sinYaw(im_sin(angles.z*0.5f)); const float cosYaw(im_cos(angles.z*0.5f));

const float sinRoll(im_sin(angles.x*0.5f)); const float cosRoll(im_cos(angles.x*0.5f)); const float cosPitch_cosYaw(cosPitch*cosYaw); const float sinPitch_sinYaw(sinPitch*sinYaw);

x = sinRoll * cosPitch_cosYaw - cosRoll * sinPitch_sinYaw; y = cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw; z = cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw; w = cosRoll * cosPitch_cosYaw + sinRoll * sinPitch_sinYaw; }

//this is the alternative //multiplying euler angles in the correct order //i _think_ that the above is simply a re-arrangment //but i think the ordering here is wrong or somthing //(whatever, the above works the way i want and this doesnt) // //inline void makeEulerRotation(ivector3 &angles) //{ // iquaternion4 qx( im_cos(angles.x/2),im_sin(angles.x/2),0,0 ); // iquaternion4 qy( im_cos(angles.y/2),0,im_sin(angles.y/2),0 ); // iquaternion4 qz( im_cos(angles.z/2),0,0,im_sin(angles.z/2) ); // qx.multiply ( qy ); // qx.multiply ( qz ); // *this = qx; //} // //---------------------------- //---------------------------- //-------------- functions --- //---------------------------- //well this seems to draw the expected vector //but its easier to extract the basis from the //matrix, since the quat is converted to one in the //end const ivector3 &direction() { ivector3 out; out.x = 2.0f * ( x * z - w * y ); out.y = 2.0f * ( y * z + w * x ); out.z = 1.0f - 2.0f * ( x * x - y * y );

out.normalise(); return out; }

inline float dot(const iquaternion4 &right) { return ( (x * right.x) + (y * right.y) + (z * right.z) + (w * right.w) ); } inline float lengthsqr() { return dot(*this); } inline float length() { return sqrt( lengthsqr() ); }

//just like a vector ( UNTESTED ) inline void normalise() { const float leng(length() ); x /= leng; y /= leng; z /= leng; w /= leng; }

//?? inline iquaternion4 &lerp(iquaternion4 &other,float t); //?? inline iquaternion4 &slerp(iquaternion4 &other,float t); //?? inline void invert(iquaternion4 &multiply); //---------------------------- //---------------------------- };

//-------------- imatrix16 ----------------------------------------------------------- // // --------------------------------- // Row and clomn major format issues // --------------------------------- // // Currently, this is an OpenGL freindly matrix // class. Direct3D stores matricies in a different // order to OpenGL, and this would need to be accounted // for if Direct3D was used. Also, an engine might need // to use both formats if it supports both APIs. This is // why i have differed implementing this feature untill i // know how to get it right. // // //matrix in colomn major format (consistant with opengl) // // eg { m[0] m[4] m[8] m[12] // m[1] m[5] m[9] m[13] // m[2] m[6] m[10] m[14] // m[3] m[7] m[11] m[15] } // //note: it would be cool to have a union for the matrix data allowing sensible names // for different parts of the matrix. For instance, the first 3x3 block represents // the rotation in the form of the orthonormal basis axes. The matrix also stores scaling etc. // // somthing like... // // // union // { // float m[16]; // struct { float col0[4],col1[4],col2[4],col3[4]; }; // // }; // //--------------------------------------------------------------------------------- class imatrix16 { public:

//------- construction etc --- //---------------------------- float m[16]; //matrix data inline imatrix16() { makeIdentity(); } //ctor inline imatrix16(iplane4 &cast_floor,ivector3 lightpos) { makeProjection(cast_floor,lightpos); } //ctor explicit inline imatrix16(iquaternion4 &createfrom) { makefromQuaternion(createfrom); } //ctor inline ~imatrix16() {} //dtor(unnessesary) //---------------------------- //---------------------------- //--------- void functions --- //---------------------------- //dumps the matrix componets inline const void cdump(const char *caption) { cout << caption << " row major\n";

cout << caption << " row 1 " << m[0] << " " << m[1] << " " << m[2] << " " << m[3] << endl; cout << caption << " row 2 " << m[4] << " " << m[5] << " " << m[6] << " " << m[7] << endl; cout << caption << " row 3 " << m[8] << " " << m[9] << " " << m[10] << " " << m[11] << endl; cout << caption << " row 4 " << m[2] << " " << m[13] << " " << m[14] << " " << m[15] << endl; cout << caption << " col major\n";

cout << caption << " col 1 " << m[0] << " " << m[4] << " " << m[8] << " " << m[12] << endl; cout << caption << " col 2 " << m[1] << " " << m[5] << " " << m[9] << " " << m[13] << endl; cout << caption << " col 3 " << m[2] << " " << m[6] << " " << m[10] << " " << m[14] << endl; cout << caption << " col 4 " << m[3] << " " << m[7] << " " << m[11] << " " << m[15] << endl << endl; }

//inline void invert //inline void transpose inline void makeIdentity() { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0;

m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0;

m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0;

//last right hand colomn m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; }

//this makes a projection matrix //which can be fed into a graphics API // //is by no means perfect as a shadow/projection //matrix (still a work in progress) //from http://www.sgi.com/software/opengl/advanced96/node46.html inline void makeProjection(iplane4 &cast_floor,ivector3 &light_pos) { float light_posw = 0.0; //0.0? float dot = cast_floor.norm.x * light_pos.x + cast_floor.norm.y * light_pos.y + cast_floor.norm.z * light_pos.z + cast_floor.d * light_posw;

m[0] = dot - light_pos.x * cast_floor.norm.x; m[1] = 0.0 - light_pos.y * cast_floor.norm.x; m[2] = 0.0 - light_pos.z * cast_floor.norm.x; m[3] = 0.0 - light_posw * cast_floor.norm.x; m[4] = 0.0 - light_pos.x * cast_floor.norm.y; m[5] = dot - light_pos.y * cast_floor.norm.y; m[6] = 0.0 - light_pos.z * cast_floor.norm.y; m[7] = 0.0 - light_posw * cast_floor.norm.y; m[8 ] = 0.0 - light_pos.x * cast_floor.norm.z; m[9 ] = 0.0 - light_pos.y * cast_floor.norm.z; m[10] = dot - light_pos.z * cast_floor.norm.z; m[11] = 0.0 - light_posw * cast_floor.norm.z; m[12] = 0.0 - light_pos.x * cast_floor.d; m[13] = 0.0 - light_pos.y * cast_floor.d; m[14] = 0.0 - light_pos.z * cast_floor.d; m[15] = dot - light_posw * cast_floor.d; } //from gametutorials.net (see ref 6) inline void makefromQuaternion(iquaternion4 &q) { // First row m[ 0] = 1.0f - 2.0f * ( q.y * q.y + q.z * q.z ); m[ 1] = 2.0f * ( q.x * q.y - q.w * q.z ); m[ 2] = 2.0f * ( q.x * q.z + q.w * q.y ); m[ 3] = 0.0f;

// Second row m[ 4] = 2.0f * ( q.x * q.y + q.w * q.z ); m[ 5] = 1.0f - 2.0f * ( q.x * q.x + q.z * q.z ); m[ 6] = 2.0f * ( q.y * q.z - q.w * q.x ); m[ 7] = 0.0f;

// Third row m[ 8] = 2.0f * ( q.x * q.z - q.w * q.y ); m[ 9] = 2.0f * ( q.y * q.z + q.w * q.x ); m[10] = 1.0f - 2.0f * ( q.x * q.x + q.y * q.y ); m[11] = 0.0f;

// Fourth row m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1.0f; }

//this functions could be avoided by //providing better access to the matrix's //internal values //based on theroy (Q5 of matrix FAQ) (see ref 5) inline ibasis9 &getBasis() { //prepare the basis based on the matrix ivector3 xa( m[0],m[1],m[2] ); ivector3 ya( m[4],m[5],m[6] ); ivector3 za( m[8],m[9],m[10] ); //make it and return it ibasis9 out(xa,ya,za); return out; }

// void multiply_vectors(ivector3 *vector_array,int num_vectors) { assert(vector_array); assert(num_vectors == 1);

ivector3 out; out.x = m[0] * vector_array->x + m[4] * vector_array->y + m[8] * vector_array->z; out.y = m[1] * vector_array->x + m[5] * vector_array->y + m[9] * vector_array->z; out.z = m[2] * vector_array->x + m[6] * vector_array->y + m[10] * vector_array->z; *vector_array = out; }

//??? inline void makePerspectiveProjection() {} //??? inline void makeOrthographicProjection() {} //??? inline void makeEulerRotation(float angle, ivector3 &axis) {} //??? inline void makeAngleAxisRotation(float angle, ivector3 &axis) {} //---------------------------- //---------------------------- };

#endif

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/imath/imath_lut.h] - (8,920 bytes)

/*-----------------------------------------------------------------------
		
	Inline Math library : Lookup table implementation
	
	* See imath.h for more information

By Matt Barnett (see References in imath.h) ------------------------------------------------------------------------*/


#ifndef _IMATH_LUT_IMP_HEADER_223457642 #define _IMATH_LUT_IMP_HEADER_223457642

//------- float_lookuptable ------------------------------------ // // Before i begin.. Yes, i know that the c++ // standard library has a lookup table template class. // // // This is a simple generic lookup table(lut) class // for functions that return a single float // and take a single float parameter // (GPG2 see ref 2) has a better lookuptable) // // this works well for sinf etc // //. With bounds checking its quite a bit slower. // Without it, i think a lookup maybe amount to // only a few cycles (WRONG!, in retrospect, see asm anal), // because looking up consists of // an inline (no fuction call) function // which performs a single divide, and // uses the clever real2int to get an int // to index the array with // // ------ design notes ----- // // i decided to forgo inheritance // // (it would be nice to have a base class // lookuptable and inhert specific // table types) // // templates would probably be a good idea // // (but an int indexing table would be // quite different than a float "indexing" // one, and could be faster, so the template // would have to account for that) // // In the end decided to make this a simple class // with inlined functions specific to functions of // the form // // float somefunction(float someparam); // // becomes... // // float somelut.lookup(someparam); // // The other lut class, is specifically // for generating random numbers and is // pretty much hard-coded to that effect. // // ---------- performance notes --------------- // -------------------------------------------- // // *test yourself using test_speed(int); // *test in both Debug and Release modes // (only take Release mode seriously, but // its usefull to see the difference between // debug & release) // // // Debug mode is still faster than parent functions // which are them selves slower than in Release mode. // // faster than parent tri functions // generally slower for sqrtf // faster than on-the fly random number generation // (not yet suited to rng, which really // deserves its own lut class) // // -------------------------------------------- // ---------- mem usage notes --------------- // ------------------------------------------ // //100 floats 400bytes //maybe for some stuff //1000 floats = 4k //vagly accurate //10000 floats = 40k etc //pretty accurate // // Need more accuracy? // (fix class before using more samples) // // 1) // // I've made that the upper limit for the number of // samples. Not due to memory usage but processor // cache usage. (im guessing here, from accumlated knowledge) // We want to be sure that the whole table fits in the cache // so that its really fast. (this afik occurs automagically) // If the table is to big, the chances are that the processor // will thrash the table. Much like a gfx card will thrash textures // between system/texture memory if the application tries to use to // much texture memory. // ------------------------------------------ //if you want a quick report when a lookup table constructs then define FLUT_VERBOSE //if you want to remove the construction message, rem FLUT_VERBOSE out #define FLUT_VERBOSE

class float_lookuptable { public:

//constructor provides everything float_lookuptable(int innumsamples,float instart,float inend,float (*function)(float) ) { //store the pointer to the function for testing later parentfunction = function; num_samples = innumsamples; if (innumsamples > 10000) { printf("float_lookuptable::float_lookuptable() num_samples > 10000!! rtfm\n"); exit(0); }

start = instart; end = inend; samples = 0; samples = meNew float [num_samples]; assert(samples);

//may as well fabs() to be sure we get a positive //delta (as this is precalc float diff = fabs(end - start); delta = diff / (float)(num_samples); float x = start;

#ifdef FLUT_VERBOSE printf("float_lookuptable( start(%f),end(%f),delta(%f),num(%i) )\n",start,end,delta,num_samples); #endif

for (int i = 0; i < num_samples; i++) { //assert(index < num_samples); x = start + (diff * (float)i / (num_samples) ); samples[i] = (*parentfunction)(x); } }

//looks up like the function inline float lookup(float lookup_what) const { lookup_what /= delta; int il = im_real2int(lookup_what); //fast //int il = (int)lookup_what ; //doesnt seem any slower //we only need to check the index is safe //to access the array. These are faster //than comparing floats // (we could use a smaller precision index // and possibly gain more speed)

//was previously this line (which caused the assertion(il < num_samples) to fail (+3v!L />U|\|7i/\/\3 3/>/>0z) //while (il >= num_samples) il -= num_samples; while (il >= num_samples) il -= num_samples; while (il < 0) il += num_samples; assert(il >= 0); assert(il < num_samples);

return samples[il]; }

void test_speed(int test_samples) const { printf("\n\ntesting speed\n\n");

//i think as long as we do enough samples //it will be an ok test long before,after,deltatime; float some_number = two_pi/1.23456789; //get an angle float out; //temp to store output of function int x = 0; //counter before = GetTickCount(); //time before for (x=0;x<test_samples;x++) //do the test out = lookup(some_number); after = GetTickCount(); //time after deltatime = after - before; //delta printf("lookup(%f) x %i = (%f) in %i msec\n",some_number,samples,out,deltatime);

before = GetTickCount(); //time before for (x=0;x<test_samples;x++) //do the test out = parentfunction(some_number);

after = GetTickCount(); //time after deltatime = after - before; //delta

printf("parentfunction(%f) x %i = (%f) in %i msec\n",some_number,samples,out,deltatime); }

~float_lookuptable() { meDelete [] samples; }

private: float *samples; int num_samples; float start,end; float delta; float (*parentfunction)(float);

//no assignment or copy kids operator=(float_lookuptable &); float_lookuptable(float_lookuptable &); };

//------------------------------------- //hard coded random number lookup table //------------------------------------- //note: this is slower in debug mode than // rand(); // // but in release mode it beats rand() // however, because rand() is so fast // its probably not worth the memory //quick prototype void im_random_seed_time();

class float_random_lookuptable { public: float_random_lookuptable(int numsamples) { //seed the generator im_random_seed_time();

//class general num_samples = numsamples; current_index = 0;

//alloc memory samples = 0; samples = meNew float [num_samples]; assert(samples);

//fill the array for (int x=0;x<num_samples;x++) { samples[x] = ((float)rand()/(RAND_MAX+1)); }

} ~float_random_lookuptable() { meDelete [] samples; }

inline float lookup_random_num() { return samples[current_index]; current_index++;

//loop around again if (current_index > num_samples) current_index = 0; } //not const becauase it calls lookup_random_num void test_speed(int test_samples) { printf("\n\ntesting speed\n\n");

//i think as long as we do enough samples //it will be an ok test long before,after,deltatime;

float out; //temp to store output of function int x = 0; //counter before = GetTickCount(); //time before for (x=0;x<test_samples;x++) //do the test out = lookup_random_num(); after = GetTickCount(); //time after deltatime = after - before; //delta printf("lookup_random_num() x %i = %i msec\n",test_samples,deltatime);

before = GetTickCount(); //time before for (x=0;x<test_samples;x++) //do the test out = ((float)rand()/(RAND_MAX+1));

after = GetTickCount(); //time after deltatime = after - before; //delta printf("((float)rand()/(RAND_MAX+1)) x %i = %i msec\n",test_samples,deltatime); }

private: int num_samples,current_index; float *samples; };

#endif

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/imath/imath.h] - (5,274 bytes)

/*---------------------------------------------
		
	Inline Math library 
	(imath , im_)

By Matt Barnett (see References)

----------- portability -----------

exclusivly uses the internal float datatype throughout and precision and portability are dependent on that.

------------ classes ------------ ivector3 ibasis9 imatrix16 iquaternion4 iray6 iplane4 ibox3

---------------- other components ----------------

* float constants collection

* lookup table class (for functions such as sin/cos/tan/acos etc) * random number lookup table class

* interfaces to generalise common math functions im_random_num() //uses lookup tables im_random_clamp() im_sin() //uses lookup tables im_cos() //uses lookup tables im_acos() im_tan() //uses lookup tables im_sqrt()

------------------------------- external components [optional] ------------------------------- ibox3 (closly intergrated with imath)

------------ class design ------------

imath.h //include this file imath.cpp //add this file to project imath.lib? //or link to this? this file, imath.h sould include the files

imath_vmq.h //vector mathrix and quats all together imath_trace.h //rays and planes together imath_box.h //bounding boxes imath_lut.h //lookup tables * All functions are inlined (the i stands for inline) ( this should be optimal, ie: the compilier chooses )

* Operators are generally not implemented using member functions calls. This is deliberate. Member function calls quite specifically operate on an object, and operators act between them. * Integral types are passed/returned by value math objects are passed/returned by reference where appropriate

* All members are public (for core classes). Classes are designed to mimic integral types(hmm, dont that too seriously).

----------- References: ( INCOMPLETE ) ----------- 1. PI constants from windows calculator :) Allthough you cant store such an accurate PI very easily its worth noting that wincalc will give pi to 21 decimal places.

2. Game Programming Gems 2 3. Elemetry Linear Algebra 4. Real2Int function By Sree (* See imath_real2int.h ) 5. www.gametutorials.com (specifically the quaternion example, great site) 6. matrix & quaternion FAQ (everything about m's and q's) 7. Effective C++ 2e (great book) 8. flipcode http://www.flipcode.com/cgi-bin/msg.cgi?showThread=00002476&forum=general&id=-1 (angle between 2 vectors thread) Paul Hope's angle code ---------------------------------------------*/




//-------- headers etc ------- //---------------------------- #ifndef _IMATH_MAIN_H_HEADER_069389570 #define _IMATH_MAIN_H_HEADER_069389570

#include "../leakdetect.h"

#include <iostream>

using std::cout; using std::endl;

#include <math.h> //fpu maths #include <cassert> //assert #include <windows.h> //opengl needs windows (comment for non WIN32 platforms) #include <gl/gl.h> //opengl for drawing vectors etc (minimal, not important) #include "../myerror.h"

//---------------------------- //----------------------------

//---------------------------- //---------------------------- //alias/type/macro your favorites #define RANDOM_NUM im_random_num() #define RANDOM_CLAMP im_random_clamp()

//macroed settings #define _IVECTOR3_VERBOSE_NORMALISE_FAIL_

//---------------------------- //----------------------------

//---------------------------- //---------------------------- class ivector3; class float_lookuptable;

//---------------------------- //----------------------------

//---- constants ------------------- // // see imath.cpp for // constant definitions and comments //---------------------------------- extern const float cnf_epsilon; //"small" value (considered 0) extern const float pi; extern const float half_pi; extern const float two_pi; extern const float _pi_over_180; extern const float _180_over_pi;

//extern const ivector3 xaxis; //extern const ivector3 yaxis; //extern const ivector3 zaxis; //extern const ivector3 zero; //extern const ivector3 red; //extern const ivector3 green; //extern const ivector3 blue; //extern const ivector3 black; //extern const ivector3 cyan; //extern const ivector3 magenta; //extern const ivector3 yellow; extern const float_lookuptable sintable; extern const float_lookuptable costable; extern const float_lookuptable tantable;

//---------------------------- //----------------------------

//-- imath component headers -- //----------------------------- #include "imath_real2int.h" //need first by lut #include "imath_lut.h" //lookup tables #include "imath_core.h" //trig, sqrt, etc #include "imath_vector.h" //vector is needed by trace #include "imath_trace.h" //trace is needed by matrix #include "imath_mq.h" //matrix and quaternion #include "imath_box.h" //bounding boxess //---------------------------- //---------------------------- #endif

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/imath/imath.cpp] - (2,097 bytes)

/*---------------------------------------------
		
	Inline Math library : Constants implementation (cpp)
	(imath , im_)

* See Header file for more information

By Matt Barnett (see References)

---------------------------------------------*/


#include "imath.h"

//---- float constants -------- //----------------------------- //data ranges (according to msvc help) //a 4 byte float can hold 7 digits //an 8 byte double can hold 15 digits //a long double (10 bytes) can hold 19 digits //hence all constants match the precision //of the the type that stores them const float cnf_epsilon(0.0001f); //"small" value (considered 0) //pi constants //precalced often used pi values //theroy (radians) // // half_pi radians = 90 degrees // pi radians = 180 degrees // two_pi radians = 360 degeres const float pi(3.141592f); //(* See ref 1) const float half_pi(1.570796f); //(* See ref 1) const float two_pi(6.283185f); //(* See ref 1) const float _pi_over_180(0.0174532f); const float _180_over_pi(57.295779f);

//---------------------------- //----------------------------

//------ ivector3 constants ----- //------------------------------- extern const ivector3 xaxis(1.0,0.0,0.0); extern const ivector3 yaxis(0.0,1.0,0.0); extern const ivector3 zaxis(0.0,0.0,1.0); extern const ivector3 zero (0.0,0.0,0.0);

//a few colors extern const ivector3 red (1.0,0.0,0.0); extern const ivector3 green(0.0,1.0,0.0); extern const ivector3 blue (0.0,0.0,1.0); extern const ivector3 black(0.0,0.0,0.0);

extern const ivector3 cyan (0.0,1.0,1.0); extern const ivector3 magenta(1.0,0.0,1.0); extern const ivector3 yellow (1.0,1.0,0.0);

//---------------------------- //----------------------------

//-- lookup table constants -- //---------------------------- const float_lookuptable sintable(5000,0,two_pi,&sinf); const float_lookuptable costable(5000,0,two_pi,&cosf); const float_lookuptable tantable(5000,0,two_pi,&tanf);

//---------------------------- //----------------------------

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/imath/imath_core.h] - (2,551 bytes)

/*-----------------------------------------------------------------------
		
	Inline Math library : Non member function implementation
	
	* See imath.h for more information

By Matt Barnett (see References in imath.h) ------------------------------------------------------------------------*/


//-------- headers etc ------- //---------------------------- #ifndef _IMATH_CORE_IMP_HEADER_354766003 #define _IMATH_CORE_IMP_HEADER_354766003

//--- non member functions --- //---------------------------- // // some may seem silly stuff like // // inline float im_sin(float angle) { return sinf(angle) } // inline float im_sqrt(float val) { return sqrtf(val) } // // this are interfaces so that these functions can be replaced // with more efficient versions. (trig functions are replaced with // lookup tables) // //theroy (degrees & radians) // //to avoid confusion it is best _NOT_ to convert angle measures. //Sick with radians untill conversion to degrees is ABSOLUTELY nessesary //(try not to store degrees, throw them away if appropriate) //converts radians to degrees inline float im_r2d(float angle) { return (angle * _180_over_pi); }

//converts degrees to radians inline float im_d2r(float angle) { return (angle * _pi_over_180); }

//random number generation //seed with the generator (custom seed inline void im_random_seed(unsigned int seed) { srand( seed ); } //seed with time inline void im_random_seed_time() { im_random_seed( GetTickCount() ); }

//random number retrival functions //returns a float between 0 & 1 inline float im_random_num() { return ((float)rand()/(RAND_MAX+1)); }

//all based on im_random_num inline float im_random_num(float range) { return im_random_num() * range;} //returns a float between 0 & range inline float im_random_clamp() { return -1 + im_random_num() * 2; } //returns a float in the range -1.0f -> + 1.0f inline float im_random_clamp(float range) { return im_random_clamp() * range; } //returns a float between -range & +range //sqrt inline float im_sqrt(float in) { return sqrtf(in); }

inline float im_sin(float in) { //return sinf(in); return sintable.lookup(in); }

inline float im_cos(float in) { //return cosf(in); return costable.lookup(in); }

inline float im_acos(float in) { return acosf(in); }

inline float im_tan(float in) { //return tanf(in); return tantable.lookup(in); }

//---------------------------- //---------------------------- #endif

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/imath/imath_real2int.h] - (2,762 bytes)

/*-----------------------------------------------------------------------
		
	Inline Math library : Real to Integer conversion by Sree
	
	* See imath.h for more information

By Matt Barnett (see References in imath.h) ------------------------------------------------------------------------*/


#ifndef _IMATH_REAL2INT_IMP_HEADER_156858806791 #define _IMATH_REAL2INT_IMP_HEADER_156858806791

// Float/Double -> Int // // By Sree // // (from web article) // Sree's Real2Int // // There are quite a few ways to fix this. One of the best general conversion utilities I have is one // that Sree Kotay wrote. It's only safe to use when your FPU is in double-precision mode, so you have // to be careful about it if you're switching precision like above. It'll basically return '0' all the // time if you're in single precision. // // --- notes by matt --- // Somthing is wierd here // My lut class attempts to switch to single precision mode // but this function must still be working, or (i think) the // core im_ functions would all fall down. // // (I've recently discovered that this discussion bears a lot of resemblance to Chris Hecker's article // on the topic, so be sure to read that if you can't figure out what I'm saying.) // This function is basically an ANSI C compliant conversion -- it always chops, always does the right thing, // for positive or negative inputs. // // //-- performace notes by matt -- // // the blurb states that (int)somefloat casts // are very slow. My lookup table class // didnt seem to show that(the cast was no slower that this function), // but i have left this function in, and the class uses it. // (i guess it may be noticable for doubles (which i am avoiding) // flipcode threads have also mentioned (somewhere) float->int // conversions as being slow. // typedef double lreal; typedef float real; typedef unsigned long uint32; typedef long int32;

const lreal _double2fixmagic = 68719476736.0*1.5; //2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor const int32 _shiftamt = 16; //16.16 fixed point representation, #if BigEndian_ #define iexp_ 0 #define iman_ 1 #else #define iexp_ 1 #define iman_ 0 #endif //BigEndian_ //-------------------- // im_real2int(double) //-------------------- inline int32 im_real2int(lreal val) { #if DEFAULT_CONVERSION return val; #else val = val + _double2fixmagic; return ((int32*)&val)[iman_] >> _shiftamt; #endif }

//------------------- // im_real2int(float) //------------------- inline int32 im_real2int(real val) { #if DEFAULT_CONVERSION return val; #else return im_real2int ((lreal)val); #endif }

#endif

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/imath/imath_box.h] - (4,894 bytes)

/*-----------------------------------------------------------------------
		
	Inline Math library : Bounding box implementation (header)
	
	* See imath.h for more information

By Matt Barnett (see References in imath.h) ------------------------------------------------------------------------*/


/*------------------------------------------------------------------------------------ ibox3 class

------------ Description ------------ Bounding box class based for imath library

This class performs intersection testing, not "collision detection". (collisions and intersections are similar, and you need intersections to implement collisions) ------- General -------

Everything is public in this class (like the other imath components) This class has some non inlined functions

Orientation -----------

To orient the bbox simply fiddle with the quaternion

eg: iquaternion4 somerotation;

//create somerotation with a suitable rotation object.GetQuaternion().multiply(somerotation);



---------------------------------------------*/


#ifndef _IBOX3_HEADER_ #define _IBOX3_HEADER_

//#define _IBOX3_TESTWITH_TEAPOT #ifdef _IBOX3_TESTWITH_TEAPOT #include <gl/glut.h> #else #include <gl/gl.h> #include <gl/glu.h> #endif

class ibox3 { public: //assigning const ibox3 &operator=(const ibox3 &rhs) { center = rhs.center; extents = rhs.extents; pos = rhs.pos; quat = rhs.quat; bas = rhs.bas;

return *this; } //------- construction etc --- //---------------------------- //constructor ibox3() { center = zero; extents.set(0.01f,0.01f,0.01f); }

//default constructor ibox3(ivector3 &cextents,ivector3 &rotationcenter) { center = rotationcenter; extents = cextents; }

//copy constructor ibox3(const ibox3 ©) { center = copy.center; extents = copy.extents; pos = copy.pos; quat = copy.quat; bas = copy.bas; }

//destructor ~ibox3() {

}

//---------------------------- //---------------------------- //------ public attributes --- //---------------------------- //you can only change pos/angles directly //position, or center of box ivector3 pos; //position of box imatrix16 rm; //rotation matrix (made from quaternion as nessesary) iquaternion4 quat; // //dont fuck with the basis outside this class (copy) inline ibasis9 getBasis() { return bas; } //ditto for extents(copy) inline ivector3 getExtents() { return extents; } //ditto for center(copy) inline ivector3 getCenter() { return center; }

//---------------------------- //---------------------------- const bool intersect(const ibox3 &b) const; //=========================================== //inline bool intersectSphere(const ibox3 &b) const // // true for bounding sphere collision detection // between this and b. optimised to no sqrts. // // // when inlined this give as big speedup // when we need to call it alot of times // (its an quick exit from collision) //============================================*/ //const bool intersectSphere(const ibox3 &b) const; inline bool intersectSphere(const ibox3 &b) const {

//float aradsqr = killed tempories //float bradsqr = //float radsqr = aradsqr + bradsqr; //float arad = extents.length(); //float brad = b.extents.length(); //float rad = arad + brad; ivector3 areal = pos; ivector3 breal = b.pos;

ivector3 temp;

//because bas can be anything //there doesnt seem to be a //good way to simplfy here temp = bas.x;temp.multiply(center.x);areal.add(temp); temp = bas.y;temp.multiply(center.y);areal.add(temp); temp = bas.z;temp.multiply(center.z);areal.add(temp);

temp = b.bas.x;temp.multiply(b.center.x);breal.add(temp); temp = b.bas.y;temp.multiply(b.center.y);breal.add(temp); temp = b.bas.z;temp.multiply(b.center.z);breal.add(temp);

temp = breal - areal;

//as with most of my maths, i dont know why we must *2 //here. its because the two lengthsqr's on the one side are //too small if ( temp.lengthsqr() < (extents.lengthsqr() + b.extents.lengthsqr() ) *2 ) return true; else return false;

}

const void gldraw(); //draws the oobb (bounding box) (shows what will/should be intersected with) const void gldrawSphere(); //draws the bounding sphere const void update() { rm.makefromQuaternion(quat); bas = rm.getBasis(); }

protected: ibasis9 bas; //ortho basis ivector3 extents; //the extents of the box are constant ivector3 center; //center offset };

#endif

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/imath/imath_box.cpp] - (8,873 bytes)

/*-----------------------------------------------------------------------
		
	Inline Math library : Bounding box implementation (cpp)
	
	* See imath_box.h for more information

By Matt Barnett (see References in imath.h) ------------------------------------------------------------------------*/


#include "imath.h"

/*=========================================== const void ibox3::gldrawSphere()

//very dirty way of display the box ============================================*/


const void ibox3::gldrawSphere() { GLUquadricObj* qobj; qobj = gluNewQuadric();

gluQuadricDrawStyle(qobj,GLU_SILHOUETTE);

ivector3 areal = pos; ivector3 temp;

temp = bas.x;temp.multiply(center.x);areal.add(temp); temp = bas.y;temp.multiply(center.y);areal.add(temp); temp = bas.z;temp.multiply(center.z);areal.add(temp);

glPushMatrix(); glTranslatef(areal.x,areal.y,areal.z); gluSphere(qobj, extents.length() ,9,9);

glPopMatrix();

gluDeleteQuadric(qobj); }

/*=========================================== const void ibox3::gldraw()

//very dirty way of display the box ============================================*/
const void ibox3::gldraw() { //pos.gldraw(); //draw the box ivector3 h,l;

h.add(extents); l.subtract(extents);

//could do my own rotation around it //from here. glPushMatrix(); glTranslatef(pos.x,pos.y,pos.z);

update();

//push and add the quaternion matrix glPushMatrix(); glMultMatrixf(rm.m);

glTranslatef(center.x,center.y,center.z); //draw test object here #ifdef _IBOX3_TESTWITH_TEAPOT glEnable(GL_LIGHTING); glRotatef(90,1.0,0.0,0.0); //draw test object here glDisable(GL_LIGHTING); #endif glDisable(GL_TEXTURE_2D);

//draw the bow glBegin(GL_LINE_LOOP); //top loop glVertex3f(h.v[0],h.v[1],h.v[2]); glVertex3f(l.v[0],h.v[1],h.v[2]); glVertex3f(l.v[0],l.v[1],h.v[2]); glVertex3f(h.v[0],l.v[1],h.v[2]); glEnd(); glBegin(GL_LINE_LOOP); //bottom loop glVertex3f(h.v[0],h.v[1],l.v[2]); glVertex3f(l.v[0],h.v[1],l.v[2]); glVertex3f(l.v[0],l.v[1],l.v[2]); glVertex3f(h.v[0],l.v[1],l.v[2]); glEnd(); glBegin(GL_LINES); //the lines inbetween the loops glVertex3f(h.v[0],h.v[1],h.v[2]);glVertex3f(h.v[0],h.v[1],l.v[2]); glVertex3f(l.v[0],h.v[1],h.v[2]);glVertex3f(l.v[0],h.v[1],l.v[2]); glVertex3f(l.v[0],l.v[1],h.v[2]);glVertex3f(l.v[0],l.v[1],l.v[2]); glVertex3f(h.v[0],l.v[1],h.v[2]);glVertex3f(h.v[0],l.v[1],l.v[2]); glEnd(); glBegin(GL_LINES); glColor3f(1.0f,0.0,0.0);glVertex3f(-0.5f,0.0,0.0);glVertex3f(1.2f,0.0,0.0); glColor3f(0.0,1.0f,0.0);glVertex3f(0.0,-0.5f,0.0);glVertex3f(0.0,1.2f,0.0); glColor3f(0.0,0.0,1.0f);glVertex3f(0.0,0.0,-0.5f);glVertex3f(0.0,0.0,1.2f); glEnd();

glPopMatrix();

//pop off the quat matrix //and draw the basis bas.gldraw();

glBegin(GL_LINES); glColor3f(1.0f,0.0,0.0);glVertex3f(-0.5f,0.0,0.0);glVertex3f(1.2f,0.0,0.0); glColor3f(0.0,1.0f,0.0);glVertex3f(0.0,-0.5f,0.0);glVertex3f(0.0,1.2f,0.0); glColor3f(0.0,0.0,1.0f);glVertex3f(0.0,0.0,-0.5f);glVertex3f(0.0,0.0,1.2f); glEnd(); glPopMatrix();

}

/*=========================================== const bool ibox3::intersect(const ibox3 &b)

true for bounding box collision detection between this and b (seperating axis test based on gamasutra article) ============================================*/


const bool ibox3::intersect(const ibox3 &b) const { //<mat2002> //mat2002 added offset for center // //we must pass the real center to the intersect test, adjusted for the pivot/center //to do this, we need to transform the position by the center with respect to the basis //(this just means moving it from its position to its center along its basis) ivector3 areal = pos; ivector3 breal = b.pos;

ivector3 temp;

temp = bas.x;temp.multiply(center.x);areal.add(temp); temp = bas.y;temp.multiply(center.y);areal.add(temp); temp = bas.z;temp.multiply(center.z);areal.add(temp);

temp = b.bas.x;temp.multiply(b.center.x);breal.add(temp); temp = b.bas.y;temp.multiply(b.center.y);breal.add(temp); temp = b.bas.z;temp.multiply(b.center.z);breal.add(temp);

//works without centers //ivector3 areal = (pos); //ivector3 breal = (b.pos); ivector3 v = breal - areal; //translation, in parent frame ivector3 T( bas.x.dot(v),bas.y.dot(v),bas.z.dot(v) ); //translation in A's frame float R[3][3]; //rotation matrix float ra,rb,t;

int i,k;

//calculate rotation matrix R[][] R[0][0] = bas.x.dot(b.bas.x); R[0][1] = bas.x.dot(b.bas.y); R[0][2] = bas.x.dot(b.bas.z);

R[1][0] = bas.y.dot(b.bas.x); R[1][1] = bas.y.dot(b.bas.y); R[1][2] = bas.y.dot(b.bas.z);

R[2][0] = bas.z.dot(b.bas.x); R[2][1] = bas.z.dot(b.bas.y); R[2][2] = bas.z.dot(b.bas.z);



// for (i=0;i<3;i++) // for (k=0;k<3;k++) // printf("R[%i][%i] %f\n",i,k,R[i][k]);

//a's basis vectors for (i=0;i<3;i++) { ra = extents[i]; //ra = extents[i]; //mat2002 rb = b.extents[0] * fabs(R[i][0]) + b.extents[1] * fabs(R[i][1]) + b.extents[2] * fabs(R[i][2]); t = fabs(T[i]); if (t > ra + rb) { #ifdef VERBOSE_SEPERATION printf("a basis %i seperates a and b\n",i); #endif

return false; } }

//safe to here //b's basis vectors for (k=0;k<3;k++) { ra = extents[0] * fabs(R[0][k]) + extents[1] * fabs(R[1][k]) + extents[2] * fabs(R[2][k]); rb = b.extents[k]; t = fabs(T[0] * R[0][k] + T[1] * R[1][k] + T[2] * R[2][k]); if (t > ra + rb) { #ifdef VERBOSE_SEPERATION printf("b basis %i seperates a and b\n",k); #endif

return false; } } //9 cross products //all the a0s ra = extents[1] * fabs(R[2][0]) + extents[2] * fabs(R[1][0]); rb = b.extents[1] * fabs(R[0][2]) + b.extents[2] * fabs(R[0][1]); t = fabs(T[2] * R[1][0] - T[1] * R[2][0]); if (t > ra + rb) { #ifdef VERBOSE_SEPERATION printf("a0*b0 seperates a and b\n",k); #endif return false; } ra = extents[1] * fabs(R[2][1]) + extents[2] * fabs(R[1][1]); rb = b.extents[0] * fabs(R[0][2]) + b.extents[2] * fabs(R[0][0]); t = fabs(T[2] * R[1][1] - T[1] * R[2][1]); if (t > ra + rb) {

#ifdef VERBOSE_SEPERATION printf("a0*b1 seperates a and b\n",k); #endif

return false; }

ra = extents[1] * fabs(R[2][2]) + extents[2] * fabs(R[1][2]); rb = b.extents[0] * fabs(R[0][1]) + b.extents[1] * fabs(R[0][0]); t = fabs(T[2] * R[1][2] - T[1] * R[2][2]); if (t > ra + rb) {

#ifdef VERBOSE_SEPERATION printf("a0*b2 seperates a and b\n",k); #endif

return false; }

//all the a1s ra = extents[0] * fabs(R[2][0]) + extents[2] * fabs(R[0][0]); rb = b.extents[1] * fabs(R[1][2]) + b.extents[2] * fabs(R[1][1]); t = fabs(T[0] * R[2][0] - T[2] * R[0][0]); if (t > ra + rb) {

#ifdef VERBOSE_SEPERATION printf("a1*b0 seperates a and b\n",k); #endif

return false; }

ra = extents[0] * fabs(R[2][1]) + extents[2] * fabs(R[0][1]); rb = b.extents[0] * fabs(R[1][2]) + b.extents[2] * fabs(R[1][0]); t = fabs(T[0] * R[2][1] - T[2] * R[0][1]); if (t > ra + rb) { #ifdef VERBOSE_SEPERATION printf("a1*b1 seperates a and b\n",k); #endif return false; }

ra = extents[0] * fabs(R[2][2]) + extents[2] * fabs(R[0][2]); rb = b.extents[0] * fabs(R[1][1]) + b.extents[1] * fabs(R[1][0]); t = fabs(T[0] * R[2][2] - T[2] * R[0][2]); if (t > ra + rb) { #ifdef VERBOSE_SEPERATION printf("a1*b2 seperates a and b\n",k); #endif return false; }

//all the a2s

ra = extents[0] * fabs(R[1][0]) + extents[1] * fabs(R[0][0]); rb = b.extents[1] * fabs(R[2][2]) + b.extents[2] * fabs(R[2][1]); t = fabs(T[1] * R[0][0] - T[0] * R[1][0]); if (t > ra + rb) { #ifdef VERBOSE_SEPERATION printf("a2*b0 seperates a and b\n",k); #endif return false; }

ra = extents[0] * fabs(R[1][1]) + extents[1] * fabs(R[0][1]); rb = b.extents[0] * fabs(R[2][2]) + b.extents[2] * fabs(R[2][0]); t = fabs(T[1] * R[0][1] - T[0] * R[1][1]); if (t > ra + rb) { #ifdef VERBOSE_SEPERATION printf("a2*b1 seperates a and b\n",k); #endif return false; }

ra = extents[0] * fabs(R[1][2]) + extents[1] * fabs(R[0][2]); rb = b.extents[0] * fabs(R[2][1]) + b.extents[1] * fabs(R[2][0]); t = fabs(T[1] * R[0][2] - T[0] * R[1][2]); if (t > ra + rb) { #ifdef VERBOSE_SEPERATION printf("a2*b2 seperates a and b\n",k); #endif return false; }

//disturbed laughter return true; }

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/imath/imath_trace.h] - (7,147 bytes)

/*-----------------------------------------------------------------------
		
	Inline Math library : Ray and Plane implementation
	
	* See imath.h for more information

By Matt Barnett (see References in imath.h) ------------------------------------------------------------------------*/


#ifndef _IMATH_TRACE_IMP_HEADER_529081235 #define _IMATH_TRACE_IMP_HEADER_529081235

/*--------------------------------------------- Raytracing/linetracing and collision detection

iray6 iplane6

------- classes ------- iray6 iplane6

------ design ------

* a ray is defined a point(position) and a normalised vector(direction) * a plane is defined as abcd ---------------------------------------------*/


//-------------- iplane4 ------------ // plane class //------------------------------------ class iplane4 { public: ivector3 norm; float d; //-------------- operators --- //---------------------------- //return types according to Effective C++ 2e (see ref 8) //assignment inline const iplane4 &operator=(const iplane4 &right) { if (&right != this) { //check for self assign norm = right.norm; //copy right to left d = right.d; } return *this; //enables x = y = z }

//---------------------------- //---------------------------- //------- construction etc --- //---------------------------- //inlined ctor inline iplane4() { //no need here //vectors construct themselves adequetly } //inlined ctor inline iplane4(const float in_d,const ivector3 &in_norm) { norm = in_norm; d = in_d; } //inlined dtor(unnessesary) inline ~iplane4() {} //---------------------------- //---------------------------- //--------- functions -------- //---------------------------- //sets components //dumps the componets (debug aid) inline void cdump(const char *caption) const { norm.cdump("iplane4 norm = "); printf("iplane4 d = %f\n",d); } //draw's the plane (debug aid) //plane extend to infinity, //so the client decideds how far that is (length) //(not optimised for drawing lots of planes, which may be needed later) //creates a quad from the plane's normal //much like a particle is generated7 inline void gldraw(float length,ivector3 rgbcolor) { //some good practice at vector math here //we need to create an up vector and a left vector //from the normal of the plane //both are perpendicular to the norm, so crossproducts //are an easy way to do this (allthought there may //be a faster solution) //create any vector perp to the normal //(the operand xaxis could be any vector) ivector3 left = norm.cross(xaxis); left.normalise(); //the up vector needs to be perp to both the norm and the left vector ivector3 up = norm.cross(left); up.normalise(); //size it according to length param left.multiply(length); up.multiply(length);

//pos is a point on the plane ivector3 pos = (norm * d); ivector3 temp = pos;

glDisable(GL_LIGHTING);

glBegin(GL_LINES);

glColor3fv(red.v);

pos.glplot();temp = pos + norm; temp.glplot(); glColor3fv(cyan.v); pos.glplot();temp = pos + left; temp.glplot();

glColor3fv(yellow.v);

pos.glplot();temp = pos + up; temp.glplot();

glEnd();

glColor3fv(rgbcolor.v);

glBegin(GL_QUADS); glVertex3f(pos.x + left.x + up.x,pos.y + left.y + up.y,pos.z + left.z + up.z); glVertex3f(pos.x - left.x + up.x,pos.y - left.y + up.y,pos.z - left.z + up.z); glVertex3f(pos.x - left.x - up.x,pos.y - left.y - up.y,pos.z - left.z - up.z); glVertex3f(pos.x + left.x - up.x,pos.y + left.y - up.y,pos.z + left.z - up.z); glEnd(); } //---------------------------- //---------------------------- };

//-------------- iray ------------ // // ray class //------------------------------------ class iray6 { public: ivector3 pos; //treated as a position ivector3 dir; //treated as a direction (magnitude represents light/strength?)

//-------------- operators --- //---------------------------- //return types according to Effective C++ 2e (see ref 8) //assignment //the comilier should be able to generate this (its only member copy) inline const iray6 &operator=(const iray6 &right) { if (&right != this) { //check for self assign dir = right.dir; //copy right to left pos = right.pos; } return *this; //enables x = y = z }

//---------------------------- //---------------------------- //------- construction etc --- //---------------------------- //inlined ctor inline iray6() { pos.set(0,0,0); //we'll start all rays at 0,0,0 dir.set(0,0,1.0); //pointing up in the air } //inlined ctor(initalises to pos,dir) inline iray6(const ivector3 &in_pos,const ivector3 &in_dir) { pos = in_pos; dir = in_dir; } //inlined cpy ctor //the comilier generates this (its only member copy) //inlined dtor(unnessesary) inline ~iray6() {} //---------------------------- //---------------------------- //--------- functions -------- //---------------------------- inline float intersect(class iplane4 &with) { float cosAlpha = dir.dot( with.norm ); //dot product of ray's direction vector (normalised) and plane's normal vector (normalised) ivector3 diff = (with.norm * with.d) - pos; //vector from plane origin to ray origin float deltaD = diff.dot(with.norm); //dot product of above and plane's normal //deltaD is the length of the shortest line to the point return deltaD/cosAlpha; }

//dumps the componets (debug aid) inline void cdump(const char *caption) const { pos.cdump("ray pos = "); dir.cdump("ray dir = "); } //draw's the ray (debug aid) //rays extend to infinity, //so the client decideds how far that is (length) //(not optimised for drawing lots of rays, which may be needed later) inline void gldraw(float length,const ivector3 &startcol,const ivector3 &endcol) const { ivector3 endpos = dir; endpos.multiply(length); endpos.add(pos);

glDisable(GL_LIGHTING); //glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); glBegin(GL_LINES); glColor3fv(startcol.v); pos.glplot(); glColor3fv(endcol.v); endpos.glplot(); glEnd(); } inline void gldraw(float length) const { ivector3 endpos = dir; endpos.multiply(length); endpos.add(pos); glDisable(GL_LIGHTING); glBegin(GL_LINES); pos.glplot(); endpos.glplot(); glEnd(); } //---------------------------- //---------------------------- };



#endif

Currently browsing [matnn_cotd.zip] (123,598 bytes) - [matnn_cotd/code/imath/imath_vector.h] - (10,827 bytes)

/*-----------------------------------------------------------------------
		
	Inline Math library : Vector Matrix and Quaternion implementation
	
	* See imath.h for more information

By Matt Barnett (see References in imath.h) ------------------------------------------------------------------------*/


#ifndef _IMATH_V_IMP_HEADER_4778097634v #define _IMATH_V_IMP_HEADER_4778097634v

//-------------- ivector3 ------------ // // simple 3d vector with 3 components // (there is no 2d version, use this) //------------------------------------ //enum for auto constructing some vector types //if you want to contruct a random vector //or and random normalised vector etc. enum ivector3_constructor_enum { IVECTOR3_RANDOM , IVECTOR3_RANDOM_NORM };

class ivector3 { public: //three floats are the data union { float v[3]; struct { float x, y, z; }; };

//-------------- operators --- //---------------------------- //return types according to Effective C++ 2e (see ref 8) inline const ivector3 operator-(const ivector3 &right) const { return ivector3(x - right.x,y - right.y,z - right.z); } inline const ivector3 operator+(const ivector3 &right) const { return ivector3(x + right.x,y + right.y,z + right.z); } inline const ivector3 operator*(const ivector3 &right) const { return ivector3(x * right.x,y * right.y,z * right.z); } inline const ivector3 operator/(const ivector3 &right) const { return ivector3(x / right.x,y / right.y,z / right.z); }

inline const ivector3 operator*(const float scalar) const { return ivector3(x * scalar,y * scalar,z * scalar); } inline const ivector3 operator/(const float scalar) const { return ivector3(x / scalar,y / scalar,z / scalar); }

//void operators inline void operator-=(const ivector3 &right) { subtract(right); } inline void operator+=(const ivector3 &right) { add(right); }

//assignment inline ivector3 &operator=(const ivector3 &right) { if (&right != this) { //check for self assign x = right.x; //copy right to left y = right.y; z = right.z; } return *this; //enables x = y = z }

inline float operator[](int subscript) const { assert( subscript < 3 && subscript >= 0 ); return v[subscript]; } //---------------------------- //---------------------------- //------- construction etc --- //---------------------------- //inlined ctor(initalises to 0,0,0) inline ivector3() { set(0,0,0); } //inlined ctor(initalises to x,y,z) inline ivector3(const float setx,const float sety,const float setz) { set(setx,sety,setz); } //ctor for a random normalised vector explicit inline ivector3(ivector3_constructor_enum inv_ce) { if (inv_ce == IVECTOR3_RANDOM_NORM) { randomize(1.0); normalise(); } else if (inv_ce == IVECTOR3_RANDOM) randomize(1.0); }

//inlined dtor(unnessesary) inline ~ivector3() {} //---------------------------- //---------------------------- //--------- void functions --- //---------------------------- //sets vector components inline void set(const float setx,const float sety,const float setz) { x = setx; y = sety; z = setz; } //sets z == 0 inline void make2d() { z = 0; }

//dumps the vectors componets (debug aid) inline void cdump(const char *caption) const { cout << caption << x << " " << y << " " << z << endl; } //draw O -> vector (debug aid) inline void gldraw() const { glDisable(GL_LIGHTING); glBegin(GL_LINES); glVertex3f(0.0,0.0,0.0); glVertex3fv(v); glEnd(); } //plot the vector (debug aid) inline void glplot() const { glVertex3fv(v); }

//multiplies this by scalar inline void multiply(const float scalar) { x *= scalar; y *= scalar; z *= scalar; } //multiplies this by multiply inline void multiply(const ivector3 &multiply) { x *= multiply.x; y *= multiply.y; z *= multiply.z; }

//divides this by scalar inline void divide(const float scalar) { x /= scalar; y /= scalar; z /= scalar; } //divides this by divide inline void divide(const ivector3 ÷) { x /= divide.x; y /= divide.y; z /= divide.z; } //adds add to this inline void add(const ivector3 &add) { x += add.x; y += add.y; z += add.z; } //subtracts subtract from this inline void subtract(const ivector3 &subtract) { x -= subtract.x; y -= subtract.y; z -= subtract.z; }

//multiplies this by matrix multiply //inline void multiply(imatrix16 &multiply) //{ // //} //normalise inline void normalise() { const float n = length(); if (!n) { #ifdef _IVECTOR3_VERBOSE_NORMALISE_FAIL_ printf("ivector3::MATH_ERROR ( normalise failed(), length = 0 )\n"); cdump("vector "); #endif

return; }

x /= n; y /= n; z /= n; } //randomises each component inline void randomize(float range) { x = im_random_clamp(range); y = im_random_clamp(range); z = im_random_clamp(range); } //makes "this" the normal of the three vectors inline void makeTriangleNormal(const ivector3 &a,const ivector3 &b,const ivector3 &c) { ivector3 ab,ac;

ab = b - a; ac = c - a;

ivector3 cross = ab.cross(ac); cross.normalise();

*this = cross; } //---------------------------- //---------------------------- //-------------- functions --- //---------------------------- //crossproduct inline const ivector3 &cross(const ivector3 &in) const { ivector3 out; out.x = y*in.z - z*in.y; out.y = z*in.x - x*in.z; out.z = x*in.y - y*in.x; return out; } //length/norm inline float length() const { float a = (x*x)+(y*y)+(z*z);

if (a <= 0) { #ifdef _IVECTOR3_VERBOSE_LENGTH_FAIL_ printf("ivector3::MATH_ERROR ( length failed, x*x+y*y+z*z <= 0 )\n"); cdump("vector "); printf("x*x+y*y+z*z = %f\n",a); #endif

return 0; }

return im_sqrt(a); } //length/norm inline float lengthsqr() const { float a = (x*x)+(y*y)+(z*z);

if (a <= 0) { #ifdef _IVECTOR3_VERBOSE_LENGTH_FAIL_ printf("ivector3::MATH_ERROR ( length failed, x*x+y*y+z*z <= 0 )\n"); cdump("vector "); printf("x*x+y*y+z*z = %f\n",a); #endif

return 0; }

return a; } //dotproduct inline float dot(const ivector3 &in) const { return x*in.x + y*in.y + z*in.z; } //angle between this and in // //inline float angle(const ivector3 &in) const //{ // float tdotin,theta; // // tdotin = dot(in); //dot product // // float li; // li = in.length(); // // theta = tdotin / (length() * li); //lengths // theta = (float)im_acos(theta); //inverse im_cos // // return theta; //return theta in radians //} inline float cangle(const ivector3 &in) const { return ( x*in.x + y*in.y + z*in.z ) / ( (length() )*(in.length() ) ); }

//matrix based angle axis rotation (radians) //matrix isnt stored //usefull to rotate a point/vector about an axis inline void rotate(const float angle,const ivector3 &axis) { //componets of rotation axis //float a = axis.x; //float b = axis.y; //float c = axis.z; //get the matrix float f1cos,fasin,fbsin,fcsin; //fcos = im_cos(angle); //im_cos of angle //fsin = im_sin(angle); //im_sin of angle f1cos = (1 - im_cos(angle) ); //1 - im_cos of angle fasin = (axis.x * im_sin(angle) ); //a * im_sin of angle fbsin = (axis.y * im_sin(angle) ); //b * im_sin of angle fcsin = (axis.z * im_sin(angle) ); //c * im_sin of angle //m[0] = a*a*f1cos + fcos; //m[1] = a*b*f1cos - fcsin; //m[2] = a*c*f1cos + fbsin; //m[3] = a*b*f1cos + fcsin; //m[4] = b*b*f1cos + fcos; //m[5] = b*c*f1cos - fasin; //m[6] = a*c*f1cos - fbsin; //m[7] = b*c*f1cos + fasin; //m[8] = c*c*f1cos + fcos; ivector3 out;

out.x = x * (axis.x * axis.x * f1cos + im_cos(angle) ) + y * (axis.x * axis.y * f1cos - fcsin) + z * (axis.x * axis.z * f1cos + fbsin); out.y = x * (axis.x * axis.y * f1cos + fcsin) + y * (axis.y * axis.y * f1cos + im_cos(angle) ) + z * (axis.y * axis.z * f1cos - fasin); out.z = x * (axis.x * axis.z * f1cos - fbsin) + y * (axis.y * axis.z * f1cos + fasin) + z * (axis.z * axis.z * f1cos + im_cos(angle) );

x = out.x; y = out.y; z = out.z;

} //---------------------------- //---------------------------- };

//------ ivector3 constants ----- //------------------------------- const ivector3 xaxis(1.0,0.0,0.0); const ivector3 yaxis(0.0,1.0,0.0); const ivector3 zaxis(0.0,0.0,1.0); const ivector3 zero (0.0,0.0,0.0);

//a few colors const ivector3 red (1.0,0.0,0.0); const ivector3 green(0.0,1.0,0.0); const ivector3 blue (0.0,0.0,1.0); const ivector3 black(0.0,0.0,0.0);

const ivector3 cyan (0.0,1.0,1.0); const ivector3 magenta(1.0,0.0,1.0); const ivector3 yellow (1.0,1.0,0.0);

//---------------------------- //---------------------------- //-------------- ibasis9 ------ // // just for storing and drawing // orthonominal(??) bases or axes // // there is no clever shit here making // sure that the vectors remain perpendicular // this is just for storage of 3 vectors. class ibasis9 { public: //three vectors are the data ivector3 x,y,z;

ibasis9::ibasis9(const ivector3 &inx,const ivector3 &iny,const ivector3 &inz) { x = inx; y = iny; z = inz; } ibasis9::ibasis9() { x = xaxis; y = yaxis; z = zaxis; }

//just normalises each vector to save some typing inline void normalise() { x.normalise(); y.normalise(); z.normalise(); }

//draws the basis (debug aid) inline void gldraw() const { glDisable(GL_LIGHTING); glBegin(GL_LINES); glColor3fv(cyan.v); glVertex3fv(zero.v);glVertex3fv(x.v); glColor3fv(magenta.v);glVertex3fv(zero.v);glVertex3fv(y.v); glColor3fv(yellow.v); glVertex3fv(zero.v);glVertex3fv(z.v); glEnd(); } };

//---------------------------- //---------------------------- #endif

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.