aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/examples/16.Quake3MapShader/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/examples/16.Quake3MapShader/main.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/examples/16.Quake3MapShader/main.cpp389
1 files changed, 389 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/examples/16.Quake3MapShader/main.cpp b/src/others/irrlicht-1.8.1/examples/16.Quake3MapShader/main.cpp
new file mode 100644
index 0000000..6391705
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/examples/16.Quake3MapShader/main.cpp
@@ -0,0 +1,389 @@
1/** Example 016 Quake3 Map Shader Support
2
3This Tutorial shows how to load a Quake 3 map into the
4engine, create a SceneNode for optimizing the speed of
5rendering and how to create a user controlled camera.
6
7Lets start like the HelloWorld example: We include
8the irrlicht header files and an additional file to be able
9to ask the user for a driver type using the console.
10*/
11#include <irrlicht.h>
12#include "driverChoice.h"
13
14/*
15 define which Quake3 Level should be loaded
16*/
17#define IRRLICHT_QUAKE3_ARENA
18//#define ORIGINAL_QUAKE3_ARENA
19//#define CUSTOM_QUAKE3_ARENA
20//#define SHOW_SHADER_NAME
21
22#ifdef ORIGINAL_QUAKE3_ARENA
23 #define QUAKE3_STORAGE_FORMAT addFolderFileArchive
24 #define QUAKE3_STORAGE_1 "/baseq3/"
25 #ifdef CUSTOM_QUAKE3_ARENA
26 #define QUAKE3_STORAGE_2 "/cf/"
27 #define QUAKE3_MAP_NAME "maps/cf.bsp"
28 #else
29 #define QUAKE3_MAP_NAME "maps/q3dm8.bsp"
30 #endif
31#endif
32
33#ifdef IRRLICHT_QUAKE3_ARENA
34 #define QUAKE3_STORAGE_FORMAT addFileArchive
35 #define QUAKE3_STORAGE_1 "../../media/map-20kdm2.pk3"
36 #define QUAKE3_MAP_NAME "maps/20kdm2.bsp"
37#endif
38
39using namespace irr;
40using namespace scene;
41
42/*
43Again, to be able to use the Irrlicht.DLL file, we need to link with the
44Irrlicht.lib. We could set this option in the project settings, but
45to make it easy, we use a pragma comment lib:
46*/
47#ifdef _MSC_VER
48#pragma comment(lib, "Irrlicht.lib")
49#endif
50
51
52/*
53A class to produce a series of screenshots
54*/
55class CScreenShotFactory : public IEventReceiver
56{
57public:
58
59 CScreenShotFactory( IrrlichtDevice *device, const c8 * templateName, ISceneNode* node )
60 : Device(device), Number(0), FilenameTemplate(templateName), Node(node)
61 {
62 FilenameTemplate.replace ( '/', '_' );
63 FilenameTemplate.replace ( '\\', '_' );
64 }
65
66 bool OnEvent(const SEvent& event)
67 {
68 // check if user presses the key F9
69 if ((event.EventType == EET_KEY_INPUT_EVENT) &&
70 event.KeyInput.PressedDown)
71 {
72 if (event.KeyInput.Key == KEY_F9)
73 {
74 video::IImage* image = Device->getVideoDriver()->createScreenShot();
75 if (image)
76 {
77 c8 buf[256];
78 snprintf(buf, 256, "%s_shot%04d.jpg",
79 FilenameTemplate.c_str(),
80 ++Number);
81 Device->getVideoDriver()->writeImageToFile(image, buf, 85 );
82 image->drop();
83 }
84 }
85 else
86 if (event.KeyInput.Key == KEY_F8)
87 {
88 if (Node->isDebugDataVisible())
89 Node->setDebugDataVisible(scene::EDS_OFF);
90 else
91 Node->setDebugDataVisible(scene::EDS_BBOX_ALL);
92 }
93 }
94 return false;
95 }
96
97private:
98 IrrlichtDevice *Device;
99 u32 Number;
100 core::stringc FilenameTemplate;
101 ISceneNode* Node;
102};
103
104
105/*
106Ok, lets start.
107*/
108
109int IRRCALLCONV main(int argc, char* argv[])
110{
111 /*
112 Like in the HelloWorld example, we create an IrrlichtDevice with
113 createDevice(). The difference now is that we ask the user to select
114 which hardware accelerated driver to use. The Software device would be
115 too slow to draw a huge Quake 3 map, but just for the fun of it, we make
116 this decision possible too.
117 */
118
119 // ask user for driver
120 video::E_DRIVER_TYPE driverType=driverChoiceConsole();
121 if (driverType==video::EDT_COUNT)
122 return 1;
123
124 // create device and exit if creation failed
125 const core::dimension2du videoDim(800,600);
126
127 IrrlichtDevice *device = createDevice(driverType, videoDim, 32, false );
128
129 if (device == 0)
130 return 1; // could not create selected driver.
131
132 const char* mapname=0;
133 if (argc>2)
134 mapname = argv[2];
135 else
136 mapname = QUAKE3_MAP_NAME;
137
138 /*
139 Get a pointer to the video driver and the SceneManager so that
140 we do not always have to write device->getVideoDriver() and
141 device->getSceneManager().
142 */
143 video::IVideoDriver* driver = device->getVideoDriver();
144 scene::ISceneManager* smgr = device->getSceneManager();
145 gui::IGUIEnvironment* gui = device->getGUIEnvironment();
146
147 //! add our private media directory to the file system
148 device->getFileSystem()->addFileArchive("../../media/");
149
150 /*
151 To display the Quake 3 map, we first need to load it. Quake 3 maps
152 are packed into .pk3 files, which are nothing other than .zip files.
153 So we add the .pk3 file to our FileSystem. After it was added,
154 we are able to read from the files in that archive as they would
155 directly be stored on disk.
156 */
157 if (argc>2)
158 device->getFileSystem()->QUAKE3_STORAGE_FORMAT(argv[1]);
159 else
160 device->getFileSystem()->QUAKE3_STORAGE_FORMAT(QUAKE3_STORAGE_1);
161#ifdef QUAKE3_STORAGE_2
162 device->getFileSystem()->QUAKE3_STORAGE_FORMAT(QUAKE3_STORAGE_2);
163#endif
164
165 // Quake3 Shader controls Z-Writing
166 smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
167
168 /*
169 Now we can load the mesh by calling getMesh(). We get a pointer returned
170 to a IAnimatedMesh. As you know, Quake 3 maps are not really animated,
171 they are only a huge chunk of static geometry with some materials
172 attached. Hence the IAnimated mesh consists of only one frame,
173 so we get the "first frame" of the "animation", which is our quake level
174 and create an Octree scene node with it, using addOctreeSceneNode().
175 The Octree optimizes the scene a little bit, trying to draw only geometry
176 which is currently visible. An alternative to the Octree would be a
177 AnimatedMeshSceneNode, which would draw always the complete geometry of
178 the mesh, without optimization. Try it out: Write addAnimatedMeshSceneNode
179 instead of addOctreeSceneNode and compare the primitives drawn by the
180 video driver. (There is a getPrimitiveCountDrawed() method in the
181 IVideoDriver class). Note that this optimization with the Octree is only
182 useful when drawing huge meshes consisting of lots of geometry.
183 */
184 scene::IQ3LevelMesh* const mesh =
185 (scene::IQ3LevelMesh*) smgr->getMesh(mapname);
186
187 /*
188 add the geometry mesh to the Scene ( polygon & patches )
189 The Geometry mesh is optimised for faster drawing
190 */
191 scene::ISceneNode* node = 0;
192 if (mesh)
193 {
194 scene::IMesh * const geometry = mesh->getMesh(quake3::E_Q3_MESH_GEOMETRY);
195 node = smgr->addOctreeSceneNode(geometry, 0, -1, 4096);
196 }
197
198 // create an event receiver for making screenshots
199 CScreenShotFactory screenshotFactory(device, mapname, node);
200 device->setEventReceiver(&screenshotFactory);
201
202 /*
203 now construct SceneNodes for each Shader
204 The Objects are stored in the quake mesh scene::E_Q3_MESH_ITEMS
205 and the Shader ID is stored in the MaterialParameters
206 mostly dark looking skulls and moving lava.. or green flashing tubes?
207 */
208 if ( mesh )
209 {
210 // the additional mesh can be quite huge and is unoptimized
211 const scene::IMesh * const additional_mesh = mesh->getMesh(quake3::E_Q3_MESH_ITEMS);
212
213#ifdef SHOW_SHADER_NAME
214 gui::IGUIFont *font = device->getGUIEnvironment()->getFont("../../media/fontlucida.png");
215 u32 count = 0;
216#endif
217
218 for ( u32 i = 0; i!= additional_mesh->getMeshBufferCount(); ++i )
219 {
220 const IMeshBuffer* meshBuffer = additional_mesh->getMeshBuffer(i);
221 const video::SMaterial& material = meshBuffer->getMaterial();
222
223 // The ShaderIndex is stored in the material parameter
224 const s32 shaderIndex = (s32) material.MaterialTypeParam2;
225
226 // the meshbuffer can be rendered without additional support, or it has no shader
227 const quake3::IShader *shader = mesh->getShader(shaderIndex);
228 if (0 == shader)
229 {
230 continue;
231 }
232
233 // we can dump the shader to the console in its
234 // original but already parsed layout in a pretty
235 // printers way.. commented out, because the console
236 // would be full...
237 // quake3::dumpShader ( Shader );
238
239 node = smgr->addQuake3SceneNode(meshBuffer, shader);
240
241#ifdef SHOW_SHADER_NAME
242 count += 1;
243 core::stringw name( node->getName() );
244 node = smgr->addBillboardTextSceneNode(
245 font, name.c_str(), node,
246 core::dimension2d<f32>(80.0f, 8.0f),
247 core::vector3df(0, 10, 0));
248#endif
249 }
250 }
251
252 /*
253 Now we only need a Camera to look at the Quake 3 map. And we want to
254 create a user controlled camera. There are some different cameras
255 available in the Irrlicht engine. For example the Maya Camera which can
256 be controlled comparable to the camera in Maya: Rotate with left mouse
257 button pressed, Zoom with both buttons pressed, translate with right
258 mouse button pressed. This could be created with
259 addCameraSceneNodeMaya(). But for this example, we want to create a
260 camera which behaves like the ones in first person shooter games (FPS).
261 */
262
263 scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
264
265 /*
266 so we need a good starting Position in the level.
267 we can ask the Quake3 Loader for all entities with class_name
268 "info_player_deathmatch"
269 we choose a random launch
270 */
271 if ( mesh )
272 {
273 quake3::tQ3EntityList &entityList = mesh->getEntityList();
274
275 quake3::IEntity search;
276 search.name = "info_player_deathmatch";
277
278 s32 index = entityList.binary_search(search);
279 if (index >= 0)
280 {
281 s32 notEndList;
282 do
283 {
284 const quake3::SVarGroup *group = entityList[index].getGroup(1);
285
286 u32 parsepos = 0;
287 const core::vector3df pos =
288 quake3::getAsVector3df(group->get("origin"), parsepos);
289
290 parsepos = 0;
291 const f32 angle = quake3::getAsFloat(group->get("angle"), parsepos);
292
293 core::vector3df target(0.f, 0.f, 1.f);
294 target.rotateXZBy(angle);
295
296 camera->setPosition(pos);
297 camera->setTarget(pos + target);
298
299 ++index;
300/*
301 notEndList = ( index < (s32) entityList.size () &&
302 entityList[index].name == search.name &&
303 (device->getTimer()->getRealTime() >> 3 ) & 1
304 );
305*/
306 notEndList = index == 2;
307 } while ( notEndList );
308 }
309 }
310
311 /*
312 The mouse cursor needs not to be visible, so we make it invisible.
313 */
314
315 device->getCursorControl()->setVisible(false);
316
317 // load the engine logo
318 gui->addImage(driver->getTexture("irrlichtlogo2.png"),
319 core::position2d<s32>(10, 10));
320
321 // show the driver logo
322 const core::position2di pos(videoDim.Width - 128, videoDim.Height - 64);
323
324 switch ( driverType )
325 {
326 case video::EDT_BURNINGSVIDEO:
327 gui->addImage(driver->getTexture("burninglogo.png"), pos);
328 break;
329 case video::EDT_OPENGL:
330 gui->addImage(driver->getTexture("opengllogo.png"), pos);
331 break;
332 case video::EDT_DIRECT3D8:
333 case video::EDT_DIRECT3D9:
334 gui->addImage(driver->getTexture("directxlogo.png"), pos);
335 break;
336 }
337
338 /*
339 We have done everything, so lets draw it. We also write the current
340 frames per second and the drawn primitives to the caption of the
341 window. The 'if (device->isWindowActive())' line is optional, but
342 prevents the engine render to set the position of the mouse cursor
343 after task switching when other program are active.
344 */
345 int lastFPS = -1;
346
347 while(device->run())
348 if (device->isWindowActive())
349 {
350 driver->beginScene(true, true, video::SColor(255,20,20,40));
351 smgr->drawAll();
352 gui->drawAll();
353 driver->endScene();
354
355 int fps = driver->getFPS();
356 //if (lastFPS != fps)
357 {
358 io::IAttributes * const attr = smgr->getParameters();
359 core::stringw str = L"Q3 [";
360 str += driver->getName();
361 str += "] FPS:";
362 str += fps;
363#ifdef _IRR_SCENEMANAGER_DEBUG
364 str += " Cull:";
365 str += attr->getAttributeAsInt("calls");
366 str += "/";
367 str += attr->getAttributeAsInt("culled");
368 str += " Draw: ";
369 str += attr->getAttributeAsInt("drawn_solid");
370 str += "/";
371 str += attr->getAttributeAsInt("drawn_transparent");
372 str += "/";
373 str += attr->getAttributeAsInt("drawn_transparent_effect");
374#endif
375 device->setWindowCaption(str.c_str());
376 lastFPS = fps;
377 }
378 }
379
380 /*
381 In the end, delete the Irrlicht device.
382 */
383 device->drop();
384
385 return 0;
386}
387
388/*
389**/