// NeL - MMORPG Framework // 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 . /* 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 #include // Pacs includes #include #include #include // 3d includes #include #include #include #include #include #include #include #include "object.h" #ifdef NL_OS_WINDOWS // Just for the main function and ::MessageBox # include #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 arrayArena; // Create an arena with boxes int num_cell=ARENA_SIZE/SIZE_PRIMITIVE_MAX+1; for (int cell=0; cellgetCam(); 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 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; tFreezed) arrayObj[t]->setSpeed (randomSpeed ()); } } // Keyboard if (!arrayObj.empty()) { // 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=(uint)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; itryMove (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; idoMove (DELTA_TIME, worldImage); // Check triggers clearColor=CRGBA::Black; // Setup view matrix if (!arrayObj.empty()) { // 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; igetNumTriggerInfo(); 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; }