#ifndef TIMEDHOP_H_INCLUDED
#define TIMEDHOP_H_INCLUDED
/**
* \brief How to add a custom action into mvWorld system
*
* To add new classes describing how bodies should behave or act, we build a sub
* class of mvBaseAction and its corresponding loader (factory),
* mvBaseActionLoader.
*
* The programmer must implement three virtual functions if he/she wants to use
* customable mvAction class. To retrive variables from your custom
* action class via the mvMotionAI library, implement the superclass
* set/getParameter(ifv)() functions that are needed.
*
* 1. virtual bool bodyOp(mvBehaviourResultPtr resultMod) of the derived
* mvBaseAction class:
*
* - Via the parameter resultMod, we can set the possible future velocity or a
* steering force to the body. More importantly EVERY pointers and references
* is READ-ONLY (const), expect for mvBaseActionPtr & mvBehaviourResultPtr.
* This is to keep the changes within the system isolated. This function is
* called for every action instance within the system per mvWorldStep,
* i.e. if 5 mvBodies have the 7 copies of same mvBaseAction, then this
* function might be called up to 35 times.
*
* 2. virtual bool groupOp(mvGroupBehaviourResultPtr groupBehMod) of the derived
* mvBaseAction class:
*
* - This is the user defined method for group interactions (mvGroupBehaviours)
* with other mvBody within mvWorld system. The big difference between the
* bodyOp & groupOp is the latter has READ and WRITE access to mvWorld objects
* in the system. Therefore this function can create new objects & change
* variables of other classes.
* This function is used together with the mvGroupBehaviour object.
* mvGroupBehaviours provide a shared variable area to all multiple bodies
* using a top-down approach. Types of behaviours suitable for group
* behaviours are boids, squadarons and a game of tag between many bodies.
*
* However, this function is called far less, i.e. for a mvGroupBehaviour's
* associated group node per a mvWorldStep, so once for a group per every
* instance of mvGroupBehaviour in an instance of mvWorld.
*
* 3. virtual mvBaseActionPtr operator()(mvNewBaseActionInfo& actionQuery) of the
* derived mvBaseActionLoader class:
*
* - This function acts a factory creating new instance of any action
* as long as the instance is returning as a mvBaseAction pointer.
* The parameter actionQuery is used to specialise the new object
* for various purposes. Through querying the actionQery instance,
* we can create different objects for every given situation;
* we can use the same 'key' to create different behaviours.
*
* The situations when an action is created:
* 1. for an individual body or private action instance
* - bool isNewPrivateBehaviour() const
* 2. a global behaviour which can be used by any body in the system
* - bool isNewGlobalBehaviour() const
* 3. a starter/(main node) group behaviour (has many groups, has many members
* (indirectly), 1 default action)
* - bool isNewGroupBehaviour() const
* 4. a group behaviour group node (belongs to 1 group behavour, has 1 group,
* has many members, has 1 action)
* - bool isNewGroupBehaviourGroupNode() const
* 5. a group member of a group node. (has 1 member, belong to 1 group)
* - bool isNewGroupMemberNode() const
*
* Note that situation 4 & 5 are different as they have access to other
* mvBaseAction pointers. The programmer can use the values
* of the main node's or a group node's action classes for initialisation,
* updating node values, etc.
*/
#include <mv/mvMotionAI.h>
class TimedHop : public mvBaseAction
{
public:
TimedHop();
/**
* \brief this is user defined method for a single body
* interacting with the mvWorld system objects such as mvBody, mvObstacle,
* and mvWaypoints.
*/
virtual bool bodyOp(mvBehaviourResultPtr resultMod);
/**
* \brief this is user defined method for group interaction with other
* mvBody mvWorld system.
*/
virtual bool groupOp(mvGroupBehaviourResultPtr groupBehMod);
~TimedHop();
};
class TimedHopLoader : public mvBaseActionLoader
{
public:
TimedHopLoader();
virtual mvBaseActionPtr operator()(mvNewBaseActionInfo& actionQuery);
~TimedHopLoader();
};
#endif // TIMEDHOP_H_INCLUDED
#include "TimedHop.h"
#include <iostream> // not actually used by this class
TimedHop::TimedHop()
/* NOTE : you should use a different mvOptionEnum enum than
* existing mvBaseAction classes
*/
: mvBaseAction(MV_NON_BODY_TYPE)
{
}
bool TimedHop::bodyOp(mvBehaviourResultPtr resultMod)
{
if (!resultMod)
{
return false;
}
mvIndex currentTime = (mvIndex) (
resultMod->getElapsedSystemTime() +resultMod->getTimeStep());
if (currentTime % 2 == 0)
{
resultMod->setVelocity(mvVec3(0,4,0),MV_DIRECTIONAL_MOTION);
}
else
{
resultMod->setVelocity(mvVec3(0,-4,0),MV_DIRECTIONAL_MOTION);
}
return true;
}
bool TimedHop::groupOp(mvGroupBehaviourResultPtr groupBehMod)
{
return false;
}
TimedHop::~TimedHop()
{
}
TimedHopLoader::TimedHopLoader()
{
}
mvBaseActionPtr TimedHopLoader::operator()(mvNewBaseActionInfo& actionQuery)
{
return new TimedHop();
}
TimedHopLoader::~TimedHopLoader()
{
}
/**
* \brief tutorial3 :
* How to implement custom behaviours to the mvMotionAI system
*
* Copyright (c) 2005 - 2006 David Young.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <GL/glut.h>
#include <iostream>
#include "../Camera.h"
#include <cstdlib>
/*
* Step 1.0 : include header to use library
*/
#include <mv/mvMotionAI.h>
/*
* Step 1.1 include custom action class i.e TimedHop
*/
#include "TimedHop.h"
static float left = -1.0;
static float right = 1.0;
static float bottom = -1.0;
static float top = 1.0;
static float nearValue = 1.0;
static float farValue = 100.0;
static float lightPos1[] = {5.0,0.0,5.0,0.0};
static Camera worldCam;
static int windowHeight = 500;
static int windowWidth = 480;
static const float MIN_FRAME_PERIOD = 1.0f/60.0f * 1000.0f;
static float previousTime;
static float elapsedTime = 0.0;
static long int noOfFrames = 0;
static float angle = 0.0;
static double frameRateInterval = 0.0;
#define BUFFER_SIZE 1024
static char buffer[BUFFER_SIZE];
void displayFrameRate(long int frameNo);
void drawText(GLint x, GLint y, char* s, int windowWidth,
int windowHeight, GLfloat r, GLfloat g, GLfloat b);
void drawGLShape(int drawMode, mvConstShapePtr shapePtr,
const mvVec3& pos, float r, float g, float b);
void init();
void reshape(int w, int h);
void keyboard(unsigned char key,int x, int y);
void display();
void animate();
#define USE_ARGUMENTV_FILE_ARG_COUNT 2
#define FILE_NAME_ARGV_INDEX 1
char defaultLuaFileName[] = "Test.lua";
char* scriptFileName = NULL;
bool isAnimating = false;
void displayMotionAI();
void displayWaypoint(mvWaypointPtr wp, void* ptr);
void displayObstacle(mvObstaclePtr o, void* ptr);
void displayBody(mvBodyPtr p, void* extraPtr);
void worldFunction(mvWorldPtr tempWorld, void* ptr);
int main(int argc, char** argv)
{
// ignore : OpenGL startup code
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (windowWidth, windowHeight);
glutInitWindowPosition (100, 100);
glutCreateWindow("tutorial3 :implementing a custom behaviour in mvMotionAI");
// ignore : more application based OpenGL startup code
init ();
/*
* Step 2 : initialise mvMotionAI library
*/
mvInitMotionAI();
mvErrorEnum initError = mvInitDefaultActions();
if (initError != MV_NO_ERROR)
{
puts("MV INIT ACTIONS ERROR");
}
/*
* Step 2.1 adding a new instance of TimedHopLoader
* - NOTE that the mvWorld class handles the deletion of mvBaseActionLoaders.
*/
initError = mvAddBehaviourFunction(MV_NON_BODY_TYPE, new TimedHopLoader());
if (initError != MV_NO_ERROR)
{
puts("MV INIT CUSTOM ACTIONS ERROR");
}
initError = mvInitDefaultForces();
if (initError != MV_NO_ERROR)
{
puts("MV INIT FORCES ERROR");
}
/*
* Step 3 : create mvWorld object via C interface
*/
int worldID = mvCreateWorld();
std::cout << "worldID : " << worldID << std::endl;
int bodyID2 = mvCreateBody(worldID,MV_PARTICLE,MV_SPHERE, 0 , 4 , 4);
int entryID = mvAddBehaviourToList(worldID,bodyID2,MV_NON_BODY_TYPE, MV_NULL, MV_NULL);
if (entryID == MV_NULL)
{
puts("MV INIT ENTRY ERROR");
}
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return EXIT_SUCCESS;
}
const char* animateFlag = NULL;
const char no_animation[] = "a : Start animation";
const char yes_animation[] = "A : stop Animation";
const char camera_keys[] = "q|Q/w|W/e|E : move camera\nz|Z/x|X/c|c rotates camera\n";
void display(void)
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
worldCam.apply();
glLightfv(GL_LIGHT0,GL_POSITION,lightPos1);
glColor3f(0,1,0);
glBegin(GL_QUADS);
glNormal3f(0,1,0);
glVertex3f(20,0,-20);
glVertex3f(-20,0,-20);
glVertex3f(-20,0,20);
glVertex3f(20,0,20);
glEnd();
/*
* MISC: Use rotating teapot to see if animation is on.
*/
glPushMatrix();
glRotatef(angle,0,1,0);
glColor3f(1,1,1);
glutSolidTeapot(1.0);
glPopMatrix();
/*
* Step 4: Add the user defined function
* application to interact with mvMotionAI library
* displayMotionAI;
*/
displayMotionAI();
glPopMatrix();
/*
* MISC : draw frame rate
*/
animateFlag = (isAnimating) ? yes_animation : no_animation;
sprintf(buffer,"tutorial3, 2007\nFrame Rate : %3.3f fps\n%s\n%s\n",frameRateInterval,animateFlag,camera_keys);
drawText(5, windowHeight - 13, buffer ,windowWidth,windowHeight, 1.0, 1.0, 1.0);
glFlush();
glutSwapBuffers();
}
void displayMotionAI()
{
/*
* Step 5: For all worlds, we apply the function 'worldFunction'
* as a function pointer. By passing the function name to mvApplyToAllWorlds
* and some other parameter. Here we used NULL but you could pass
* structures, classes and anything that will fit as a void* pointer.
*/
mvApplyToAllWorlds(worldFunction,NULL);
}
void worldFunction(mvWorldPtr tempWorld, void* entry)
{
/*
* Step 6: Here we call other functions to draw the classes
* inside the mvWorld instance such as mvBody, mvObstacles
* & mvWaypoints. Each of these functions below take a void function
* i.e void func(mvClass* object, void* ptr);
*/
if (tempWorld != NULL)
{
tempWorld->applyToAllBodies(displayBody,NULL);
tempWorld->applyToAllObstacles(displayObstacle,NULL);
tempWorld->applyToAllWaypoints(displayWaypoint,NULL);
}
}
/*
* Step 6a : this function draws the mvBody type in the
* application
*/
void displayBody(mvBodyPtr p,void* extraPtr)
{
if (p != NULL)
{
glPushAttrib(GL_LIGHTING_BIT);
glDisable(GL_LIGHTING);
// Direction
glPushMatrix();
glTranslatef(p->getX(),p->getY(),p->getZ());
glBegin(GL_LINES);
// RED TO GREEN - own velocity
glColor3f(1,0,0);
glVertex3f(0,0,0);
glColor3f(0,1,0);
glVertex3f(p->getVelocity().getX(), p->getVelocity().getY(), p->getVelocity().getZ());
// GREEN TO BLUE - final velocity
glColor3f(0,1,0);
glVertex3f(0,1,0);
glColor3f(0,0,1);
glVertex3f(p->getFinalVelocity().getX(), 1.0f + p->getFinalVelocity().getY(), p->getFinalVelocity().getZ());
glEnd();
glPopMatrix();
glPopAttrib();
drawGLShape(GL_FILL, p->getShape(),p->getPosition(), 1, 1, 1);
}
}
/*
* Step 6b : this function draws the mvObstacle type in the
* application
*/
void displayObstacle(mvObstaclePtr o,void* extraPtr)
{
if (o != NULL)
{
drawGLShape(GL_FILL, o->getShape(),
o->getPosition(), 1, 0, 1);
}
}
void drawGLShape(int drawMode, mvConstShapePtr shapePtr,
const mvVec3& pos, float r, float g, float b)
{
mvOptionEnum tempShape;
mvFloat radius;
mvFloat aaboxDimensions[MV_VEC3_NO_OF_COMPONENTS];
mvCount noOfDimensions;
mvErrorEnum error;
glPushMatrix();
glTranslatef(pos.getX(),pos.getY(),pos.getZ());
tempShape = shapePtr->getType();
if (tempShape == MV_AABOX)
{
error = shapePtr->getParameterv(MV_SHAPE_DIMENSIONS,
&aaboxDimensions[0], &noOfDimensions);
if (error == MV_NO_ERROR)
{
glScalef(aaboxDimensions[0], aaboxDimensions[1],\
aaboxDimensions[2]);
glColor3f(r,g,b);
}
else
{
glColor3f(1,0,0);
}
if (drawMode == GL_LINE)
{
glutWireCube(1.0);
}
else
{
glutSolidCube(1.0);
}
}
else if (tempShape == MV_SPHERE)
{
error = shapePtr->getParameterf(MV_RADIUS, &radius);
if (error == MV_NO_ERROR)
{
glColor3f(r,g,b);
}
else
{
glColor3f(1,0,0);
radius = 1;
}
if (drawMode == GL_LINE)
{
glutWireSphere(radius,20,20);
}
else
{
glutSolidSphere(radius,20,20);
}
}
else
{
if (drawMode == GL_LINE)
{
glutWireOctahedron();
}
else
{
glutSolidOctahedron();
}
}
glPopMatrix();
}
/*
* Step 6c : this function draws the mvWaypoint type in the
* application
*/
void displayWaypoint(mvWaypointPtr wp,void* extraPtr)
{
if (wp != NULL)
{
drawGLShape(GL_LINE, wp->getShape(),
wp->getPosition(), 1, 1, 0);
}
}
void animate(void)
{
float temp = (float) glutGet(GLUT_ELAPSED_TIME);
float diffTime = temp - previousTime;
float timeInSecs;
elapsedTime = glutGet(GLUT_ELAPSED_TIME)/(float)1000.0;
if (diffTime > MIN_FRAME_PERIOD)
{
timeInSecs = diffTime/1000.0;
angle += (float) 25.0 * (timeInSecs);
previousTime = temp;
/*
* Step 7 : To animate mvMotionAI, add elapsed time in seconds to step
* the worlds forward.
*/
//std::cout << "BEFORE" <<std::endl;
mvAllWorldsStepForward(timeInSecs);
//std::cout << "AFTER" <<std::endl;
}
displayFrameRate(noOfFrames);
glutPostRedisplay();
noOfFrames++;
}
void displayFrameRate(long int frameNo)
{
static const double interval = 1.0;
static long int frameNoStartInterval = 0;
static double elapsedTimeStartInterval = 0.0;
static double tpfPrevious = 0.0;
static double tpfCurrent = 0.0;
static int noOfSeconds = 0;
if (elapsedTime > elapsedTimeStartInterval + interval)
{
frameRateInterval = (frameNo - frameNoStartInterval) /
(elapsedTime - elapsedTimeStartInterval);
elapsedTimeStartInterval = elapsedTime;
frameNoStartInterval = frameNo;
tpfCurrent = 1000.0/frameRateInterval;
std::cout << "TPF : " << tpfCurrent << " +/- " << tpfCurrent - tpfPrevious <<std::endl;
tpfPrevious = tpfCurrent;
noOfSeconds++;
/*
if (noOfSeconds > 10)
{
exit(0);
}
*/
}
}
/*
* Ignore these function below
*/
void cleanup()
{
mvFreeMotionAI();
}
/* ARGSUSED1 */
void keyboard (unsigned char key, int x, int y)
{
switch (key) {
case 'a':
previousTime = (float) glutGet(GLUT_ELAPSED_TIME);
glutIdleFunc(animate);
isAnimating = true;
glutPostRedisplay();
break;
case 'A':
glutIdleFunc(NULL);
isAnimating = false;
glutPostRedisplay();
break;
case 'z':
worldCam.addXRotation(15.0);
glutPostRedisplay();
break;
case 'Z':
worldCam.addXRotation(-15.0);
glutPostRedisplay();
break;
case 'x':
worldCam.addYRotation(15.0);
glutPostRedisplay();
break;
case 'X':
worldCam.addYRotation(-15.0);
glutPostRedisplay();
break;
case 'c':
worldCam.addZRotation(15.0);
glutPostRedisplay();
break;
case 'C':
worldCam.addZRotation(-15.0);
glutPostRedisplay();
break;
case 'q':
worldCam.addXPosition(0.25);
glutPostRedisplay();
break;
case 'Q':
worldCam.addXPosition(-0.25);
glutPostRedisplay();
break;
case 'w':
worldCam.addYPosition(0.25);
glutPostRedisplay();
break;
case 'W':
worldCam.addYPosition(-0.25);
glutPostRedisplay();
break;
case 'e':
worldCam.addZPosition(0.25);
glutPostRedisplay();
break;
case 'E':
worldCam.addZPosition(-0.25);
glutPostRedisplay();
break;
case 27:
cleanup();
exit(0);
break;
default:
break;
}
}
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_SMOOTH);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
worldCam.resetCamera();
worldCam.addYPosition(3);
// refresh screen
displayFrameRate(noOfFrames);
glutPostRedisplay();
}
void drawText(GLint x, GLint y, char* s, int windowWidth,
int windowHeight, GLfloat r, GLfloat g, GLfloat b)
{
/* Fron Luke Bigum's TiledProj,2005*/
int lines;
char* p;
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, windowWidth,
0.0, windowHeight, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glColor3f(r, g, b);
glRasterPos2i(x, y);
for(p = s, lines = 0; *p; p++)
{
if (*p == '\n')
{
lines++;
glRasterPos2i(x, y-(lines*15));
continue;
}
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, *p);
}
glPopAttrib();
glEnable(GL_DEPTH_TEST);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
void reshape (int w, int h)
{
windowWidth = w;
windowHeight = h;
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glFrustum(left,right,bottom,top,nearValue,farValue);
gluLookAt( 0 , 0, 2.0, 0, 0 , 0, 0, 1.00, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef (0.0, 0.0, -3.0);
}
This file was created with HTML Kit on 21th November 2007. This code is revelant to version 00-02-38 and greater.