Code Search for Developers
 
 
  

kcollision.cpp from Spatial Knowledge Experiments at Krugle


Show kcollision.cpp syntax highlighted

/*
    Copyright (C) 2003 by Luca Cappa
    Written by Luca Cappa groton@users.sourceforge.net
  
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.
  
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.
  
    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

//
// I N C L U D E S
//


#include "cssysdef.h"

#include "csutil/sysfunc.h"
#include "csutil/cscolor.h"
#include "csutil/cmdhelp.h"
#include "csutil/cspmeter.h"
#include "csutil/csstring.h"
#include "csutil/scfstr.h"

#include "cstool/csview.h"
#include "cstool/initapp.h"
#include "cstool/collider.h"

#include "iutil/vfs.h"
#include "iutil/eventq.h"
#include "iutil/event.h"
#include "iutil/objreg.h"
#include "iutil/csinput.h"
#include "iutil/virtclk.h"
#include "iutil/plugin.h"
#include "iutil/string.h"


#include "iengine/sector.h"
#include "iengine/engine.h"
#include "iengine/camera.h"
#include "iengine/light.h"
#include "iengine/texture.h"
#include "iengine/mesh.h"
#include "iengine/movable.h"
#include "iengine/material.h"

#include "imesh/thing.h"
#include "imesh/object.h"
#include "imesh/sprite3d.h"


#include "ivideo/graph3d.h"
#include "ivideo/graph2d.h"
#include "ivideo/natwin.h"
#include "ivideo/txtmgr.h"
#include "ivideo/texture.h"
#include "ivideo/material.h"
#include "ivideo/fontserv.h"

#include "igraphic/imageio.h"

#include "imap/loader.h"

#include "ivaria/reporter.h"
#include "ivaria/stdrep.h"
#include "ivaria/conout.h"
#include "ivaria/reporter.h"
#include "ivaria/stdrep.h"
#include "ivaria/collider.h"

#include "csgeom/quaterni.h"
#include "csgeom/transfrm.h"
#include "csgeom/math3d_d.h"
#include "csgeom/math3d.h"

#include "igeom/polymesh.h"

#include "imap/loader.h"


#include "iaws/aws.h"
#include "iaws/awscnvs.h"


#include "korientation.h"
#include "kblock.h"
#include "kmap.h"
#include "kblockid.h"
#include "ksprite3d.h"
#include "kappstate.h"
#include "skybox.h"
#include "kcamera.h"
#include "kplayer.h"
#include "ske.h"
#include "kquaternion.h"


//?? Define this symbol to use the same code walktest use for collisions.
//???#define ALTERNATIVE_COLLISION

#ifdef ALTERNATIVE_COLLISION
/***********/

static bool s_onGround = false;//??added by me! :)

static int FindIntersection(csCollisionPair& cd,csVector3 line[2])
{
  csVector3 tri1[3]; tri1[0]=cd.a1; tri1[1]=cd.b1; tri1[2]=cd.c1;
  csVector3 tri2[3]; tri2[0]=cd.a2; tri2[1]=cd.b2; tri2[2]=cd.c2;
  
  return csMath3::FindIntersection(tri1,tri2,line);
}

#define MAXSECTORSOCCUPIED  20

// No more than 1000 collisions ;)
//This array contains all the pairs of triangles colliding.
csCollisionPair l_ourCdContact[1000];
int l_numOurCd;

int FindSectors (csVector3 v, csVector3 d, iSector *s, iSector **sa)
{
  int c = 0;
  //??? Avoid this sqrt somehow? i.e. by having it in the objects.
  float size = qsqrt (d.x * d.x + d.y * d.y + d.z * d.z);
  csRef<iSectorIterator> it (g_ske->m_engine->GetNearbySectors (s, v, size));
  iSector* sector;
  while ((sector = it->Fetch ()) != NULL)
  {
    sa[c++] = sector;
    if (c >= MAXSECTORSOCCUPIED) break;
  }
  return c;
}


//
//Returns the number of mesh objects collided with the collider passed
//as the argument.
int CollisionDetect (iEngine* Engine, csColliderWrapper *c, iSector* sp,
                     csReversibleTransform *cdt)
{
  int l_hit = 0;
  int j;
  
  // Check collision with this sector.
  csCollisionPair* CD_contact;
  
  csRef<iObjectIterator> objit (g_ske->m_engine->GetNearbyObjects (sp,
    cdt->GetOrigin (), 3));		// 3 should be enough for moving around.
  while (!objit->IsFinished ())
  {
    iObject* mw_obj = objit->GetObject ();
    //do not test with the player's colliders!//???
    csColliderWrapper* l_cW = csColliderWrapper::GetColliderWrapper (mw_obj);
    if (
      (l_cW != NULL) && (l_cW->GetID () == 
      g_ske->m_player->GetBodyColliderWrapper ()->GetID () )
      ||
      (l_cW != NULL) && (l_cW->GetID () == 
      g_ske->m_player->GetFeetsColliderWrapper ()->GetID () )
      ||
      (strchr (mw_obj->GetName (), '@'))//???
      )
    {
      objit->Next ();
      continue;
    }//if

    csRef<iMeshWrapper> mw (SCF_QUERY_INTERFACE (mw_obj, iMeshWrapper));
    if (mw)
    {
      g_ske->m_collisionDet->ResetCollisionPairs ();
      if (c->Collide (mw_obj, cdt, &mw->GetMovable ()->GetTransform ())) 
        l_hit++;
      
      CD_contact = g_ske->m_collisionDet->GetCollisionPairs ();
      for (j=0 ; j<g_ske->m_collisionDet->GetCollisionPairCount () ; j++)
        l_ourCdContact [l_numOurCd++] = CD_contact[j];
      
      if (g_ske->m_collisionDet->GetOneHitOnly () && l_hit)
        return 1;
      // TODO, should test which one is the closest.
    }
    objit->Next ();
  }
  
  return l_hit;
}

SCF_VERSION (TerrainInfo, 0, 0, 1);

struct TerrainInfo : public csObject
{
  iTerrFuncState* terrfunc;
  SCF_DECLARE_IBASE_EXT (csObject);
};

SCF_IMPLEMENT_IBASE_EXT (TerrainInfo)
SCF_IMPLEMENTS_INTERFACE (TerrainInfo)
SCF_IMPLEMENT_IBASE_EXT_END







#else /////////////////////////////////////////////////////////////////////

struct KTriangle
{
  csVector3 *m_a,*m_b,*m_c;
  float m_distance;
  csVector3 *m_normal;
  
  KTriangle () : m_a(NULL), m_b(NULL), m_c(NULL), m_normal(NULL) 
  {
  };
  
  ~KTriangle ()
  {
    delete m_a;delete m_b;delete m_c;delete m_normal;
  };
};

/*float PointTriangleDistance (csVector3 p_point, KTriangle* p_tr)
{
    csVector3 l_tr1[3];
  l_tr1[0] = *p_tr->m_a;
  l_tr1[1] = *p_tr->m_b;
  l_tr1[2] = *p_tr->m_c;

  csVector3 l_tr2[3];
  l_tr2[0] = *p_tr->m_a;
  l_tr2[1] = *p_tr->m_b;
  l_tr2[2] = *p_tr->m_c;

  csMath3::FindIntersection ());
}

//
//Order by distance (first the nearest).
static void OrderTriangle (KTriangle** p_triangles, int p_count)
{
  qsort (p_triangles, p_count, sizeof (KTriangle), );
  /*for(int i=0; i < p_count - 1; i++)
  {
    int l_max=i;
    for(int j = i + 1; j < p_count; j++)
    {
      if(p_triangles[j]->m_distance < p_triangles[l_max]->m_distance)
      {
        l_max = j;
      }//if
    }//for
    KTriangle* l_temp = p_triangles[i];
    p_triangles[i] = p_triangles[l_max];
    p_triangles[l_max] = l_temp;
  }//for
}*/

#endif


//test for collision.
void SKE::DoGravity (const csVector3& p_pos, csVector3& p_vel,
                        const csMatrix3& l_mat)
{
  
#ifndef ALTERNATIVE_COLLISION
  csMatrix3 l_identityMatrix;	
  
  csReversibleTransform l_bodyRT (l_identityMatrix, p_pos);
  csVector3 l_newPos = p_pos + p_vel;//get the new pos.
  csVector3 old = l_newPos;
  csVector3 l_tempVel = p_vel;
  
  //collects datas for CollidePath().
  int l_count = -1; //start from -1!!!

//??UGLY!
#define MAX_OBJECTS_COLLECTED_FOR_COLLIDEPAT 60

  static iCollider* l_coll[MAX_OBJECTS_COLLECTED_FOR_COLLIDEPAT];
  static csReversibleTransform l_transByValue[MAX_OBJECTS_COLLECTED_FOR_COLLIDEPAT];
  static csReversibleTransform* l_trans[MAX_OBJECTS_COLLECTED_FOR_COLLIDEPAT];
  csRef<iObjectIterator> l_objIt = 
    m_engine->GetNearbyObjects (m_world, l_newPos, 3.0f);
  
  if(l_objIt)
    while (l_objIt->HasNext ())
    {
      iObject* l_o = l_objIt->Next ();
      csColliderWrapper* l_cW = csColliderWrapper::GetColliderWrapper (l_o);
      //Do not collect the player's colliders (nor meshes named using a @ char).
      if ( 
        (l_cW != NULL) && 
        (l_cW->GetID () != 
        m_player->GetBodyColliderWrapper()->GetID () ) &&
        (l_cW->GetID () != 
        m_player->GetFeetsColliderWrapper()->GetID () ) &&
        (!strchr (l_cW->GetName (), '@'))
        )
      {
        if (l_count++ > MAX_OBJECTS_COLLECTED_FOR_COLLIDEPAT)
          break;

        l_coll[l_count] = l_cW->GetCollider ();

        csRef<iMeshWrapper> l_mW = SCF_QUERY_INTERFACE (l_o, iMeshWrapper);
        l_transByValue[l_count] = (l_mW->GetMovable ()->GetFullTransform ());
        l_trans[l_count] = & l_transByValue[l_count];
      }//if
    };//while
    
    //Increment the counter of the collider:
    //-1 means none, so -1+1 means 0 colliders.
    ++l_count;
    
    int i = 0;
    //
    //Test along the path the collision.	
    m_collisionDet->ResetCollisionPairs ();
    if(csColliderHelper::CollidePath (this->m_collisionDet, m_player->GetBodyColliderWrapper ()->
      GetCollider (), &l_bodyRT, 0.1f,/*//??????*/ l_newPos, l_count, l_coll, l_trans) != 1)
    {
      csVector3 l_firstNewPos = l_newPos;

      csCollisionPair *pair = m_collisionDet->GetCollisionPairs ();
      int l_pairCount = m_collisionDet->GetCollisionPairCount ();
      
      KTriangle** l_tr = new KTriangle* [l_pairCount];
      for (i = 0; i < l_pairCount; i++)
      {
        l_tr[i] = new KTriangle;
        l_tr[i]->m_a = new csVector3 (pair[i].a2);
        l_tr[i]->m_b = new csVector3 (pair[i].b2);
        l_tr[i]->m_c = new csVector3 (pair[i].c2);
        //???l_tr[i]->m_distance = PointTriangleDistance (l_newPos, l_tr[i]);
        csVector3 l_nV;
        csMath3::CalcNormal(l_nV,pair[i].a2,pair[i].b2,pair[i].c2);
        
        l_nV.Normalize();
        
        l_tr[i]->m_normal = new csVector3 (l_nV);
      }//for
      
      for(i = 0; i < l_pairCount; i++)
      {
        if (*l_tr[i]->m_normal * p_vel > 0)
          continue;//if the normal is in the other direction, disregard it.
        
        l_tempVel = (l_firstNewPos + -(p_vel % *l_tr[i]->m_normal) % *l_tr[i]->m_normal) -
          p_pos;

        if (l_tempVel == 0)
          continue;
        l_newPos = csVector3 (p_pos + l_tempVel);
        if (csColliderHelper::CollidePath (m_collisionDet, m_player->GetBodyColliderWrapper()->
          GetCollider(), &l_bodyRT, 0.1f,/*//??????*/ l_newPos, l_count, l_coll, l_trans)
          == 1)
        {
          p_vel = l_tempVel;
          return;//No collision.
        }//if
        else
        {
          //
          //Test if we are moving. If yes, just return the movement, if not, try another normal.
          if( ((l_newPos - p_pos ).Norm() ) > SMALL_EPSILON )
          {
            p_vel = l_newPos - p_pos;
            return;
          }//if
        }//else
      }//for
      
      if(i == l_pairCount)
      {
        p_vel = l_newPos - p_pos;
        return;	
      }//if
    }//if








#else
    
    csVector3 l_newPos = p_pos + p_vel;
    csMatrix3 l_identity;
    csOrthoTransform l_test (l_identity, l_newPos);
    
    iSector* l_sectors[MAXSECTORSOCCUPIED];
    int l_numSectors = FindSectors (l_newPos, 4.0f * m_player->m_bodyRadius,
      g_ske->m_kcam->GetCamera()->GetSector(), l_sectors);
    
    l_numOurCd = 0;
    g_ske->m_collisionDet->SetOneHitOnly (false);
    int l_hits = 0;
    
    // Check to see if there are any terrains, if so test against those.
    // This routine will automatically adjust the transform to the highest
    // terrain at this point.
    
    // @@@@@@ The following code supports only one terrain in a sector!
    int k = 0;
    for (; k < l_numSectors ; k++)
    {
      iMeshList* l_mL = l_sectors[k]->GetMeshes ();
      if (l_mL->GetCount () > 0)
      {
        csRef<TerrainInfo> l_tI (CS_GET_CHILD_OBJECT (l_sectors[k]->
          QueryObject (), TerrainInfo));
        if (l_tI)
        {
          if (l_tI->terrfunc)
          {
            l_hits += l_tI->terrfunc->CollisionDetect (&l_test);
          }//if
        }//if
        else
        {
          l_tI.AttachNew (new TerrainInfo ());
          l_tI->terrfunc = NULL;	// No terrain found yet.
          int i = 0;
          for ( ; i < l_mL->GetCount () ; i++)
          {
            iMeshWrapper* l_terrainMW = l_mL->Get (i);
            csRef<iTerrFuncState> l_state (SCF_QUERY_INTERFACE (l_terrainMW
              ->GetMeshObject (), iTerrFuncState));
            if (l_state)
            {
              l_hits += l_state->CollisionDetect (&l_test);
              l_tI->terrfunc = l_state;
              break;
            }//if
          }//for
          csRef<iObject> l_iObj (SCF_QUERY_INTERFACE (l_tI, iObject));
          l_sectors[k]->QueryObject ()->ObjAdd (l_iObj);
        }//else
      }//if
    }//for
    
    // If there were hits with the terrain we update our new position
    // here. Side note: this could moved outside the loop above because
    // a compiler bug with gcc 2.7.2 prevented it from working when inside
    // the loop.
    if (l_hits) 
      l_newPos = l_test.GetOrigin ();
    
    int j;
    
    if (l_hits == 0)
    {
      g_ske->m_collisionDet->ResetCollisionPairs ();

      csVector3 l_kkk(l_newPos); l_kkk += 0.5f;//???
      l_test = csOrthoTransform (csMatrix3 (), l_kkk);

      for ( ; l_numSectors-- ; )
        l_hits += CollisionDetect (g_ske->m_engine, g_ske->
            m_player->GetBodyColliderWrapper (), l_sectors[l_numSectors],
            &l_test);
      
#if CS_DEBUG
      if (l_numOurCd > 0)
        printf ("body: hits=%d num_our_cd=%d\n", l_hits, l_numOurCd);
#endif // CS_DEBUG
      for (j = 0 ; j < l_numOurCd; j++)
      {
        csCollisionPair& l_cP = l_ourCdContact[j];
        csVector3 l_n = ((l_cP.c2 - l_cP.b2) % (l_cP.b2 - l_cP.a2)).Unit ();
        if (l_n * p_vel < 0)
          continue;
        p_vel = -(p_vel % l_n) % l_n;
      }
      
      // We now know our (possible) velocity. Let's try to move up or down, if possible
      l_newPos = p_pos + p_vel;
      
      // Try again, and don't move if we're still in a wall
      l_numSectors = FindSectors (l_newPos, 4.0f * g_ske->m_player->
        m_bodyRadius,
        g_ske->m_kcam->GetCamera()->GetSector(), l_sectors);
      g_ske->m_collisionDet->SetOneHitOnly (false);
      g_ske->m_collisionDet->ResetCollisionPairs ();
      
      //????l_test = csOrthoTransform (csMatrix3(), l_newPos);
      l_kkk = csVector3(l_newPos); l_kkk += 0.5f;//???
      l_test = csOrthoTransform (csMatrix3 (), l_kkk);

      int l_hit = 0;
      for (; l_numSectors--;)
        if (CollisionDetect (g_ske->m_engine, g_ske->m_player->
          GetBodyColliderWrapper (), l_sectors[l_numSectors], &l_test) > 0)
        {
          l_newPos -= p_vel;
          break;
        }//if
        

        l_test = csOrthoTransform (csMatrix3(), l_newPos);
        
        l_numSectors = FindSectors (l_newPos, 4.0f * g_ske->m_player->
          m_feetsRadius, g_ske->m_kcam->GetCamera()->GetSector(), l_sectors);
        
        l_numOurCd = 0;
        g_ske->m_collisionDet->SetOneHitOnly (false);
        g_ske->m_collisionDet->ResetCollisionPairs ();
        
        l_kkk = csVector3 (l_newPos); l_kkk += 0.0f;//???
        l_test = csOrthoTransform (csMatrix3 (), l_kkk);

        for ( ; l_numSectors-- ; )
          l_hit += CollisionDetect (g_ske->m_engine,  g_ske->m_player->
          GetFeetsColliderWrapper (),
          l_sectors[l_numSectors], &l_test);
        
        if (!l_hit)
        {
          s_onGround = false;
          if (g_ske->m_doGravity)
            p_vel.y -= 0.002;//do the actual gravity force!
        }//if
        else
        {
          float max_y = -1e10;
          
          for (j = 0 ; j < l_numOurCd ; j++)
          {
            csCollisionPair cd = l_ourCdContact[j];
            csVector3 n = ((cd.c2 - cd.b2) % (cd.b2 - cd.a2)).Unit();
            
            if (n * csVector3(0,-1,0) < 0.7) 
              continue;
            
            csVector3 line[2];
            
            cd.a1 += l_newPos;
            cd.b1 += l_newPos;
            cd.c1 += l_newPos;
            
            if (FindIntersection (cd,line))
            {
              if (line[0].y>max_y)
                max_y=line[0].y;
              if (line[1].y>max_y)
                max_y=line[1].y;
            }//if
          }//for
          
          float p = l_newPos.y - max_y /*+ OYL*/ + 0.01;//??????????
          if (ABS(p) < 0.5f /*DYL*/-0.01)//??? i added 0.5f, i.e. the legs offset!
          {
            if (max_y != -1e10)
              l_newPos.y = max_y /*- OYL */- 0.01;
            if (p_vel.y < 0)
              p_vel.y = 0;
          }//if
          s_onGround = true;
        }//else
    }
    
    //??l_newPos -= g_ske->m_kcam->GetCamera ()->GetTransform ().GetOrigin ();
    //???g_ske->m_kcam->GetCamera ()->MoveWorld (l_newPos);

    g_ske->m_player->m_mov3d.SetVelocity (
      /*g_ske->m_kcam->GetCamera ()->GetTransform ().GetO2T () **/ p_vel);
    

    p_vel = l_newPos - p_pos;//??? at this point, p_vel becomes the returned 
    //value of this function: infact it is the movement we can achieve in respect
    //to the original position p_pos

    
    
    /*//??????if(!g_ske->m_doGravity)
    {
      csVector3 l_vel = g_ske->m_player->m_mov3d.GetVelocity ();
      l_vel.y -= SIGN (l_vel.y) * MIN (0.017, ABS (l_vel.y));
      g_ske->m_player->m_mov3d.SetVelocity (l_vel);
    }//if*/
    
    
#endif
    
}



/*
//??
/*char s_buffer[120];
static csVector3 lll;
if((lll.x!=l_newPos.x)||(lll.y!=l_newPos.y)||(lll.z!=l_newPos.z))
{
lll=csVector3(l_newPos);
sprintf(s_buffer,"testing for (%7.03f,%7.03f) \n",l_newPos.x,l_newPos.z);
m_consoleOutput->PutText(s_buffer);
  }//if*/




See more files for this project here

Spatial Knowledge Experiments

A simulation of 3D virtual worlds for psychological experiments

Project homepage: http://sourceforge.net/projects/ske
Programming language(s): C,C++,Perl
License: other

  isense/
  joystick/
  Jamfile
  KImageCardinalDirection.h
  SKE.cpp
  SKE.h
  eulerangles.c
  eulerangles.h
  ikdraggable.cpp
  ikdraggable.h
  ikdraghandler.h
  ikmission.h
  ikxmlreader.h
  ikxmlwriter.h
  kappstate.cpp
  kappstate.h
  kbasedraggable.cpp
  kbasedraggable.h
  kbasedraghandler.cpp
  kbasedraghandler.h
  kblock.cpp
  kblock.h
  kblockId.h
  kblockid.cpp
  kcamera.cpp
  kcamera.h
  kcollision.cpp
  kcommandprocessor.cpp
  kcommandprocessor.h
  kconstant.cpp
  kconstant.h
  kcursor3d.cpp
  kcursor3d.h
  kdata.cpp
  kdata.h
  kdatalist.cpp
  kdatalist.h
  kdragmanager.cpp
  kdragmanager.h
  keventhandlermanager.cpp
  keventhandlermanager.h
  kflags.cpp
  kflags.h
  kimagecardinaldirection.cpp
  kkeys.cpp
  kkeys.h
  kkeystate.cpp
  kkeystate.h
  klandmark.cpp
  klandmark.h
  klandmarklist.cpp
  klandmarklist.h
  klight.cpp
  klight.h
  klightlist.cpp
  klightlist.h
  kmap.cpp
  kmap.h
  kmission.cpp
  kmission.h
  kmissiontype.cpp
  kmissiontype.h
  kmode.cpp
  kmode.h
  kmousemanager.cpp
  kmousemanager.h
  kobject3d.cpp
  kobject3d.h
  korientation.cpp
  korientation.h
  kpath.cpp
  kpath.h
  kpathfollower.cpp
  kpathfollower.h
  kplayer.cpp
  kplayer.h
  kposition.cpp
  kposition.h
  kquaternion.cpp
  kquaternion.h
  ksaveddatamanager.cpp
  ksaveddatamanager.h
  ksegment3.h
  ksign.cpp
  ksign.h
  ksprite3d.cpp
  ksprite3d.h
  ksprite3dlist.cpp
  ksprite3dlist.h
  kterrain.cpp
  kterrain.h
  kthing.cpp
  kthing.h
  kutil.cpp
  kutil.h
  kwireframe.cpp
  kwireframe.h
  kxmlhelper.h
  movement1d.h
  movement3d.h
  quattypes.h