Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / samples / pacs / main.cpp
blobfa334cb467da487f647b171c1cad567c926abaae
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 LEFT/RIGHT/UP/DOWN : move the selected primitive
20 TAB : select the next primitive
21 CTRL+MOUSE : move the camera
22 WHEEL: zoom in/out
23 PRIOR/NEXT: move on the z axis the selected primitive
24 INSERT: add primitives
25 SPACE: start chaos (move all primitive in random manner)
26 DEL: remove a primitive
30 // Misc includes
31 #include <nel/misc/path.h>
32 #include <nel/misc/time_nl.h>
34 // Pacs includes
35 #include <nel/pacs/u_move_container.h>
36 #include <nel/pacs/u_move_primitive.h>
37 #include <nel/pacs/u_collision_desc.h>
39 // 3d includes
40 #include <nel/3d/u_scene.h>
41 #include <nel/3d/u_camera.h>
42 #include <nel/3d/u_driver.h>
43 #include <nel/3d/u_instance.h>
44 #include <nel/3d/u_material.h>
45 #include <nel/3d/u_text_context.h>
46 #include <nel/3d/u_3d_mouse_listener.h>
48 #include "object.h"
50 #ifdef NL_OS_WINDOWS
51 // Just for the main function and ::MessageBox
52 # include <windows.h>
53 #endif // NL_OS_WINDOWS
55 #ifndef NL_PACS_DATA
56 #define NL_PACS_DATA "."
57 #endif // NL_PACS_DATA
59 using namespace NLMISC;
60 using namespace NL3D;
61 using namespace NLPACS;
63 // Some defines
64 #define ARENA_SIZE 50
65 #define NUM_CELL 10
67 #define SIZE_PRIMITIVE_MIN (1)
68 #define SIZE_PRIMITIVE_MAX 2
69 #define KEYBOARD_ACCEL (5.0) // m.s-2
70 #define SHOCK_ABSORB (0.9) //
71 #define DELTA_TIME (0.1)
72 #define GO (10)
73 #define BORDER_SIZE SIZE_PRIMITIVE_MAX
74 #define INIT_SPEED 9
75 #define MAX_WORLD_IMAGE 31
77 volatile bool synchro;
79 // Get a random size
80 double randomSize ()
82 return (SIZE_PRIMITIVE_MAX - SIZE_PRIMITIVE_MIN)*((double)rand() / (double)RAND_MAX) + SIZE_PRIMITIVE_MIN;
85 // Get a random rotation
86 double randomRot ()
88 return 2*(double)Pi*((double)rand() / (double)RAND_MAX);
91 // Get a random speed
92 CVectorD randomSpeed ()
94 return CVectorD ( 2*(double)INIT_SPEED*((double)rand() / (double)RAND_MAX) - INIT_SPEED,
95 2*(double)INIT_SPEED*((double)rand() / (double)RAND_MAX) - INIT_SPEED, 0);
98 // Get a random pos
99 CVectorD randomPos ()
101 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,
102 ((double)ARENA_SIZE - 2*BORDER_SIZE - SIZE_PRIMITIVE_MAX)*((double)rand() / (double)RAND_MAX) - ARENA_SIZE / 2.0 + BORDER_SIZE+ (SIZE_PRIMITIVE_MAX) / 2,
106 // Setup speed with keyboard
107 void keyboard (UDriver *pDriver, double deltaTime, CObjectDyn &obj)
109 // Add speed to selected object
110 CVectorD speed (0,0,0);
111 if (pDriver->AsyncListener.isKeyDown (KeyLEFT))
112 speed.x+=KEYBOARD_ACCEL*deltaTime;
113 if (pDriver->AsyncListener.isKeyDown (KeyRIGHT))
114 speed.x-=KEYBOARD_ACCEL*deltaTime;
115 if (pDriver->AsyncListener.isKeyDown (KeyUP))
116 speed.y-=KEYBOARD_ACCEL*deltaTime;
117 if (pDriver->AsyncListener.isKeyDown (KeyDOWN))
118 speed.y+=KEYBOARD_ACCEL*deltaTime;
119 if (pDriver->AsyncListener.isKeyDown (KeyPRIOR))
120 speed.z+=KEYBOARD_ACCEL*deltaTime;
121 if (pDriver->AsyncListener.isKeyDown (KeyNEXT))
122 speed.z-=KEYBOARD_ACCEL*deltaTime;
124 // Set new speed
125 if (speed.norm() > 0)
126 obj.setSpeed(obj.getSpeed ()+speed);
129 // ** Main entry
131 #ifdef NL_OS_WINDOWS
132 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
133 #else // NL_OS_WINDOWS
134 int main ()
135 #endif // NL_OS_WINDOWS
137 NLMISC::CApplicationContext myApplicationContext;
141 // Init search paths
142 CPath::addSearchPath (NL_PACS_DATA"/shapes");
144 // Create a driver
145 UDriver *pDriver=UDriver::createDriver(0);
147 // Setup text context
148 pDriver->setDisplay (UDriver::CMode(640, 480, 0));
150 // Create a scene
151 UScene *pScene = pDriver->createScene(false);
152 nlassert(pScene);
154 pScene->enableLightingSystem(true);
155 pScene->setAmbientGlobal(CRGBA(128,128,128));
157 // Create a container
158 // This container has 31 world images. The first is a static world image, the others are dynamic.
159 // Each frame, the sample eval the collision in the next dynamic world image.
160 // This is to show the multiple world images functionality.
161 UMoveContainer *container=UMoveContainer::createMoveContainer (-ARENA_SIZE/2.0, -ARENA_SIZE/2.0, ARENA_SIZE/2.0, ARENA_SIZE/2.0,
162 NUM_CELL, NUM_CELL, (double)SIZE_PRIMITIVE_MAX*sqrt(2.0), MAX_WORLD_IMAGE);
164 // Set the world image 0 as static (for borders)
165 container->setAsStatic (0);
167 // Array arena
168 std::vector<CObjectDyn*> arrayArena;
170 // Create an arena with boxes
171 int num_cell=ARENA_SIZE/SIZE_PRIMITIVE_MAX+1;
172 for (int cell=0; cell<num_cell; cell++)
174 // Create static boxes around the test area
175 arrayArena.push_back (new CObjectDyn (SIZE_PRIMITIVE_MAX, SIZE_PRIMITIVE_MAX, 10*SIZE_PRIMITIVE_MAX, 0,
176 CVectorD (SIZE_PRIMITIVE_MAX*cell-(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, (ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, 0),
177 CVectorD(0,0,0), true, *container, *pScene, UMovePrimitive::DoNothing, UMovePrimitive::NotATrigger, 0, 1, 0));
178 arrayArena.push_back (new CObjectDyn (SIZE_PRIMITIVE_MAX, SIZE_PRIMITIVE_MAX, 10*SIZE_PRIMITIVE_MAX, 0,
179 CVectorD (SIZE_PRIMITIVE_MAX*cell-(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, -(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, 0),
180 CVectorD(0,0,0), true, *container, *pScene, UMovePrimitive::DoNothing, UMovePrimitive::NotATrigger, 0, 1, 0));
181 arrayArena.push_back (new CObjectDyn (SIZE_PRIMITIVE_MAX, SIZE_PRIMITIVE_MAX, 10*SIZE_PRIMITIVE_MAX, 0,
182 CVectorD ((ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, SIZE_PRIMITIVE_MAX*cell-(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, 0),
183 CVectorD(0,0,0), true, *container, *pScene, UMovePrimitive::DoNothing, UMovePrimitive::NotATrigger, 0, 1, 0));
184 arrayArena.push_back (new CObjectDyn (SIZE_PRIMITIVE_MAX, SIZE_PRIMITIVE_MAX, 10*SIZE_PRIMITIVE_MAX, 0,
185 CVectorD (-(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, SIZE_PRIMITIVE_MAX*cell-(ARENA_SIZE-SIZE_PRIMITIVE_MAX)/2, 0),
186 CVectorD(0,0,0), true, *container, *pScene, UMovePrimitive::DoNothing, UMovePrimitive::NotATrigger, 0, 1, 0));
189 // Setup camera
190 UCamera pCam=pScene->getCam();
191 pCam.setTransformMode (UTransformable::DirectMatrix);
192 pCam.setPerspective ((float)Pi/2.f, 1.33f, 0.1f, 1000);
194 // Setup the mouse listener
195 U3dMouseListener *plistener=pDriver->create3dMouseListener ();
196 plistener->setHotSpot (CVectorD (0,0,0));
197 plistener->setFrustrum (pCam.getFrustum());
198 plistener->setMatrix (pCam.getMatrix());
199 plistener->setMouseMode (U3dMouseListener::edit3d);
201 // Array of dynamic objects
202 std::vector<CObjectDyn*> arrayObj;
204 // Create one object
205 arrayObj.push_back (
206 new CObjectDyn (randomSize (), randomSize (), randomPos (), CVectorD(0,0,0), true, *container, *pScene,
207 UMovePrimitive::Reflexion, UMovePrimitive::NotATrigger, 1, 30, 1));
209 // Selected object
210 uint selected=0;
212 // Get time
213 TTime lastTime=CTime::getLocalTime ();
215 // Current world image
216 uint worldImage=1;
218 // Color to clear the background
219 CRGBA clearColor;
221 // Main loop
222 while (pDriver->isActive() && (!pDriver->AsyncListener.isKeyPushed (KeyESCAPE)))
224 // Get the current time
225 TTime newTime=CTime::getLocalTime ();
226 double deltaTime=(double)(uint32)(newTime-lastTime)/1000.0;
227 lastTime=newTime;
229 // Insert objects in press INSERT
230 if (pDriver->AsyncListener.isKeyDown (KeyINSERT))
232 if (pDriver->AsyncListener.isKeyDown (KeyMENU))
234 // Random cylinder and boxes
235 if (rand()&1)
236 arrayObj.push_back (new CObjectDyn (randomSize(), randomSize(), randomSize(), randomRot(), randomPos (), CVectorD(0,0,0),
237 false, *container, *pScene, UMovePrimitive::DoNothing, (UMovePrimitive::TTrigger)(UMovePrimitive::EnterTrigger|UMovePrimitive::ExitTrigger|UMovePrimitive::OverlapTrigger), 1, 30, worldImage));
238 else
239 arrayObj.push_back (new CObjectDyn (randomSize (), randomSize (), randomPos (), CVectorD(0,0,0), false, *container,
240 *pScene, UMovePrimitive::DoNothing, (UMovePrimitive::TTrigger)(UMovePrimitive::EnterTrigger|UMovePrimitive::ExitTrigger|UMovePrimitive::OverlapTrigger), 1, 30, worldImage));
242 else
244 // Random cylinder and boxes
245 bool fixed = (rand()&1) != 0;
246 if (rand()&1)
247 arrayObj.push_back (new CObjectDyn (randomSize(), randomSize(), randomSize(), randomRot(), randomPos (), CVectorD(0,0,0),
248 true, *container, *pScene, fixed?UMovePrimitive::DoNothing:UMovePrimitive::Reflexion, UMovePrimitive::NotATrigger,
249 1, 30, worldImage));
250 else
251 arrayObj.push_back (new CObjectDyn (randomSize (), randomSize (), randomPos (), CVectorD(0,0,0), true, *container,
252 *pScene, fixed?UMovePrimitive::DoNothing:UMovePrimitive::Reflexion, UMovePrimitive::NotATrigger, 1, 30, worldImage));
256 // Make chaos if SPACE pressed
257 if (pDriver->AsyncListener.isKeyDown (KeySPACE))
259 for (uint t=0; t<arrayObj.size(); t++)
261 if (!arrayObj[t]->Freezed)
262 arrayObj[t]->setSpeed (randomSpeed ());
266 // Keyboard
267 if (!arrayObj.empty())
269 // Manipulate selected primitive
270 keyboard (pDriver, deltaTime, *(arrayObj[selected]));
272 // Remove a primitive if DELETE pressed
273 if (pDriver->AsyncListener.isKeyDown (KeyDELETE))
275 // remove all but one
276 if (arrayObj.size() > 1)
278 arrayObj[arrayObj.size()-1]->remove (*container, *pScene);
279 arrayObj.resize (arrayObj.size()-1);
283 // Check selected
284 if (selected>=arrayObj.size())
285 selected=(uint)arrayObj.size()-1;
286 //if (selected<0)
287 // selected=0;
289 // Change selected object if TAB pressed
290 if (pDriver->AsyncListener.isKeyPushed (KeyTAB))
292 selected++;
293 selected%=arrayObj.size();
297 // Move primitives
298 for (uint i=0; i<arrayObj.size(); i++)
299 arrayObj[i]->tryMove (DELTA_TIME, *container, worldImage);
301 // Eval static world image
302 container->evalCollision (DELTA_TIME, 0);
304 // Eval current dynamic world image
305 container->evalCollision (DELTA_TIME, worldImage);
307 // Simulation new position
308 uint i;
309 for (i=0; i<arrayObj.size(); i++)
310 arrayObj[i]->doMove (DELTA_TIME, worldImage);
312 // Check triggers
313 clearColor=CRGBA::Black;
315 // Setup view matrix
316 if (!arrayObj.empty())
318 // Setup hotspot for the 3d listener
319 plistener->setHotSpot (arrayObj[selected]->getPos());
321 // Look at selected primitive
322 pCam.lookAt (plistener->getViewMatrix().getPos (), arrayObj[selected]->getPos());
325 // Force listener current matrix
326 plistener->setMatrix (pCam.getMatrix());
328 // Clear
329 pDriver->clearBuffers (clearColor);
331 // Render
332 pScene->render ();
334 // Draw some lines
335 pDriver->setMatrixMode3D(pCam);
337 // Compute triggers
338 uint in = 0;
339 uint out = 0;
340 uint inside = 0;
341 for (i=0; i<container->getNumTriggerInfo(); i++)
343 uint8 type = container->getTriggerInfo(i).CollisionType;
344 in += (type == UTriggerInfo::In)?1:0;
345 out += (type == UTriggerInfo::Out)?1:0;
346 inside += (type == UTriggerInfo::Inside)?1:0;
347 if (type == UTriggerInfo::Out)
348 int foobar = 0;
351 // Draw the trigger bar
352 pDriver->setMatrixMode2D11();
353 pDriver->drawQuad(0, 0.10f, 1.f * (float)in / 50.f, 0.15f, CRGBA::Red);
354 pDriver->drawQuad(0, 0.05f, 1.f * (float)inside / 50.f, 0.10f, CRGBA::Green);
355 pDriver->drawQuad(0, 0.00f, 1.f * (float)out / 50.f, 0.05f, CRGBA::Blue);
357 // Swap
358 pDriver->swapBuffers ();
360 // Pump messages
361 pDriver->EventServer.pump();
363 // Next world image
364 int nextImage=worldImage+1;
365 if (nextImage>=MAX_WORLD_IMAGE)
366 nextImage=1;
367 container->duplicateWorldImage (worldImage, nextImage);
368 worldImage=nextImage;
371 // Remove mouse listener
372 pDriver->delete3dMouseListener (plistener);
374 catch (const Exception& e)
376 #ifdef NL_OS_WINDOWS
377 ::MessageBox (NULL, e.what(), "Test collision move", MB_OK|MB_ICONEXCLAMATION);
378 #else // NL_OS_WINDOWS
379 printf ("%s\n", e.what());
380 #endif // NL_OS_WINDOWS
383 return 0;