Links
Crystal Space
Crystal Space Tutorial Site
QuArK
polycount
Sample Code
mysimple.h
mysimple.cpp
mysimple.zip
|
/*
Copyright (C) 2001 by M. Kohel
modified by Andreas Busch to work with the current
CVS-Version of CrystalSpace V0.95
*/
#include "cssysdef.h"
#include "cssys/sysfunc.h"
#include "iutil/vfs.h"
#include "csutil/cscolor.h"
#include "cstool/csview.h"
#include "cstool/initapp.h"
#include "./../include/mysimple.h"
#include "iutil/eventq.h"
#include "iutil/event.h"
#include "iutil/objreg.h"
#include "iutil/csinput.h"
#include "iutil/virtclk.h"
#include "iengine/sector.h"
#include "iengine/engine.h"
#include "iengine/camera.h"
#include "iengine/light.h"
#include "iengine/statlght.h"
#include "iengine/texture.h"
#include "iengine/mesh.h"
#include "iengine/movable.h"
#include "iengine/material.h"
#include "iengine/campos.h"
#include "imesh/thing/polygon.h"
#include "imesh/thing/thing.h"
#include "imesh/sprite3d.h"
#include "imesh/object.h"
#include "ivideo/graph3d.h"
#include "ivideo/graph2d.h"
#include "ivideo/txtmgr.h"
#include "ivideo/texture.h"
#include "ivideo/material.h"
#include "ivideo/fontserv.h"
#include "igraphic/imageio.h"
#include "imap/parser.h"
#include "ivaria/reporter.h"
#include "ivaria/stdrep.h"
#include "csutil/cmdhelp.h"
#include "csutil/debug.h"
//includes needed for collision detection
#include "ivaria/collider.h"
#include "igeom/polymesh.h"
#include "cstool/collider.h"
#include "igeom/objmodel.h"
CS_IMPLEMENT_APPLICATION
//-----------------------------------------------------------------------------
// The global pointer to simple
Simple *simple;
Simple::Simple ()
{
engine = NULL;
loader = NULL;
g3d = NULL;
kbd = NULL;
vc = NULL;
view = NULL;
cdsys = NULL;
sprite1 = NULL;
sprite2 = NULL;
sprite3 = NULL;
npc_collide1 = NULL;
npc_collide2 = NULL;
npc_collide3 = NULL;
mesh_collider = NULL;
forward = true;
}
/*************************************************************
**
**
*************************************************************/
Simple::~Simple ()
{
}
/*************************************************************
**
**
*************************************************************/
void Simple::SetupFrame ()
{
static csVector3 old_pos;
static csVector3 real_old_pos;
static long frame_number = 0;
frame_number++;
// First get elapsed time from the virtual clock.
csTicks elapsed_time = vc->GetElapsedTicks ();
// Now rotate the camera according to keyboard state
float speed = (elapsed_time / 1000.0) * (0.03 * 20);
// Move the mesh with the keys as avitar
iMovable* movable2 = sprite2->GetMovable();
movable2->SetSector( room );
iCamera* c = view->GetCamera();
if (kbd->GetKeyState (CSKEY_RIGHT))
{
movable2->GetTransform ().RotateThis (CS_VEC_ROT_RIGHT, 3 * speed);
c->SetTransform(movable2->GetTransform() );
c->Move ( csVector3( -2,1,0 ));
c->GetTransform ().RotateThis (CS_VEC_ROT_LEFT, 80);
movable2->UpdateMove();
}
if (kbd->GetKeyState (CSKEY_LEFT))
{
movable2->GetTransform ().RotateThis (CS_VEC_ROT_LEFT, 3 * speed);
c->SetTransform(movable2->GetTransform() );
c->Move ( csVector3( -2,1,0 ));
c->GetTransform ().RotateThis (CS_VEC_ROT_LEFT, 80);
movable2->UpdateMove();
}
if (kbd->GetKeyState (CSKEY_UP))
{
csVector3 new_pos = movable2->GetTransform ().This2Other(
csVector3(1,0,0) * 6 * speed);
movable2->SetPosition ( new_pos );
c->SetTransform(movable2->GetTransform() );
c->Move ( csVector3( -2,1,0 ));
c->GetTransform ().RotateThis (CS_VEC_ROT_LEFT, 80);
movable2->UpdateMove();
}
if (kbd->GetKeyState (CSKEY_DOWN))
{
csVector3 new_pos = movable2->GetTransform ().This2Other(
csVector3(-1,0,0) * 6 * speed);
movable2->SetPosition ( new_pos );
c->SetTransform(movable2->GetTransform() );
c->Move ( csVector3( -2,1,0 ));
c->GetTransform ().RotateThis (CS_VEC_ROT_LEFT, 80);
movable2->UpdateMove();
}
if (kbd->GetKeyState (119))
c->Move (CS_VEC_FORWARD * 4 * speed);
if (kbd->GetKeyState (115))
c->Move (CS_VEC_BACKWARD * 4 * speed);
if (kbd->GetKeyState (97))
c->GetTransform ().RotateThis (CS_VEC_ROT_LEFT, speed);
if (kbd->GetKeyState (100))
c->GetTransform ().RotateThis (CS_VEC_ROT_RIGHT, speed);
if (kbd->GetKeyState (CSKEY_PGUP))
c->GetTransform ().RotateThis (CS_VEC_TILT_UP, speed);
if (kbd->GetKeyState (CSKEY_PGDN))
c->GetTransform ().RotateThis (CS_VEC_TILT_DOWN, speed);
// Move the mesh as NPC
iMovable* movable = sprite1->GetMovable();
movable->SetSector( room );
csVector3 npc_current_pos = movable->GetPosition();
csVector3 current_pos = movable2->GetPosition();
if( forward )
{
movable->SetPosition( npc_current_pos + csVector3( 3 * speed, 0, 0 ) );
}
else
{
movable->SetPosition( npc_current_pos + csVector3( -3 * speed, 0, 0 ) );
}
movable->UpdateMove();
// Check for collision
cdsys->ResetCollisionPairs ();
csReversibleTransform ft1 = sprite1->GetMovable ()->GetFullTransform ();
csReversibleTransform ft2 = sprite2->GetMovable ()->GetFullTransform ();
//Begin CD code from walk test
int i=0;
int num_meshes = mesh_list->GetCount();
bool cd1 = false;
bool cd2 = false;
for (i=0; i< num_meshes; i++ )
{
// JORRIT: if cd1 and cd2 are both true we can already stop the loop.
if (cd1 && cd2) break;
// JORRIT: get collider corresponding with this mesh.
mesh_in_sector = mesh_list->Get(i);
csColliderWrapper* cd_wrap = csColliderWrapper::GetColliderWrapper (mesh_in_sector->QueryObject ());
if (!cd_wrap) continue;
mesh_collider = cd_wrap->GetCollider ();
// JORRIT: if mesh_collider is NULL we skip this iteration.
if (!mesh_collider) continue;
csReversibleTransform mesh_transform = mesh_in_sector->GetMovable ()->GetFullTransform ();
// NPC mesh - only check for first collisions
// also make sure the mesh from the list is not the same sprite we are
// checking collisions for
if( ( cd1 == false ) && ( mesh_collider != npc_collide1 ) )
{
// JORRIT: VERY WEIRD. THE OBJECTS HAVE TO BE REVERSED.
cd1 = cdsys->Collide ( npc_collide1, &ft1, mesh_collider, &mesh_transform);
// if after checking for a collision we found one print a debug
// message stating what mesh we collided with
if( cd1 )
{
printf("object 1 collided with: %s \n\n",
mesh_in_sector->QueryObject()->GetName() );
}
}
// avitar mesh - only check for first collisions
// also make sure the mesh from the list is not the same sprite we are
// checking collisions for
if( ( cd2 == false ) && ( mesh_collider != npc_collide2 ) )
{
// JORRIT: VERY WEIRD. THE OBJECTS HAVE TO BE REVERSED.
cd2 = cdsys->Collide ( npc_collide2, &ft2, mesh_collider, &mesh_transform);
// if after checking for a collision we found one print a debug
// message stating what mesh we collided with
if( cd2 )
{
printf("object 2 collided with: %s\n\n",
mesh_in_sector->QueryObject()->GetName() );
}
}
}
/* end code from walktest
*/
// check for npc collisions, if collide reverse direction
if ( cd1 )
{
if( forward )
{
forward = false;
movable->SetPosition( npc_current_pos + csVector3( 0, 0, -.5 ) );
movable->GetTransform ().LookAt ( csVector3( 0, -1.5, -100 ),
csVector3 (0, 1, 0));
}
else
{
forward = true;
movable->SetPosition( npc_current_pos + csVector3( 0, 0, .5 ) );
movable->GetTransform ().LookAt ( csVector3( 0, -1.5, 100 ),
csVector3 (0, 1, 0));
}
movable->UpdateMove();
}
// check for camera mesh collide, if collide set position back to position
// before collide
if( cd2 )
{
movable2->SetPosition( real_old_pos );
movable2->UpdateMove();
}
else
{
// JORRIT: the below two lines are suspicious. Shouldn't
// they be swapped? With the lines below old_pos
// and real_old_pos will get the same value and I'm not
// sure that is right.
old_pos = current_pos;
real_old_pos = old_pos;
}
// Tell 3D driver we're going to display 3D things.
if (!g3d->BeginDraw (engine->GetBeginDrawFlags () | CSDRAW_3DGRAPHICS))
return;
// Tell the camera to render into the frame buffer.
view->Draw ();
}
/*************************************************************
**
**
*************************************************************/
void Simple::FinishFrame ()
{
g3d->FinishDraw ();
g3d->Print (NULL);
}
/*************************************************************
**
**
*************************************************************/
bool Simple::HandleEvent (iEvent& ev)
{
if (ev.Type == csevBroadcast && ev.Command.Code == cscmdProcess)
{
simple->SetupFrame ();
return true;
}
else if (ev.Type == csevBroadcast && ev.Command.Code == cscmdFinalProcess)
{
simple->FinishFrame ();
return true;
}
else if (ev.Type == csevKeyDown && ev.Key.Code == CSKEY_ESC)
{
csRef q = CS_QUERY_REGISTRY (object_reg, iEventQueue);
if (q)
{
q->GetEventOutlet()->Broadcast (cscmdQuit);
}
return true;
}
else if (ev.Type == csevKeyDown && ev.Key.Code == 'l')
{
csDebuggingGraph::Dump (NULL);
engine->DeleteAll ();
csDebuggingGraph::Dump (NULL);
csDebuggingGraph::Clear (NULL);
LoadMap ();
return true;
}
return false;
}
/*************************************************************
**
**
*************************************************************/
bool Simple::SimpleEventHandler (iEvent& ev)
{
return simple->HandleEvent (ev);
}
/*************************************************************
**
**
*************************************************************/
iCollider* Simple::InitCollider (csRef mesh)
{
csRef polmesh = SCF_QUERY_INTERFACE ( mesh->GetMeshObject (),
iPolygonMesh);
if (polmesh)
{
csColliderWrapper* wrap = new csColliderWrapper
(mesh->QueryObject (), cdsys, polmesh);
wrap->DecRef ();
return wrap->GetCollider ();
}
else
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"Object doesn't support collision detection!");
return NULL;
}
}
/*************************************************************
**
**
*************************************************************/
bool Simple::LoadMap ()
{
// Set VFS current directory to the level we want to load.
csRef VFS = CS_QUERY_REGISTRY (object_reg, iVFS);
VFS->Mount ("/lev/mysimple", "$.$/mysimple.zip");
VFS->ChDir ("/lev/mysimple");
// Load the level file which is called 'world'.
if (!loader->LoadMapFile ("world"))
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"Couldn't load level!");
return false;
}
// Find the starting position in this level.
csVector3 pos (0, 0, 0);
if (engine->GetCameraPositions ()->GetCount () > 0)
{
printf("found sector\n");
// There is a valid starting position defined in the level file.
iCameraPosition* campos = engine->GetCameraPositions ()->Get (0);
room = engine->GetSectors ()->FindByName (campos->GetSector ());
pos = campos->GetPosition ();
}
else
{
printf("defaulted sector\n");
// We didn't find a valid starting position. So we default
// to going to room called 'room' at position (0,0,0).
room = engine->GetSectors ()->FindByName ("room");
}
if(!room)
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"Can't find a valid starting position!");
return false;
}
view->GetCamera ()->SetSector (room);
view->GetCamera ()->GetTransform ().SetOrigin (pos);
return true;
}
/*************************************************************
**
**
*************************************************************/
bool Simple::Initialize (iObjectRegistry* object_reg)
{
Simple::object_reg = object_reg;
csDebuggingGraph::SetupGraph (object_reg);
if (!csInitializer::RequestPlugins (object_reg,
CS_REQUEST_VFS,
CS_REQUEST_SOFTWARE3D,
CS_REQUEST_ENGINE,
CS_REQUEST_FONTSERVER,
CS_REQUEST_IMAGELOADER,
CS_REQUEST_LEVELLOADER,
CS_REQUEST_REPORTER,
CS_REQUEST_REPORTERLISTENER,
CS_REQUEST_PLUGIN("crystalspace.collisiondetection.rapid",
iCollideSystem),
CS_REQUEST_END))
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"Can't initialize plugins!");
return false;
}
if (!csInitializer::SetupEventHandler (object_reg, SimpleEventHandler))
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"Can't initialize event handler!");
return false;
}
// Check for commandline help.
if (csCommandLineHelper::CheckHelp (object_reg))
{
csCommandLineHelper::Help (object_reg);
return false;
}
// The collision detection system.
cdsys = CS_QUERY_REGISTRY (object_reg, iCollideSystem);
if (!cdsys)
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"Can't find the collision detection system!");
return false;
}
// The virtual clock.
vc = CS_QUERY_REGISTRY (object_reg, iVirtualClock);
if (!vc)
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"Can't find the virtual clock!");
return false;
}
// Find the pointer to engine plugin
engine = CS_QUERY_REGISTRY (object_reg, iEngine);
if (!engine)
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"No iEngine plugin!");
return false;
}
loader = CS_QUERY_REGISTRY (object_reg, iLoader);
if (!loader)
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"No iLoader plugin!");
return false;
}
g3d = CS_QUERY_REGISTRY (object_reg, iGraphics3D);
if (!g3d)
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"No iGraphics3D plugin!");
return false;
}
kbd = CS_QUERY_REGISTRY (object_reg, iKeyboardDriver);
if (!kbd)
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"No iKeyboardDriver plugin!");
return false;
}
// Open the main system. This will open all the previously loaded plug-ins.
if (!csInitializer::OpenApplication (object_reg))
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"Error opening system!");
return false;
}
view = csPtr (new csView (engine, g3d));
iGraphics2D* g2d = g3d->GetDriver2D ();
view->SetRectangle (0, 0, g2d->GetWidth (), g2d->GetHeight ());
if (!LoadMap ()) return false;
mesh_list = room->GetMeshes();
// Load a texture for our sprite.
csRef txtmgr = g3d->GetTextureManager ();
iTextureWrapper* txt = loader->LoadTexture ("knightskin",
"/lev/mysimple/evilknight.jpg",
CS_TEXTURE_3D, txtmgr, true);
iTextureWrapper* txt2 = loader->LoadTexture ("knightskin2",
"/lev/mysimple/knight.jpg",
CS_TEXTURE_3D, txtmgr, true);
if ( (txt == NULL) || (txt2 == NULL ) )
{
csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"Error loading texture!");
return false;
}
// Make a separate material from the good knight's texture
iMaterialWrapper* mat = engine->CreateMaterial("goodknight_mat", txt2 );
// Now prepare the engine with all the defined materials
engine->Prepare ();
// Load a sprite template from disk (*loader.spr can wrap binary or other sprite formats)
csRef imeshfact = loader->LoadMeshObjectFactory (
"/lev/mysimple/knightloader.spr");
if( imeshfact == NULL )
{
csReport( object_reg, CS_REPORTER_SEVERITY_ERROR,
"crystalspace.application.mysimple",
"Error loading knight mesh object factory!");
}
// Create the sprite with there predefined textures
sprite1 = engine->CreateMeshWrapper( imeshfact,
"MySprite1",
room,
csVector3( -5, -1.5, 5 ) );
sprite2 = engine->CreateMeshWrapper( imeshfact,
"MySprite2",
room,
csVector3( -.25, -1.5, 0 ) );
sprite3 = engine->CreateMeshWrapper( imeshfact,
"MySprite3",
room,
csVector3( -20, -1.5, 0 ) );
csMatrix3 m;
m.Identity ();
m *= 1.;
sprite1->GetMovable()->SetTransform(m);
sprite1->GetMovable()->GetTransform ().LookAt( csVector3( 0, -1.5, 100 ),
csVector3 (0, 1, 0));
sprite1->GetMovable()->UpdateMove();
csRef spstate1 = SCF_QUERY_INTERFACE( sprite1->GetMeshObject(),
iSprite3DState);
spstate1->SetAction ("run");
sprite2->GetMovable()->SetTransform(m);
sprite2->GetMovable()->UpdateMove();
csRef spstate2 = SCF_QUERY_INTERFACE( sprite2->GetMeshObject(),
iSprite3DState);
// Assign the good knight's material explicitly to sprite1 state
spstate2->SetMaterialWrapper( mat );
spstate2->SetAction ("point");
sprite3->GetMovable()->SetTransform(m);
sprite3->GetMovable()->UpdateMove();
csRef spstate3 = SCF_QUERY_INTERFACE( sprite3->GetMeshObject(),
iSprite3DState);
spstate3->SetAction ("point");
npc_collide1 = InitCollider (sprite1);
if (!npc_collide1) return false;
npc_collide2 = InitCollider (sprite2);
if (!npc_collide2) return false;
npc_collide3 = InitCollider (sprite3);
if (!npc_collide3) return false;
// The following two calls are not needed since CS_ZBUF_USE and
// ObjectRenderPriority are the defaults, but the show how you can
// do this.
sprite1->SetZBufMode( CS_ZBUF_USE );
sprite1->SetRenderPriority( engine->GetObjectRenderPriority() );
sprite1->DeferUpdateLighting( CS_NLIGHT_STATIC|CS_NLIGHT_DYNAMIC, 10 );
sprite2->DeferUpdateLighting( CS_NLIGHT_STATIC|CS_NLIGHT_DYNAMIC, 10 );
sprite3->DeferUpdateLighting( CS_NLIGHT_STATIC|CS_NLIGHT_DYNAMIC, 10 );
// get all meshes is the sector and create colliders for them
// the colliders will be stored in csColliderWrapper's.
mesh_list = room->GetMeshes();
int i=0;
int num_meshes = mesh_list->GetCount();
for (i=0; i < num_meshes; i++ )
{
mesh_in_sector = mesh_list->Get(i);
if( mesh_in_sector->QueryObject()->GetID() !=
sprite2->QueryObject()->GetID() )
{
mesh_collider = InitCollider( mesh_in_sector );
if (!mesh_collider)
{
printf("InitCollider error\n");
}
}
}
sprite1->DecRef();
sprite2->DecRef();
sprite3->DecRef();
return true;
}
/*************************************************************
**
**
*************************************************************/
void Simple::Start ()
{
csDefaultRunLoop (object_reg);
}
/*---------------------------------------------------------------------*
* Main function
*---------------------------------------------------------------------*/
int main (int argc, char* argv[])
{
iObjectRegistry* object_reg = csInitializer::CreateEnvironment (argc, argv);
if (!object_reg) return false;
simple = new Simple ();
if (simple->Initialize (object_reg))
simple->Start ();
delete simple;
csInitializer::DestroyApplication (object_reg);
return 0;
}
|