tutorial3 - source code only

Menu

  1. TimedHop.h

  2. TimedHop.cpp

  3. CustomActionGLMain.cpp

Back To Index

TimedHop.h

#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

Back To Menu

Back To Index

TimedHop.cpp

#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()
{

}

Back To Menu

Back To Index

CustomActionGLMain.cpp

/**
* \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);
}

Back To Menu

Back To Index


This file was created with HTML Kit on 21th November 2007. This code is revelant to version 00-02-38 and greater.

SourceForge.net Logo