1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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
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
31 #include <nel/misc/path.h>
32 #include <nel/misc/time_nl.h>
35 #include <nel/pacs/u_move_container.h>
36 #include <nel/pacs/u_move_primitive.h>
37 #include <nel/pacs/u_collision_desc.h>
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>
51 // Just for the main function and ::MessageBox
53 #endif // NL_OS_WINDOWS
56 #define NL_PACS_DATA "."
57 #endif // NL_PACS_DATA
59 using namespace NLMISC
;
61 using namespace NLPACS
;
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)
73 #define BORDER_SIZE SIZE_PRIMITIVE_MAX
75 #define MAX_WORLD_IMAGE 31
77 volatile bool synchro
;
82 return (SIZE_PRIMITIVE_MAX
- SIZE_PRIMITIVE_MIN
)*((double)rand() / (double)RAND_MAX
) + SIZE_PRIMITIVE_MIN
;
85 // Get a random rotation
88 return 2*(double)Pi
*((double)rand() / (double)RAND_MAX
);
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);
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
;
125 if (speed
.norm() > 0)
126 obj
.setSpeed(obj
.getSpeed ()+speed
);
132 int APIENTRY
WinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPSTR lpCmdLine
, int nCmdShow
)
133 #else // NL_OS_WINDOWS
135 #endif // NL_OS_WINDOWS
137 NLMISC::CApplicationContext myApplicationContext
;
142 CPath::addSearchPath (NL_PACS_DATA
"/shapes");
145 UDriver
*pDriver
=UDriver::createDriver(0);
147 // Setup text context
148 pDriver
->setDisplay (UDriver::CMode(640, 480, 0));
151 UScene
*pScene
= pDriver
->createScene(false);
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);
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));
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
;
206 new CObjectDyn (randomSize (), randomSize (), randomPos (), CVectorD(0,0,0), true, *container
, *pScene
,
207 UMovePrimitive::Reflexion
, UMovePrimitive::NotATrigger
, 1, 30, 1));
213 TTime lastTime
=CTime::getLocalTime ();
215 // Current world image
218 // Color to clear the background
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;
229 // Insert objects in press INSERT
230 if (pDriver
->AsyncListener
.isKeyDown (KeyINSERT
))
232 if (pDriver
->AsyncListener
.isKeyDown (KeyMENU
))
234 // Random cylinder and boxes
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
));
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
));
244 // Random cylinder and boxes
245 bool fixed
= (rand()&1) != 0;
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
,
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 ());
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);
284 if (selected
>=arrayObj
.size())
285 selected
=(uint
)arrayObj
.size()-1;
289 // Change selected object if TAB pressed
290 if (pDriver
->AsyncListener
.isKeyPushed (KeyTAB
))
293 selected
%=arrayObj
.size();
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
309 for (i
=0; i
<arrayObj
.size(); i
++)
310 arrayObj
[i
]->doMove (DELTA_TIME
, worldImage
);
313 clearColor
=CRGBA::Black
;
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());
329 pDriver
->clearBuffers (clearColor
);
335 pDriver
->setMatrixMode3D(pCam
);
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
)
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
);
358 pDriver
->swapBuffers ();
361 pDriver
->EventServer
.pump();
364 int nextImage
=worldImage
+1;
365 if (nextImage
>=MAX_WORLD_IMAGE
)
367 container
->duplicateWorldImage (worldImage
, nextImage
);
368 worldImage
=nextImage
;
371 // Remove mouse listener
372 pDriver
->delete3dMouseListener (plistener
);
374 catch (const Exception
& e
)
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