384 lines
13 KiB
C++
384 lines
13 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program 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 Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
/*
|
|
|
|
LEFT/RIGHT/UP/DOWN : move the selected primitive
|
|
TAB : select the next primitive
|
|
CTRL+MOUSE : move the camera
|
|
WHEEL: zoom in/out
|
|
PRIOR/NEXT: move on the z axis the selected primitive
|
|
INSERT: add primitives
|
|
SPACE: start chaos (move all primitive in random manner)
|
|
DEL: remove a primitive
|
|
*/
|
|
|
|
|
|
// Misc includes
|
|
#include <nel/misc/path.h>
|
|
#include <nel/misc/time_nl.h>
|
|
|
|
// Pacs includes
|
|
#include <nel/pacs/u_move_container.h>
|
|
#include <nel/pacs/u_move_primitive.h>
|
|
#include <nel/pacs/u_collision_desc.h>
|
|
|
|
// 3d includes
|
|
#include <nel/3d/u_scene.h>
|
|
#include <nel/3d/u_camera.h>
|
|
#include <nel/3d/u_driver.h>
|
|
#include <nel/3d/u_instance.h>
|
|
#include <nel/3d/u_material.h>
|
|
#include <nel/3d/u_text_context.h>
|
|
#include <nel/3d/u_3d_mouse_listener.h>
|
|
|
|
#include "object.h"
|
|
|
|
#ifdef NL_OS_WINDOWS
|
|
// Just for the main function and ::MessageBox
|
|
# include <windows.h>
|
|
#endif // NL_OS_WINDOWS
|
|
|
|
#ifndef NL_PACS_DATA
|
|
#define NL_PACS_DATA "."
|
|
#endif // NL_PACS_DATA
|
|
|
|
using namespace NLMISC;
|
|
using namespace NL3D;
|
|
using namespace NLPACS;
|
|
|
|
// Some defines
|
|
#define ARENA_SIZE 50
|
|
#define NUM_CELL 10
|
|
|
|
#define SIZE_PRIMITIVE_MIN (1)
|
|
#define SIZE_PRIMITIVE_MAX 2
|
|
#define KEYBOARD_ACCEL (5.0) // m.s-2
|
|
#define SHOCK_ABSORB (0.9) //
|
|
#define DELTA_TIME (0.1)
|
|
#define GO (10)
|
|
#define BORDER_SIZE SIZE_PRIMITIVE_MAX
|
|
#define INIT_SPEED 9
|
|
#define MAX_WORLD_IMAGE 31
|
|
|
|
volatile bool synchro;
|
|
|
|
// Get a random size
|
|
double randomSize ()
|
|
{
|
|
return (SIZE_PRIMITIVE_MAX - SIZE_PRIMITIVE_MIN)*((double)rand() / (double)RAND_MAX) + SIZE_PRIMITIVE_MIN;
|
|
}
|
|
|
|
// Get a random rotation
|
|
double randomRot ()
|
|
{
|
|
return 2*(double)Pi*((double)rand() / (double)RAND_MAX);
|
|
}
|
|
|
|
// Get a random speed
|
|
CVectorD randomSpeed ()
|
|
{
|
|
return CVectorD ( 2*(double)INIT_SPEED*((double)rand() / (double)RAND_MAX) - INIT_SPEED,
|
|
2*(double)INIT_SPEED*((double)rand() / (double)RAND_MAX) - INIT_SPEED, 0);
|
|
}
|
|
|
|
// Get a random pos
|
|
CVectorD randomPos ()
|
|
{
|
|
return CVectorD ( ((double)ARENA_SIZE - 2*BORDER_SIZE - SIZE_PRIMITIVE_MAX)*((double)rand() / (double)RAND_MAX) - ARENA_SIZE / 2.0 + BORDER_SIZE+ (SIZE_PRIMITIVE_MAX) / 2,
|
|
((double)ARENA_SIZE - 2*BORDER_SIZE - SIZE_PRIMITIVE_MAX)*((double)rand() / (double)RAND_MAX) - ARENA_SIZE / 2.0 + BORDER_SIZE+ (SIZE_PRIMITIVE_MAX) / 2,
|
|
0);
|
|
}
|
|
|
|
// Setup speed with keyboard
|
|
void keyboard (UDriver *pDriver, double deltaTime, CObjectDyn &obj)
|
|
{
|
|
// Add speed to selected object
|
|
CVectorD speed (0,0,0);
|
|
if (pDriver->AsyncListener.isKeyDown (KeyLEFT))
|
|
speed.x+=KEYBOARD_ACCEL*deltaTime;
|
|
if (pDriver->AsyncListener.isKeyDown (KeyRIGHT))
|
|
speed.x-=KEYBOARD_ACCEL*deltaTime;
|
|
if (pDriver->AsyncListener.isKeyDown (KeyUP))
|
|
speed.y-=KEYBOARD_ACCEL*deltaTime;
|
|
if (pDriver->AsyncListener.isKeyDown (KeyDOWN))
|
|
speed.y+=KEYBOARD_ACCEL*deltaTime;
|
|
if (pDriver->AsyncListener.isKeyDown (KeyPRIOR))
|
|
speed.z+=KEYBOARD_ACCEL*deltaTime;
|
|
if (pDriver->AsyncListener.isKeyDown (KeyNEXT))
|
|
speed.z-=KEYBOARD_ACCEL*deltaTime;
|
|
|
|
// Set new speed
|
|
if (speed.norm() > 0)
|
|
obj.setSpeed(obj.getSpeed ()+speed);
|
|
}
|
|
|
|
// ** Main entry
|
|
|
|
#ifdef NL_OS_WINDOWS
|
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
|
#else // NL_OS_WINDOWS
|
|
int main ()
|
|
#endif // NL_OS_WINDOWS
|
|
{
|
|
NLMISC::CApplicationContext myApplicationContext;
|
|
|
|
try
|
|
{
|
|
// Init search paths
|
|
CPath::addSearchPath (NL_PACS_DATA"/shapes");
|
|
|
|
// Create a driver
|
|
UDriver *pDriver=UDriver::createDriver(0);
|
|
|
|
// Setup text context
|
|
pDriver->setDisplay (UDriver::CMode(640, 480, 0));
|
|
|
|
// Create a scene
|
|
UScene *pScene = pDriver->createScene(false);
|
|
nlassert(pScene);
|
|
|
|
pScene->enableLightingSystem(true);
|
|
pScene->setAmbientGlobal(CRGBA(128,128,128));
|
|
|
|
// Create a container
|
|
// This container has 31 world images. The first is a static world image, the others are dynamic.
|
|
// Each frame, the sample eval the collision in the next dynamic world image.
|
|
// This is to show the multiple world images functionality.
|
|
UMoveContainer *container=UMoveContainer::createMoveContainer (-ARENA_SIZE/2.0, -ARENA_SIZE/2.0, ARENA_SIZE/2.0, ARENA_SIZE/2.0,
|
|
NUM_CELL, NUM_CELL, (double)SIZE_PRIMITIVE_MAX*sqrt(2.0), MAX_WORLD_IMAGE);
|
|
|
|
// Set the world image 0 as static (for borders)
|
|
container->setAsStatic (0);
|
|
|
|
// Array arena
|
|
std::vector<CObjectDyn*> arrayArena;
|
|
|
|
// Create an arena with boxes
|
|
int num_cell=ARENA_SIZE/SIZE_PRIMITIVE_MAX+1;
|
|
for (int cell=0; cell<num_cell; cell++)
|
|
{
|
|
// Create static boxes around the test area
|
|
arrayArena.push_back (new CObjectDyn (SIZE_PRIMITIVE_MAX, SIZE_PRIMITIVE_MAX, 10*SIZE_PRIMITIVE_MAX, 0,
|
|
CVectorD (SIZE_PRIMITIVE_MAX*cell-(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, (ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, 0),
|
|
CVectorD(0,0,0), true, *container, *pScene, UMovePrimitive::DoNothing, UMovePrimitive::NotATrigger, 0, 1, 0));
|
|
arrayArena.push_back (new CObjectDyn (SIZE_PRIMITIVE_MAX, SIZE_PRIMITIVE_MAX, 10*SIZE_PRIMITIVE_MAX, 0,
|
|
CVectorD (SIZE_PRIMITIVE_MAX*cell-(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, -(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, 0),
|
|
CVectorD(0,0,0), true, *container, *pScene, UMovePrimitive::DoNothing, UMovePrimitive::NotATrigger, 0, 1, 0));
|
|
arrayArena.push_back (new CObjectDyn (SIZE_PRIMITIVE_MAX, SIZE_PRIMITIVE_MAX, 10*SIZE_PRIMITIVE_MAX, 0,
|
|
CVectorD ((ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, SIZE_PRIMITIVE_MAX*cell-(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, 0),
|
|
CVectorD(0,0,0), true, *container, *pScene, UMovePrimitive::DoNothing, UMovePrimitive::NotATrigger, 0, 1, 0));
|
|
arrayArena.push_back (new CObjectDyn (SIZE_PRIMITIVE_MAX, SIZE_PRIMITIVE_MAX, 10*SIZE_PRIMITIVE_MAX, 0,
|
|
CVectorD (-(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, SIZE_PRIMITIVE_MAX*cell-(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, 0),
|
|
CVectorD(0,0,0), true, *container, *pScene, UMovePrimitive::DoNothing, UMovePrimitive::NotATrigger, 0, 1, 0));
|
|
}
|
|
|
|
// Setup camera
|
|
UCamera pCam=pScene->getCam();
|
|
pCam.setTransformMode (UTransformable::DirectMatrix);
|
|
pCam.setPerspective ((float)Pi/2.f, 1.33f, 0.1f, 1000);
|
|
|
|
// Setup the mouse listener
|
|
U3dMouseListener *plistener=pDriver->create3dMouseListener ();
|
|
plistener->setHotSpot (CVectorD (0,0,0));
|
|
plistener->setFrustrum (pCam.getFrustum());
|
|
plistener->setMatrix (pCam.getMatrix());
|
|
plistener->setMouseMode (U3dMouseListener::edit3d);
|
|
|
|
// Array of dynamic objects
|
|
std::vector<CObjectDyn*> arrayObj;
|
|
|
|
// Create one object
|
|
arrayObj.push_back (
|
|
new CObjectDyn (randomSize (), randomSize (), randomPos (), CVectorD(0,0,0), true, *container, *pScene,
|
|
UMovePrimitive::Reflexion, UMovePrimitive::NotATrigger, 1, 30, 1));
|
|
|
|
// Selected object
|
|
uint selected=0;
|
|
|
|
// Get time
|
|
TTime lastTime=CTime::getLocalTime ();
|
|
|
|
// Current world image
|
|
uint worldImage=1;
|
|
|
|
// Color to clear the background
|
|
CRGBA clearColor;
|
|
|
|
// Main loop
|
|
while (pDriver->isActive() && (!pDriver->AsyncListener.isKeyPushed (KeyESCAPE)))
|
|
{
|
|
// Get the current time
|
|
TTime newTime=CTime::getLocalTime ();
|
|
double deltaTime=(double)(uint32)(newTime-lastTime)/1000.0;
|
|
lastTime=newTime;
|
|
|
|
// Insert objects in press INSERT
|
|
if (pDriver->AsyncListener.isKeyDown (KeyINSERT))
|
|
{
|
|
if (pDriver->AsyncListener.isKeyDown (KeyMENU))
|
|
{
|
|
// Random cylinder and boxes
|
|
if (rand()&1)
|
|
arrayObj.push_back (new CObjectDyn (randomSize(), randomSize(), randomSize(), randomRot(), randomPos (), CVectorD(0,0,0),
|
|
false, *container, *pScene, UMovePrimitive::DoNothing, (UMovePrimitive::TTrigger)(UMovePrimitive::EnterTrigger|UMovePrimitive::ExitTrigger|UMovePrimitive::OverlapTrigger), 1, 30, worldImage));
|
|
else
|
|
arrayObj.push_back (new CObjectDyn (randomSize (), randomSize (), randomPos (), CVectorD(0,0,0), false, *container,
|
|
*pScene, UMovePrimitive::DoNothing, (UMovePrimitive::TTrigger)(UMovePrimitive::EnterTrigger|UMovePrimitive::ExitTrigger|UMovePrimitive::OverlapTrigger), 1, 30, worldImage));
|
|
}
|
|
else
|
|
{
|
|
// Random cylinder and boxes
|
|
bool fixed = (rand()&1) != 0;
|
|
if (rand()&1)
|
|
arrayObj.push_back (new CObjectDyn (randomSize(), randomSize(), randomSize(), randomRot(), randomPos (), CVectorD(0,0,0),
|
|
true, *container, *pScene, fixed?UMovePrimitive::DoNothing:UMovePrimitive::Reflexion, UMovePrimitive::NotATrigger,
|
|
1, 30, worldImage));
|
|
else
|
|
arrayObj.push_back (new CObjectDyn (randomSize (), randomSize (), randomPos (), CVectorD(0,0,0), true, *container,
|
|
*pScene, fixed?UMovePrimitive::DoNothing:UMovePrimitive::Reflexion, UMovePrimitive::NotATrigger, 1, 30, worldImage));
|
|
}
|
|
}
|
|
|
|
// Make chaos if SPACE pressed
|
|
if (pDriver->AsyncListener.isKeyDown (KeySPACE))
|
|
{
|
|
for (uint t=0; t<arrayObj.size(); t++)
|
|
{
|
|
if (!arrayObj[t]->Freezed)
|
|
arrayObj[t]->setSpeed (randomSpeed ());
|
|
}
|
|
}
|
|
|
|
// Keyboard
|
|
if (arrayObj.size())
|
|
{
|
|
// Manipulate selected primitive
|
|
keyboard (pDriver, deltaTime, *(arrayObj[selected]));
|
|
|
|
// Remove a primitive if DELETE pressed
|
|
if (pDriver->AsyncListener.isKeyDown (KeyDELETE))
|
|
{
|
|
// remove all but one
|
|
if (arrayObj.size() > 1) {
|
|
arrayObj[arrayObj.size()-1]->remove (*container, *pScene);
|
|
arrayObj.resize (arrayObj.size()-1);
|
|
}
|
|
}
|
|
|
|
// Check selected
|
|
if (selected>=arrayObj.size())
|
|
selected=arrayObj.size()-1;
|
|
//if (selected<0)
|
|
// selected=0;
|
|
|
|
// Change selected object if TAB pressed
|
|
if (pDriver->AsyncListener.isKeyPushed (KeyTAB))
|
|
{
|
|
selected++;
|
|
selected%=arrayObj.size();
|
|
}
|
|
}
|
|
|
|
// Move primitives
|
|
for (uint i=0; i<arrayObj.size(); i++)
|
|
arrayObj[i]->tryMove (DELTA_TIME, *container, worldImage);
|
|
|
|
// Eval static world image
|
|
container->evalCollision (DELTA_TIME, 0);
|
|
|
|
// Eval current dynamic world image
|
|
container->evalCollision (DELTA_TIME, worldImage);
|
|
|
|
// Simulation new position
|
|
uint i;
|
|
for (i=0; i<arrayObj.size(); i++)
|
|
arrayObj[i]->doMove (DELTA_TIME, worldImage);
|
|
|
|
// Check triggers
|
|
clearColor=CRGBA::Black;
|
|
|
|
// Setup view matrix
|
|
int size=arrayObj.size();
|
|
if (size)
|
|
{
|
|
// Setup hotspot for the 3d listener
|
|
plistener->setHotSpot (arrayObj[selected]->getPos());
|
|
|
|
// Look at selected primitive
|
|
pCam.lookAt (plistener->getViewMatrix().getPos (), arrayObj[selected]->getPos());
|
|
}
|
|
|
|
// Force listener current matrix
|
|
plistener->setMatrix (pCam.getMatrix());
|
|
|
|
// Clear
|
|
pDriver->clearBuffers (clearColor);
|
|
|
|
// Render
|
|
pScene->render ();
|
|
|
|
// Draw some lines
|
|
pDriver->setMatrixMode3D(pCam);
|
|
|
|
// Compute triggers
|
|
uint in = 0;
|
|
uint out = 0;
|
|
uint inside = 0;
|
|
for (i=0; i<container->getNumTriggerInfo(); i++)
|
|
{
|
|
uint8 type = container->getTriggerInfo(i).CollisionType;
|
|
in += (type == UTriggerInfo::In)?1:0;
|
|
out += (type == UTriggerInfo::Out)?1:0;
|
|
inside += (type == UTriggerInfo::Inside)?1:0;
|
|
if (type == UTriggerInfo::Out)
|
|
int foobar = 0;
|
|
}
|
|
|
|
// Draw the trigger bar
|
|
pDriver->setMatrixMode2D11();
|
|
pDriver->drawQuad(0, 0.10f, 1.f * (float)in / 50.f, 0.15f, CRGBA::Red);
|
|
pDriver->drawQuad(0, 0.05f, 1.f * (float)inside / 50.f, 0.10f, CRGBA::Green);
|
|
pDriver->drawQuad(0, 0.00f, 1.f * (float)out / 50.f, 0.05f, CRGBA::Blue);
|
|
|
|
// Swap
|
|
pDriver->swapBuffers ();
|
|
|
|
// Pump messages
|
|
pDriver->EventServer.pump();
|
|
|
|
// Next world image
|
|
int nextImage=worldImage+1;
|
|
if (nextImage>=MAX_WORLD_IMAGE)
|
|
nextImage=1;
|
|
container->duplicateWorldImage (worldImage, nextImage);
|
|
worldImage=nextImage;
|
|
}
|
|
|
|
// Remove mouse listener
|
|
pDriver->delete3dMouseListener (plistener);
|
|
}
|
|
catch (Exception& e)
|
|
{
|
|
#ifdef NL_OS_WINDOWS
|
|
::MessageBox (NULL, e.what(), "Test collision move", MB_OK|MB_ICONEXCLAMATION);
|
|
#else // NL_OS_WINDOWS
|
|
printf ("%s\n", e.what());
|
|
#endif // NL_OS_WINDOWS
|
|
}
|
|
|
|
return 0;
|
|
}
|