]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CNullDriver.cpp
Replace HWBufferMap with a list and back pointers (#99)
[irrlicht.git] / source / Irrlicht / CNullDriver.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "CNullDriver.h"\r
6 #include "os.h"\r
7 #include "CImage.h"\r
8 #include "CAttributes.h"\r
9 #include "IReadFile.h"\r
10 #include "IWriteFile.h"\r
11 #include "IImageLoader.h"\r
12 #include "IImageWriter.h"\r
13 #include "IMaterialRenderer.h"\r
14 #include "IAnimatedMeshSceneNode.h"\r
15 #include "CMeshManipulator.h"\r
16 #include "CColorConverter.h"\r
17 #include "IReferenceCounted.h"\r
18 #include "IRenderTarget.h"\r
19 \r
20 \r
21 namespace irr\r
22 {\r
23 namespace video\r
24 {\r
25 \r
26 //! creates a loader which is able to load windows bitmaps\r
27 IImageLoader* createImageLoaderBMP();\r
28 \r
29 //! creates a loader which is able to load jpeg images\r
30 IImageLoader* createImageLoaderJPG();\r
31 \r
32 //! creates a loader which is able to load targa images\r
33 IImageLoader* createImageLoaderTGA();\r
34 \r
35 //! creates a loader which is able to load psd images\r
36 IImageLoader* createImageLoaderPSD();\r
37 \r
38 //! creates a loader which is able to load psd images\r
39 IImageLoader* createImageLoaderPVR();\r
40 \r
41 //! creates a loader which is able to load dds images\r
42 IImageLoader* createImageLoaderDDS();\r
43 \r
44 //! creates a loader which is able to load pcx images\r
45 IImageLoader* createImageLoaderPCX();\r
46 \r
47 //! creates a loader which is able to load png images\r
48 IImageLoader* createImageLoaderPNG();\r
49 \r
50 //! creates a loader which is able to load WAL images\r
51 IImageLoader* createImageLoaderWAL();\r
52 \r
53 //! creates a loader which is able to load halflife images\r
54 IImageLoader* createImageLoaderHalfLife();\r
55 \r
56 //! creates a loader which is able to load lmp images\r
57 IImageLoader* createImageLoaderLMP();\r
58 \r
59 //! creates a loader which is able to load ppm/pgm/pbm images\r
60 IImageLoader* createImageLoaderPPM();\r
61 \r
62 //! creates a loader which is able to load rgb images\r
63 IImageLoader* createImageLoaderRGB();\r
64 \r
65 \r
66 //! creates a writer which is able to save bmp images\r
67 IImageWriter* createImageWriterBMP();\r
68 \r
69 //! creates a writer which is able to save jpg images\r
70 IImageWriter* createImageWriterJPG();\r
71 \r
72 //! creates a writer which is able to save tga images\r
73 IImageWriter* createImageWriterTGA();\r
74 \r
75 //! creates a writer which is able to save psd images\r
76 IImageWriter* createImageWriterPSD();\r
77 \r
78 //! creates a writer which is able to save pcx images\r
79 IImageWriter* createImageWriterPCX();\r
80 \r
81 //! creates a writer which is able to save png images\r
82 IImageWriter* createImageWriterPNG();\r
83 \r
84 //! creates a writer which is able to save ppm images\r
85 IImageWriter* createImageWriterPPM();\r
86 \r
87 //! constructor\r
88 CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)\r
89         : SharedRenderTarget(0), CurrentRenderTarget(0), CurrentRenderTargetSize(0, 0), FileSystem(io), MeshManipulator(0),\r
90         ViewPort(0, 0, 0, 0), ScreenSize(screenSize), PrimitivesDrawn(0), MinVertexCountForVBO(500),\r
91         TextureCreationFlags(0), OverrideMaterial2DEnabled(false), AllowZWriteOnTransparent(false)\r
92 {\r
93         #ifdef _DEBUG\r
94         setDebugName("CNullDriver");\r
95         #endif\r
96 \r
97         DriverAttributes = new io::CAttributes();\r
98         DriverAttributes->addInt("MaxTextures", _IRR_MATERIAL_MAX_TEXTURES_);\r
99         DriverAttributes->addInt("MaxSupportedTextures", _IRR_MATERIAL_MAX_TEXTURES_);\r
100         DriverAttributes->addInt("MaxLights", getMaximalDynamicLightAmount());\r
101         DriverAttributes->addInt("MaxAnisotropy", 1);\r
102 //      DriverAttributes->addInt("MaxUserClipPlanes", 0);\r
103 //      DriverAttributes->addInt("MaxAuxBuffers", 0);\r
104         DriverAttributes->addInt("MaxMultipleRenderTargets", 1);\r
105         DriverAttributes->addInt("MaxIndices", -1);\r
106         DriverAttributes->addInt("MaxTextureSize", -1);\r
107 //      DriverAttributes->addInt("MaxGeometryVerticesOut", 0);\r
108 //      DriverAttributes->addFloat("MaxTextureLODBias", 0.f);\r
109         DriverAttributes->addInt("Version", 1);\r
110 //      DriverAttributes->addInt("ShaderLanguageVersion", 0);\r
111 //      DriverAttributes->addInt("AntiAlias", 0);\r
112 \r
113         setFog();\r
114 \r
115         setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true);\r
116         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, true);\r
117         setTextureCreationFlag(ETCF_AUTO_GENERATE_MIP_MAPS, true);\r
118         setTextureCreationFlag(ETCF_ALLOW_MEMORY_COPY, true);\r
119 \r
120         ViewPort = core::rect<s32>(core::position2d<s32>(0,0), core::dimension2di(screenSize));\r
121 \r
122         // create manipulator\r
123         MeshManipulator = new scene::CMeshManipulator();\r
124 \r
125         if (FileSystem)\r
126                 FileSystem->grab();\r
127 \r
128         // create surface loader\r
129 \r
130 #ifdef _IRR_COMPILE_WITH_WAL_LOADER_\r
131         SurfaceLoader.push_back(video::createImageLoaderHalfLife());\r
132         SurfaceLoader.push_back(video::createImageLoaderWAL());\r
133 #endif\r
134 #ifdef _IRR_COMPILE_WITH_LMP_LOADER_\r
135         SurfaceLoader.push_back(video::createImageLoaderLMP());\r
136 #endif\r
137 #ifdef _IRR_COMPILE_WITH_PPM_LOADER_\r
138         SurfaceLoader.push_back(video::createImageLoaderPPM());\r
139 #endif\r
140 #ifdef _IRR_COMPILE_WITH_RGB_LOADER_\r
141         SurfaceLoader.push_back(video::createImageLoaderRGB());\r
142 #endif\r
143 #ifdef _IRR_COMPILE_WITH_PSD_LOADER_\r
144         SurfaceLoader.push_back(video::createImageLoaderPSD());\r
145 #endif\r
146 #ifdef _IRR_COMPILE_WITH_PVR_LOADER_\r
147         SurfaceLoader.push_back(video::createImageLoaderPVR());\r
148 #endif\r
149 #if defined(_IRR_COMPILE_WITH_DDS_LOADER_) || defined(_IRR_COMPILE_WITH_DDS_DECODER_LOADER_)\r
150         SurfaceLoader.push_back(video::createImageLoaderDDS());\r
151 #endif\r
152 #ifdef _IRR_COMPILE_WITH_PCX_LOADER_\r
153         SurfaceLoader.push_back(video::createImageLoaderPCX());\r
154 #endif\r
155 #ifdef _IRR_COMPILE_WITH_TGA_LOADER_\r
156         SurfaceLoader.push_back(video::createImageLoaderTGA());\r
157 #endif\r
158 #ifdef _IRR_COMPILE_WITH_PNG_LOADER_\r
159         SurfaceLoader.push_back(video::createImageLoaderPNG());\r
160 #endif\r
161 #ifdef _IRR_COMPILE_WITH_JPG_LOADER_\r
162         SurfaceLoader.push_back(video::createImageLoaderJPG());\r
163 #endif\r
164 #ifdef _IRR_COMPILE_WITH_BMP_LOADER_\r
165         SurfaceLoader.push_back(video::createImageLoaderBMP());\r
166 #endif\r
167 \r
168 \r
169 #ifdef _IRR_COMPILE_WITH_PPM_WRITER_\r
170         SurfaceWriter.push_back(video::createImageWriterPPM());\r
171 #endif\r
172 #ifdef _IRR_COMPILE_WITH_PCX_WRITER_\r
173         SurfaceWriter.push_back(video::createImageWriterPCX());\r
174 #endif\r
175 #ifdef _IRR_COMPILE_WITH_PSD_WRITER_\r
176         SurfaceWriter.push_back(video::createImageWriterPSD());\r
177 #endif\r
178 #ifdef _IRR_COMPILE_WITH_TGA_WRITER_\r
179         SurfaceWriter.push_back(video::createImageWriterTGA());\r
180 #endif\r
181 #ifdef _IRR_COMPILE_WITH_JPG_WRITER_\r
182         SurfaceWriter.push_back(video::createImageWriterJPG());\r
183 #endif\r
184 #ifdef _IRR_COMPILE_WITH_PNG_WRITER_\r
185         SurfaceWriter.push_back(video::createImageWriterPNG());\r
186 #endif\r
187 #ifdef _IRR_COMPILE_WITH_BMP_WRITER_\r
188         SurfaceWriter.push_back(video::createImageWriterBMP());\r
189 #endif\r
190 \r
191 \r
192         // set ExposedData to 0\r
193         memset((void*)&ExposedData, 0, sizeof(ExposedData));\r
194         for (u32 i=0; i<video::EVDF_COUNT; ++i)\r
195                 FeatureEnabled[i]=true;\r
196 \r
197         InitMaterial2D.AntiAliasing=video::EAAM_OFF;\r
198         InitMaterial2D.Lighting=false;\r
199         InitMaterial2D.ZWriteEnable=video::EZW_OFF;\r
200         InitMaterial2D.ZBuffer=video::ECFN_DISABLED;\r
201         InitMaterial2D.UseMipMaps=false;\r
202         for (u32 i=0; i<video::MATERIAL_MAX_TEXTURES; ++i)\r
203         {\r
204                 InitMaterial2D.TextureLayer[i].BilinearFilter=false;\r
205                 InitMaterial2D.TextureLayer[i].TextureWrapU=video::ETC_REPEAT;\r
206                 InitMaterial2D.TextureLayer[i].TextureWrapV=video::ETC_REPEAT;\r
207                 InitMaterial2D.TextureLayer[i].TextureWrapW = video::ETC_REPEAT;\r
208         }\r
209         OverrideMaterial2D=InitMaterial2D;\r
210 }\r
211 \r
212 \r
213 //! destructor\r
214 CNullDriver::~CNullDriver()\r
215 {\r
216         if (DriverAttributes)\r
217                 DriverAttributes->drop();\r
218 \r
219         if (FileSystem)\r
220                 FileSystem->drop();\r
221 \r
222         if (MeshManipulator)\r
223                 MeshManipulator->drop();\r
224 \r
225         removeAllRenderTargets();\r
226 \r
227         deleteAllTextures();\r
228 \r
229         u32 i;\r
230         for (i=0; i<SurfaceLoader.size(); ++i)\r
231                 SurfaceLoader[i]->drop();\r
232 \r
233         for (i=0; i<SurfaceWriter.size(); ++i)\r
234                 SurfaceWriter[i]->drop();\r
235 \r
236         // delete material renderers\r
237         deleteMaterialRenders();\r
238 \r
239         // delete hardware mesh buffers\r
240         removeAllHardwareBuffers();\r
241 }\r
242 \r
243 \r
244 //! Adds an external surface loader to the engine.\r
245 void CNullDriver::addExternalImageLoader(IImageLoader* loader)\r
246 {\r
247         if (!loader)\r
248                 return;\r
249 \r
250         loader->grab();\r
251         SurfaceLoader.push_back(loader);\r
252 }\r
253 \r
254 \r
255 //! Adds an external surface writer to the engine.\r
256 void CNullDriver::addExternalImageWriter(IImageWriter* writer)\r
257 {\r
258         if (!writer)\r
259                 return;\r
260 \r
261         writer->grab();\r
262         SurfaceWriter.push_back(writer);\r
263 }\r
264 \r
265 \r
266 //! Retrieve the number of image loaders\r
267 u32 CNullDriver::getImageLoaderCount() const\r
268 {\r
269         return SurfaceLoader.size();\r
270 }\r
271 \r
272 \r
273 //! Retrieve the given image loader\r
274 IImageLoader* CNullDriver::getImageLoader(u32 n)\r
275 {\r
276         if (n < SurfaceLoader.size())\r
277                 return SurfaceLoader[n];\r
278         return 0;\r
279 }\r
280 \r
281 \r
282 //! Retrieve the number of image writers\r
283 u32 CNullDriver::getImageWriterCount() const\r
284 {\r
285         return SurfaceWriter.size();\r
286 }\r
287 \r
288 \r
289 //! Retrieve the given image writer\r
290 IImageWriter* CNullDriver::getImageWriter(u32 n)\r
291 {\r
292         if (n < SurfaceWriter.size())\r
293                 return SurfaceWriter[n];\r
294         return 0;\r
295 }\r
296 \r
297 \r
298 //! deletes all textures\r
299 void CNullDriver::deleteAllTextures()\r
300 {\r
301         // we need to remove previously set textures which might otherwise be kept in the\r
302         // last set material member. Could be optimized to reduce state changes.\r
303         setMaterial(SMaterial());\r
304 \r
305         // reset render targets.\r
306 \r
307         for (u32 i=0; i<RenderTargets.size(); ++i)\r
308                 RenderTargets[i]->setTexture(0, 0);\r
309 \r
310         // remove textures.\r
311 \r
312         for (u32 i=0; i<Textures.size(); ++i)\r
313                 Textures[i].Surface->drop();\r
314 \r
315         Textures.clear();\r
316 \r
317         SharedDepthTextures.clear();\r
318 }\r
319 \r
320 bool CNullDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect<s32>* sourceRect)\r
321 {\r
322         PrimitivesDrawn = 0;\r
323         return true;\r
324 }\r
325 \r
326 bool CNullDriver::endScene()\r
327 {\r
328         FPSCounter.registerFrame(os::Timer::getRealTime(), PrimitivesDrawn);\r
329         updateAllHardwareBuffers();\r
330         updateAllOcclusionQueries();\r
331         return true;\r
332 }\r
333 \r
334 \r
335 //! Disable a feature of the driver.\r
336 void CNullDriver::disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag)\r
337 {\r
338         FeatureEnabled[feature]=!flag;\r
339 }\r
340 \r
341 \r
342 //! queries the features of the driver, returns true if feature is available\r
343 bool CNullDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const\r
344 {\r
345         return false;\r
346 }\r
347 \r
348 \r
349 //! Get attributes of the actual video driver\r
350 const io::IAttributes& CNullDriver::getDriverAttributes() const\r
351 {\r
352         return *DriverAttributes;\r
353 }\r
354 \r
355 \r
356 //! sets transformation\r
357 void CNullDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)\r
358 {\r
359 }\r
360 \r
361 \r
362 //! Returns the transformation set by setTransform\r
363 const core::matrix4& CNullDriver::getTransform(E_TRANSFORMATION_STATE state) const\r
364 {\r
365         return TransformationMatrix;\r
366 }\r
367 \r
368 \r
369 //! sets a material\r
370 void CNullDriver::setMaterial(const SMaterial& material)\r
371 {\r
372 }\r
373 \r
374 \r
375 //! Removes a texture from the texture cache and deletes it, freeing lot of\r
376 //! memory.\r
377 void CNullDriver::removeTexture(ITexture* texture)\r
378 {\r
379         if (!texture)\r
380                 return;\r
381 \r
382         for (u32 i=0; i<Textures.size(); ++i)\r
383         {\r
384                 if (Textures[i].Surface == texture)\r
385                 {\r
386                         texture->drop();\r
387                         Textures.erase(i);\r
388                         return;\r
389                 }\r
390         }\r
391 }\r
392 \r
393 \r
394 //! Removes all texture from the texture cache and deletes them, freeing lot of\r
395 //! memory.\r
396 void CNullDriver::removeAllTextures()\r
397 {\r
398         setMaterial ( SMaterial() );\r
399         deleteAllTextures();\r
400 }\r
401 \r
402 \r
403 //! Returns a texture by index\r
404 ITexture* CNullDriver::getTextureByIndex(u32 i)\r
405 {\r
406         if ( i < Textures.size() )\r
407                 return Textures[i].Surface;\r
408 \r
409         return 0;\r
410 }\r
411 \r
412 \r
413 //! Returns amount of textures currently loaded\r
414 u32 CNullDriver::getTextureCount() const\r
415 {\r
416         return Textures.size();\r
417 }\r
418 \r
419 \r
420 //! Renames a texture\r
421 void CNullDriver::renameTexture(ITexture* texture, const io::path& newName)\r
422 {\r
423         // we can do a const_cast here safely, the name of the ITexture interface\r
424         // is just readonly to prevent the user changing the texture name without invoking\r
425         // this method, because the textures will need resorting afterwards\r
426 \r
427         io::SNamedPath& name = const_cast<io::SNamedPath&>(texture->getName());\r
428         name.setPath(newName);\r
429 \r
430         Textures.sort();\r
431 }\r
432 \r
433 ITexture* CNullDriver::addTexture(const core::dimension2d<u32>& size, const io::path& name, ECOLOR_FORMAT format)\r
434 {\r
435         if (0 == name.size())\r
436         {\r
437                 os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);\r
438                 return 0;\r
439         }\r
440 \r
441         IImage* image = new CImage(format, size);\r
442         ITexture* t = 0;\r
443 \r
444         core::array<IImage*> imageArray(1);\r
445         imageArray.push_back(image);\r
446 \r
447         if (checkImage(imageArray))\r
448         {\r
449                 t = createDeviceDependentTexture(name, image);\r
450         }\r
451 \r
452         image->drop();\r
453 \r
454         if (t)\r
455         {\r
456                 addTexture(t);\r
457                 t->drop();\r
458         }\r
459 \r
460         return t;\r
461 }\r
462 \r
463 ITexture* CNullDriver::addTexture(const io::path& name, IImage* image)\r
464 {\r
465         if (0 == name.size())\r
466         {\r
467                 os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);\r
468                 return 0;\r
469         }\r
470 \r
471         if (!image)\r
472                 return 0;\r
473 \r
474         ITexture* t = 0;\r
475 \r
476         core::array<IImage*> imageArray(1);\r
477         imageArray.push_back(image);\r
478 \r
479         if (checkImage(imageArray))\r
480         {\r
481                 t = createDeviceDependentTexture(name, image);\r
482         }\r
483 \r
484         if (t)\r
485         {\r
486                 addTexture(t);\r
487                 t->drop();\r
488         }\r
489 \r
490         return t;\r
491 }\r
492 \r
493 ITexture* CNullDriver::addTextureCubemap(const io::path& name, IImage* imagePosX, IImage* imageNegX, IImage* imagePosY,\r
494         IImage* imageNegY, IImage* imagePosZ, IImage* imageNegZ)\r
495 {\r
496         if (0 == name.size() || !imagePosX || !imageNegX || !imagePosY || !imageNegY || !imagePosZ || !imageNegZ)\r
497                 return 0;\r
498 \r
499         ITexture* t = 0;\r
500 \r
501         core::array<IImage*> imageArray(6);\r
502         imageArray.push_back(imagePosX);\r
503         imageArray.push_back(imageNegX);\r
504         imageArray.push_back(imagePosY);\r
505         imageArray.push_back(imageNegY);\r
506         imageArray.push_back(imagePosZ);\r
507         imageArray.push_back(imageNegZ);\r
508 \r
509         if (checkImage(imageArray))\r
510         {\r
511                 t = createDeviceDependentTextureCubemap(name, imageArray);\r
512         }\r
513 \r
514         if (t)\r
515         {\r
516                 addTexture(t);\r
517                 t->drop();\r
518         }\r
519 \r
520         return t;\r
521 }\r
522 \r
523 ITexture* CNullDriver::addTextureCubemap(const irr::u32 sideLen, const io::path& name, ECOLOR_FORMAT format)\r
524 {\r
525         if ( 0 == sideLen )\r
526                 return 0;\r
527 \r
528         if (0 == name.size())\r
529         {\r
530                 os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);\r
531                 return 0;\r
532         }\r
533 \r
534         core::array<IImage*> imageArray(6);\r
535         for ( int i=0; i < 6; ++i )\r
536                 imageArray.push_back(new CImage(format, core::dimension2du(sideLen, sideLen)));\r
537 \r
538         ITexture* t = 0;\r
539         if (checkImage(imageArray))\r
540         {\r
541                 t = createDeviceDependentTextureCubemap(name, imageArray);\r
542 \r
543                 if (t)\r
544                 {\r
545                         addTexture(t);\r
546                         t->drop();\r
547                 }\r
548         }\r
549 \r
550         for ( int i=0; i < 6; ++i )\r
551                 imageArray[i]->drop();\r
552 \r
553         return t;\r
554 }\r
555 \r
556 //! loads a Texture\r
557 ITexture* CNullDriver::getTexture(const io::path& filename)\r
558 {\r
559         // Identify textures by their absolute filenames if possible.\r
560         const io::path absolutePath = FileSystem->getAbsolutePath(filename);\r
561 \r
562         ITexture* texture = findTexture(absolutePath);\r
563         if (texture)\r
564         {\r
565                 texture->updateSource(ETS_FROM_CACHE);\r
566                 return texture;\r
567         }\r
568 \r
569         // Then try the raw filename, which might be in an Archive\r
570         texture = findTexture(filename);\r
571         if (texture)\r
572         {\r
573                 texture->updateSource(ETS_FROM_CACHE);\r
574                 return texture;\r
575         }\r
576 \r
577         // Now try to open the file using the complete path.\r
578         io::IReadFile* file = FileSystem->createAndOpenFile(absolutePath);\r
579 \r
580         if (!file)\r
581         {\r
582                 // Try to open it using the raw filename.\r
583                 file = FileSystem->createAndOpenFile(filename);\r
584         }\r
585 \r
586         if (file)\r
587         {\r
588                 // Re-check name for actual archive names\r
589                 texture = findTexture(file->getFileName());\r
590                 if (texture)\r
591                 {\r
592                         texture->updateSource(ETS_FROM_CACHE);\r
593                         file->drop();\r
594                         return texture;\r
595                 }\r
596 \r
597                 texture = loadTextureFromFile(file);\r
598                 file->drop();\r
599 \r
600                 if (texture)\r
601                 {\r
602                         texture->updateSource(ETS_FROM_FILE);\r
603                         addTexture(texture);\r
604                         texture->drop(); // drop it because we created it, one grab too much\r
605                 }\r
606                 else\r
607                         os::Printer::log("Could not load texture", filename, ELL_ERROR);\r
608                 return texture;\r
609         }\r
610         else\r
611         {\r
612                 os::Printer::log("Could not open file of texture", filename, ELL_WARNING);\r
613                 return 0;\r
614         }\r
615 }\r
616 \r
617 \r
618 //! loads a Texture\r
619 ITexture* CNullDriver::getTexture(io::IReadFile* file)\r
620 {\r
621         ITexture* texture = 0;\r
622 \r
623         if (file)\r
624         {\r
625                 texture = findTexture(file->getFileName());\r
626 \r
627                 if (texture)\r
628                 {\r
629                         texture->updateSource(ETS_FROM_CACHE);\r
630                         return texture;\r
631                 }\r
632 \r
633                 texture = loadTextureFromFile(file);\r
634 \r
635                 if (texture)\r
636                 {\r
637                         texture->updateSource(ETS_FROM_FILE);\r
638                         addTexture(texture);\r
639                         texture->drop(); // drop it because we created it, one grab too much\r
640                 }\r
641 \r
642                 if (!texture)\r
643                         os::Printer::log("Could not load texture", file->getFileName(), ELL_WARNING);\r
644         }\r
645 \r
646         return texture;\r
647 }\r
648 \r
649 \r
650 //! opens the file and loads it into the surface\r
651 video::ITexture* CNullDriver::loadTextureFromFile(io::IReadFile* file, const io::path& hashName )\r
652 {\r
653         ITexture* texture = 0;\r
654 \r
655         E_TEXTURE_TYPE type = ETT_2D;\r
656 \r
657         core::array<IImage*> imageArray = createImagesFromFile(file, &type);\r
658 \r
659         if (checkImage(imageArray))\r
660         {\r
661                 switch (type)\r
662                 {\r
663                 case ETT_2D:\r
664                         texture = createDeviceDependentTexture(hashName.size() ? hashName : file->getFileName(), imageArray[0]);\r
665                         break;\r
666                 case ETT_CUBEMAP:\r
667                         if (imageArray.size() >= 6 && imageArray[0] && imageArray[1] && imageArray[2] && imageArray[3] && imageArray[4] && imageArray[5])\r
668                         {\r
669                                 texture = createDeviceDependentTextureCubemap(hashName.size() ? hashName : file->getFileName(), imageArray);\r
670                         }\r
671                         break;\r
672                 default:\r
673                         _IRR_DEBUG_BREAK_IF(true);\r
674                         break;\r
675                 }\r
676 \r
677                 if (texture)\r
678                         os::Printer::log("Loaded texture", file->getFileName(), ELL_DEBUG);\r
679         }\r
680 \r
681         for (u32 i = 0; i < imageArray.size(); ++i)\r
682         {\r
683                 if (imageArray[i])\r
684                         imageArray[i]->drop();\r
685         }\r
686 \r
687         return texture;\r
688 }\r
689 \r
690 \r
691 //! adds a surface, not loaded or created by the Irrlicht Engine\r
692 void CNullDriver::addTexture(video::ITexture* texture)\r
693 {\r
694         if (texture)\r
695         {\r
696                 SSurface s;\r
697                 s.Surface = texture;\r
698                 texture->grab();\r
699 \r
700                 Textures.push_back(s);\r
701 \r
702                 // the new texture is now at the end of the texture list. when searching for\r
703                 // the next new texture, the texture array will be sorted and the index of this texture\r
704                 // will be changed. to let the order be more consistent to the user, sort\r
705                 // the textures now already although this isn't necessary:\r
706 \r
707                 Textures.sort();\r
708         }\r
709 }\r
710 \r
711 \r
712 //! looks if the image is already loaded\r
713 video::ITexture* CNullDriver::findTexture(const io::path& filename)\r
714 {\r
715         SSurface s;\r
716         SDummyTexture dummy(filename, ETT_2D);\r
717         s.Surface = &dummy;\r
718 \r
719         s32 index = Textures.binary_search(s);\r
720         if (index != -1)\r
721                 return Textures[index].Surface;\r
722 \r
723         return 0;\r
724 }\r
725 \r
726 ITexture* CNullDriver::createDeviceDependentTexture(const io::path& name, IImage* image)\r
727 {\r
728         SDummyTexture* dummy = new SDummyTexture(name, ETT_2D);\r
729         dummy->setSize(image->getDimension());\r
730         return dummy;\r
731 }\r
732 \r
733 ITexture* CNullDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)\r
734 {\r
735         return new SDummyTexture(name, ETT_CUBEMAP);\r
736 }\r
737 \r
738 bool CNullDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)\r
739 {\r
740         return false;\r
741 }\r
742 \r
743 bool CNullDriver::setRenderTarget(ITexture* texture, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)\r
744 {\r
745         if (texture)\r
746         {\r
747                 // create render target if require.\r
748                 if (!SharedRenderTarget)\r
749                         SharedRenderTarget = addRenderTarget();\r
750 \r
751                 ITexture* depthTexture = 0;\r
752 \r
753                 // try to find available depth texture with require size.\r
754                 for (u32 i = 0; i < SharedDepthTextures.size(); ++i)\r
755                 {\r
756                         if (SharedDepthTextures[i]->getSize() == texture->getSize())\r
757                         {\r
758                                 depthTexture = SharedDepthTextures[i];\r
759 \r
760                                 break;\r
761                         }\r
762                 }\r
763 \r
764                 // create depth texture if require.\r
765                 if (!depthTexture)\r
766                 {\r
767                         depthTexture = addRenderTargetTexture(texture->getSize(), "IRR_DEPTH_STENCIL", video::ECF_D24S8);\r
768                         SharedDepthTextures.push_back(depthTexture);\r
769                 }\r
770 \r
771                 SharedRenderTarget->setTexture(texture, depthTexture);\r
772 \r
773                 return setRenderTargetEx(SharedRenderTarget, clearFlag, clearColor, clearDepth, clearStencil);\r
774         }\r
775         else\r
776         {\r
777                 return setRenderTargetEx(0, clearFlag, clearColor, clearDepth, clearStencil);\r
778         }\r
779 }\r
780 \r
781 //! sets a viewport\r
782 void CNullDriver::setViewPort(const core::rect<s32>& area)\r
783 {\r
784 }\r
785 \r
786 \r
787 //! gets the area of the current viewport\r
788 const core::rect<s32>& CNullDriver::getViewPort() const\r
789 {\r
790         return ViewPort;\r
791 }\r
792 \r
793 \r
794 //! draws a vertex primitive list\r
795 void CNullDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, const void* indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)\r
796 {\r
797         if ((iType==EIT_16BIT) && (vertexCount>65536))\r
798                 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");\r
799         PrimitivesDrawn += primitiveCount;\r
800 }\r
801 \r
802 \r
803 //! draws a vertex primitive list in 2d\r
804 void CNullDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, const void* indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)\r
805 {\r
806         if ((iType==EIT_16BIT) && (vertexCount>65536))\r
807                 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");\r
808         PrimitivesDrawn += primitiveCount;\r
809 }\r
810 \r
811 \r
812 //! Draws a 3d line.\r
813 void CNullDriver::draw3DLine(const core::vector3df& start,\r
814                                 const core::vector3df& end, SColor color)\r
815 {\r
816 }\r
817 \r
818 \r
819 //! Draws a 3d triangle.\r
820 void CNullDriver::draw3DTriangle(const core::triangle3df& triangle, SColor color)\r
821 {\r
822         S3DVertex vertices[3];\r
823         vertices[0].Pos=triangle.pointA;\r
824         vertices[0].Color=color;\r
825         vertices[0].Normal=triangle.getNormal().normalize();\r
826         vertices[0].TCoords.set(0.f,0.f);\r
827         vertices[1].Pos=triangle.pointB;\r
828         vertices[1].Color=color;\r
829         vertices[1].Normal=vertices[0].Normal;\r
830         vertices[1].TCoords.set(0.5f,1.f);\r
831         vertices[2].Pos=triangle.pointC;\r
832         vertices[2].Color=color;\r
833         vertices[2].Normal=vertices[0].Normal;\r
834         vertices[2].TCoords.set(1.f,0.f);\r
835         const u16 indexList[] = {0,1,2};\r
836         drawVertexPrimitiveList(vertices, 3, indexList, 1, EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT);\r
837 }\r
838 \r
839 \r
840 //! Draws a 3d axis aligned box.\r
841 void CNullDriver::draw3DBox(const core::aabbox3d<f32>& box, SColor color)\r
842 {\r
843         core::vector3df edges[8];\r
844         box.getEdges(edges);\r
845 \r
846         // TODO: optimize into one big drawIndexPrimitive call.\r
847 \r
848         draw3DLine(edges[5], edges[1], color);\r
849         draw3DLine(edges[1], edges[3], color);\r
850         draw3DLine(edges[3], edges[7], color);\r
851         draw3DLine(edges[7], edges[5], color);\r
852         draw3DLine(edges[0], edges[2], color);\r
853         draw3DLine(edges[2], edges[6], color);\r
854         draw3DLine(edges[6], edges[4], color);\r
855         draw3DLine(edges[4], edges[0], color);\r
856         draw3DLine(edges[1], edges[0], color);\r
857         draw3DLine(edges[3], edges[2], color);\r
858         draw3DLine(edges[7], edges[6], color);\r
859         draw3DLine(edges[5], edges[4], color);\r
860 }\r
861 \r
862 \r
863 \r
864 //! draws an 2d image\r
865 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos, bool useAlphaChannelOfTexture)\r
866 {\r
867         if (!texture)\r
868                 return;\r
869 \r
870         draw2DImage(texture,destPos, core::rect<s32>(core::position2d<s32>(0,0),\r
871                                                                                                 core::dimension2di(texture->getOriginalSize())),\r
872                                                                                                 0,\r
873                                                                                                 SColor(255,255,255,255),\r
874                                                                                                 useAlphaChannelOfTexture\r
875                                                                                                 );\r
876 }\r
877 \r
878 \r
879 \r
880 //! draws a set of 2d images, using a color and the alpha channel of the\r
881 //! texture if desired. The images are drawn beginning at pos and concatenated\r
882 //! in one line. All drawings are clipped against clipRect (if != 0).\r
883 //! The subtextures are defined by the array of sourceRects and are chosen\r
884 //! by the indices given.\r
885 void CNullDriver::draw2DImageBatch(const video::ITexture* texture,\r
886                                 const core::position2d<s32>& pos,\r
887                                 const core::array<core::rect<s32> >& sourceRects,\r
888                                 const core::array<s32>& indices,\r
889                                 s32 kerningWidth,\r
890                                 const core::rect<s32>* clipRect, SColor color,\r
891                                 bool useAlphaChannelOfTexture)\r
892 {\r
893         core::position2d<s32> target(pos);\r
894 \r
895         for (u32 i=0; i<indices.size(); ++i)\r
896         {\r
897                 draw2DImage(texture, target, sourceRects[indices[i]],\r
898                                 clipRect, color, useAlphaChannelOfTexture);\r
899                 target.X += sourceRects[indices[i]].getWidth();\r
900                 target.X += kerningWidth;\r
901         }\r
902 }\r
903 \r
904 //! draws a set of 2d images, using a color and the alpha channel of the\r
905 //! texture if desired.\r
906 void CNullDriver::draw2DImageBatch(const video::ITexture* texture,\r
907                                 const core::array<core::position2d<s32> >& positions,\r
908                                 const core::array<core::rect<s32> >& sourceRects,\r
909                                 const core::rect<s32>* clipRect,\r
910                                 SColor color,\r
911                                 bool useAlphaChannelOfTexture)\r
912 {\r
913         const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());\r
914 \r
915         for (u32 i=0; i<drawCount; ++i)\r
916         {\r
917                 draw2DImage(texture, positions[i], sourceRects[i],\r
918                                 clipRect, color, useAlphaChannelOfTexture);\r
919         }\r
920 }\r
921 \r
922 \r
923 //! Draws a part of the texture into the rectangle.\r
924 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,\r
925         const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,\r
926         const video::SColor* const colors, bool useAlphaChannelOfTexture)\r
927 {\r
928         if (destRect.isValid())\r
929                 draw2DImage(texture, core::position2d<s32>(destRect.UpperLeftCorner),\r
930                                 sourceRect, clipRect, colors?colors[0]:video::SColor(0xffffffff),\r
931                                 useAlphaChannelOfTexture);\r
932 }\r
933 \r
934 \r
935 //! Draws a 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted.\r
936 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,\r
937                                 const core::rect<s32>& sourceRect,\r
938                                 const core::rect<s32>* clipRect, SColor color,\r
939                                 bool useAlphaChannelOfTexture)\r
940 {\r
941 }\r
942 \r
943 \r
944 //! Draws the outline of a 2d rectangle\r
945 void CNullDriver::draw2DRectangleOutline(const core::recti& pos, SColor color)\r
946 {\r
947         draw2DLine(pos.UpperLeftCorner, core::position2di(pos.LowerRightCorner.X, pos.UpperLeftCorner.Y), color);\r
948         draw2DLine(core::position2di(pos.LowerRightCorner.X, pos.UpperLeftCorner.Y), pos.LowerRightCorner, color);\r
949         draw2DLine(pos.LowerRightCorner, core::position2di(pos.UpperLeftCorner.X, pos.LowerRightCorner.Y), color);\r
950         draw2DLine(core::position2di(pos.UpperLeftCorner.X, pos.LowerRightCorner.Y), pos.UpperLeftCorner, color);\r
951 }\r
952 \r
953 \r
954 //! Draw a 2d rectangle\r
955 void CNullDriver::draw2DRectangle(SColor color, const core::rect<s32>& pos, const core::rect<s32>* clip)\r
956 {\r
957         draw2DRectangle(pos, color, color, color, color, clip);\r
958 }\r
959 \r
960 \r
961 \r
962 //! Draws a 2d rectangle with a gradient.\r
963 void CNullDriver::draw2DRectangle(const core::rect<s32>& pos,\r
964         SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,\r
965         const core::rect<s32>* clip)\r
966 {\r
967 }\r
968 \r
969 \r
970 \r
971 //! Draws a 2d line.\r
972 void CNullDriver::draw2DLine(const core::position2d<s32>& start,\r
973                                 const core::position2d<s32>& end, SColor color)\r
974 {\r
975 }\r
976 \r
977 //! Draws a pixel\r
978 void CNullDriver::drawPixel(u32 x, u32 y, const SColor & color)\r
979 {\r
980 }\r
981 \r
982 \r
983 //! Draws a non filled concyclic regular 2d polygon.\r
984 void CNullDriver::draw2DPolygon(core::position2d<s32> center,\r
985         f32 radius, video::SColor color, s32 count)\r
986 {\r
987         if (count < 2)\r
988                 return;\r
989 \r
990         core::position2d<s32> first;\r
991         core::position2d<s32> a,b;\r
992 \r
993         for (s32 j=0; j<count; ++j)\r
994         {\r
995                 b = a;\r
996 \r
997                 f32 p = j / (f32)count * (core::PI*2);\r
998                 a = center + core::position2d<s32>((s32)(sin(p)*radius), (s32)(cos(p)*radius));\r
999 \r
1000                 if (j==0)\r
1001                         first = a;\r
1002                 else\r
1003                         draw2DLine(a, b, color);\r
1004         }\r
1005 \r
1006         draw2DLine(a, first, color);\r
1007 }\r
1008 \r
1009 \r
1010 //! returns color format\r
1011 ECOLOR_FORMAT CNullDriver::getColorFormat() const\r
1012 {\r
1013         return ECF_R5G6B5;\r
1014 }\r
1015 \r
1016 \r
1017 //! returns screen size\r
1018 const core::dimension2d<u32>& CNullDriver::getScreenSize() const\r
1019 {\r
1020         return ScreenSize;\r
1021 }\r
1022 \r
1023 \r
1024 //! get current render target\r
1025 IRenderTarget* CNullDriver::getCurrentRenderTarget() const\r
1026 {\r
1027         return CurrentRenderTarget;\r
1028 }\r
1029 \r
1030 \r
1031 const core::dimension2d<u32>& CNullDriver::getCurrentRenderTargetSize() const\r
1032 {\r
1033         if (CurrentRenderTargetSize.Width == 0)\r
1034                 return ScreenSize;\r
1035         else\r
1036                 return CurrentRenderTargetSize;\r
1037 }\r
1038 \r
1039 \r
1040 // returns current frames per second value\r
1041 s32 CNullDriver::getFPS() const\r
1042 {\r
1043         return FPSCounter.getFPS();\r
1044 }\r
1045 \r
1046 \r
1047 \r
1048 //! returns amount of primitives (mostly triangles) were drawn in the last frame.\r
1049 //! very useful method for statistics.\r
1050 u32 CNullDriver::getPrimitiveCountDrawn( u32 param ) const\r
1051 {\r
1052         return (0 == param) ? FPSCounter.getPrimitive() : (1 == param) ? FPSCounter.getPrimitiveAverage() : FPSCounter.getPrimitiveTotal();\r
1053 }\r
1054 \r
1055 \r
1056 \r
1057 //! Sets the dynamic ambient light color. The default color is\r
1058 //! (0,0,0,0) which means it is dark.\r
1059 //! \param color: New color of the ambient light.\r
1060 void CNullDriver::setAmbientLight(const SColorf& color)\r
1061 {\r
1062         AmbientLight = color;\r
1063 }\r
1064 \r
1065 const SColorf& CNullDriver::getAmbientLight() const\r
1066 {\r
1067         return AmbientLight;\r
1068 }\r
1069 \r
1070 //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8\r
1071 //! driver, it would return "Direct3D8".\r
1072 \r
1073 const wchar_t* CNullDriver::getName() const\r
1074 {\r
1075         return L"Irrlicht NullDevice";\r
1076 }\r
1077 \r
1078 \r
1079 \r
1080 //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do\r
1081 //! this: First, draw all geometry. Then use this method, to draw the shadow\r
1082 //! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow.\r
1083 void CNullDriver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)\r
1084 {\r
1085 }\r
1086 \r
1087 \r
1088 //! Fills the stencil shadow with color. After the shadow volume has been drawn\r
1089 //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this\r
1090 //! to draw the color of the shadow.\r
1091 void CNullDriver::drawStencilShadow(bool clearStencilBuffer,\r
1092                 video::SColor leftUpEdge, video::SColor rightUpEdge,\r
1093                 video::SColor leftDownEdge, video::SColor rightDownEdge)\r
1094 {\r
1095 }\r
1096 \r
1097 \r
1098 //! deletes all dynamic lights there are\r
1099 void CNullDriver::deleteAllDynamicLights()\r
1100 {\r
1101         Lights.set_used(0);\r
1102 }\r
1103 \r
1104 \r
1105 //! adds a dynamic light\r
1106 s32 CNullDriver::addDynamicLight(const SLight& light)\r
1107 {\r
1108         Lights.push_back(light);\r
1109         return Lights.size() - 1;\r
1110 }\r
1111 \r
1112 //! Turns a dynamic light on or off\r
1113 //! \param lightIndex: the index returned by addDynamicLight\r
1114 //! \param turnOn: true to turn the light on, false to turn it off\r
1115 void CNullDriver::turnLightOn(s32 lightIndex, bool turnOn)\r
1116 {\r
1117         // Do nothing\r
1118 }\r
1119 \r
1120 \r
1121 //! returns the maximal amount of dynamic lights the device can handle\r
1122 u32 CNullDriver::getMaximalDynamicLightAmount() const\r
1123 {\r
1124         return 0;\r
1125 }\r
1126 \r
1127 \r
1128 //! Returns current amount of dynamic lights set\r
1129 //! \return Current amount of dynamic lights set\r
1130 u32 CNullDriver::getDynamicLightCount() const\r
1131 {\r
1132         return Lights.size();\r
1133 }\r
1134 \r
1135 \r
1136 //! Returns light data which was previously set by IVideoDriver::addDynamicLight().\r
1137 //! \param idx: Zero based index of the light. Must be greater than 0 and smaller\r
1138 //! than IVideoDriver()::getDynamicLightCount.\r
1139 //! \return Light data.\r
1140 const SLight& CNullDriver::getDynamicLight(u32 idx) const\r
1141 {\r
1142         if ( idx < Lights.size() )\r
1143                 return Lights[idx];\r
1144         else\r
1145         {\r
1146                 _IRR_DEBUG_BREAK_IF(true)\r
1147                 static const SLight dummy;\r
1148                 return dummy;\r
1149         }\r
1150 }\r
1151 \r
1152 \r
1153 //! Creates a boolean alpha channel of the texture based of an color key.\r
1154 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,\r
1155                                                                         video::SColor color,\r
1156                                                                         bool zeroTexels) const\r
1157 {\r
1158         if (!texture)\r
1159                 return;\r
1160 \r
1161         if (texture->getColorFormat() != ECF_A1R5G5B5 &&\r
1162                 texture->getColorFormat() != ECF_A8R8G8B8 )\r
1163         {\r
1164                 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);\r
1165                 return;\r
1166         }\r
1167 \r
1168         if (texture->getColorFormat() == ECF_A1R5G5B5)\r
1169         {\r
1170                 u16 *p = (u16*)texture->lock();\r
1171 \r
1172                 if (!p)\r
1173                 {\r
1174                         os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);\r
1175                         return;\r
1176                 }\r
1177 \r
1178                 const core::dimension2d<u32> dim = texture->getSize();\r
1179                 const u32 pitch = texture->getPitch() / 2;\r
1180 \r
1181                 // color with alpha disabled (i.e. fully transparent)\r
1182                 const u16 refZeroAlpha = (0x7fff & color.toA1R5G5B5());\r
1183 \r
1184                 const u32 pixels = pitch * dim.Height;\r
1185 \r
1186                 for (u32 pixel = 0; pixel < pixels; ++ pixel)\r
1187                 {\r
1188                         // If the color matches the reference color, ignoring alphas,\r
1189                         // set the alpha to zero.\r
1190                         if(((*p) & 0x7fff) == refZeroAlpha)\r
1191                         {\r
1192                                 if(zeroTexels)\r
1193                                         (*p) = 0;\r
1194                                 else\r
1195                                         (*p) = refZeroAlpha;\r
1196                         }\r
1197 \r
1198                         ++p;\r
1199                 }\r
1200 \r
1201                 texture->unlock();\r
1202         }\r
1203         else\r
1204         {\r
1205                 u32 *p = (u32*)texture->lock();\r
1206 \r
1207                 if (!p)\r
1208                 {\r
1209                         os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);\r
1210                         return;\r
1211                 }\r
1212 \r
1213                 core::dimension2d<u32> dim = texture->getSize();\r
1214                 u32 pitch = texture->getPitch() / 4;\r
1215 \r
1216                 // color with alpha disabled (fully transparent)\r
1217                 const u32 refZeroAlpha = 0x00ffffff & color.color;\r
1218 \r
1219                 const u32 pixels = pitch * dim.Height;\r
1220                 for (u32 pixel = 0; pixel < pixels; ++ pixel)\r
1221                 {\r
1222                         // If the color matches the reference color, ignoring alphas,\r
1223                         // set the alpha to zero.\r
1224                         if(((*p) & 0x00ffffff) == refZeroAlpha)\r
1225                         {\r
1226                                 if(zeroTexels)\r
1227                                         (*p) = 0;\r
1228                                 else\r
1229                                         (*p) = refZeroAlpha;\r
1230                         }\r
1231 \r
1232                         ++p;\r
1233                 }\r
1234 \r
1235                 texture->unlock();\r
1236         }\r
1237         texture->regenerateMipMapLevels();\r
1238 }\r
1239 \r
1240 \r
1241 \r
1242 //! Creates an boolean alpha channel of the texture based of an color key position.\r
1243 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,\r
1244                                         core::position2d<s32> colorKeyPixelPos,\r
1245                                         bool zeroTexels) const\r
1246 {\r
1247         if (!texture)\r
1248                 return;\r
1249 \r
1250         if (texture->getColorFormat() != ECF_A1R5G5B5 &&\r
1251                 texture->getColorFormat() != ECF_A8R8G8B8 )\r
1252         {\r
1253                 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);\r
1254                 return;\r
1255         }\r
1256 \r
1257         SColor colorKey;\r
1258 \r
1259         if (texture->getColorFormat() == ECF_A1R5G5B5)\r
1260         {\r
1261                 u16 *p = (u16*)texture->lock(ETLM_READ_ONLY);\r
1262 \r
1263                 if (!p)\r
1264                 {\r
1265                         os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);\r
1266                         return;\r
1267                 }\r
1268 \r
1269                 u32 pitch = texture->getPitch() / 2;\r
1270 \r
1271                 const u16 key16Bit = 0x7fff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];\r
1272 \r
1273                 colorKey = video::A1R5G5B5toA8R8G8B8(key16Bit);\r
1274         }\r
1275         else\r
1276         {\r
1277                 u32 *p = (u32*)texture->lock(ETLM_READ_ONLY);\r
1278 \r
1279                 if (!p)\r
1280                 {\r
1281                         os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);\r
1282                         return;\r
1283                 }\r
1284 \r
1285                 u32 pitch = texture->getPitch() / 4;\r
1286                 colorKey = 0x00ffffff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];\r
1287         }\r
1288 \r
1289         texture->unlock();\r
1290         makeColorKeyTexture(texture, colorKey, zeroTexels);\r
1291 }\r
1292 \r
1293 \r
1294 //! Returns the maximum amount of primitives (mostly vertices) which\r
1295 //! the device is able to render with one drawIndexedTriangleList\r
1296 //! call.\r
1297 u32 CNullDriver::getMaximalPrimitiveCount() const\r
1298 {\r
1299         return 0xFFFFFFFF;\r
1300 }\r
1301 \r
1302 \r
1303 //! checks triangle count and print warning if wrong\r
1304 bool CNullDriver::checkPrimitiveCount(u32 prmCount) const\r
1305 {\r
1306         const u32 m = getMaximalPrimitiveCount();\r
1307 \r
1308         if (prmCount > m)\r
1309         {\r
1310                 char tmp[128];\r
1311                 snprintf_irr(tmp, sizeof(tmp), "Could not draw triangles, too many primitives(%u), maximum is %u.", prmCount, m);\r
1312                 os::Printer::log(tmp, ELL_ERROR);\r
1313                 return false;\r
1314         }\r
1315 \r
1316         return true;\r
1317 }\r
1318 \r
1319 bool CNullDriver::checkImage(const core::array<IImage*>& image) const\r
1320 {\r
1321         bool status = true;\r
1322 \r
1323         if (image.size() > 0)\r
1324         {\r
1325                 ECOLOR_FORMAT lastFormat = image[0]->getColorFormat();\r
1326                 core::dimension2d<u32> lastSize = image[0]->getDimension();\r
1327 \r
1328                 for (u32 i = 0; i < image.size() && status; ++i)\r
1329                 {\r
1330                         ECOLOR_FORMAT format = image[i]->getColorFormat();\r
1331                         core::dimension2d<u32> size = image[i]->getDimension();\r
1332 \r
1333                         switch (format)\r
1334                         {\r
1335                         case ECF_DXT1:\r
1336                         case ECF_DXT2:\r
1337                         case ECF_DXT3:\r
1338                         case ECF_DXT4:\r
1339                         case ECF_DXT5:\r
1340                                 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_DXT))\r
1341                                 {\r
1342                                         os::Printer::log("DXT texture compression not available.", ELL_ERROR);\r
1343                                         status = false;\r
1344                                 }\r
1345                                 else if (size.getOptimalSize(true, false) != size)\r
1346                                 {\r
1347                                         os::Printer::log("Invalid size of image for DXT texture, size of image must be power of two.", ELL_ERROR);\r
1348                                         status = false;\r
1349                                 }\r
1350                                 break;\r
1351                         case ECF_PVRTC_RGB2:\r
1352                         case ECF_PVRTC_ARGB2:\r
1353                         case ECF_PVRTC_RGB4:\r
1354                         case ECF_PVRTC_ARGB4:\r
1355                                 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC))\r
1356                                 {\r
1357                                         os::Printer::log("PVRTC texture compression not available.", ELL_ERROR);\r
1358                                         status = false;\r
1359                                 }\r
1360                                 else if (size.getOptimalSize(true, false) != size)\r
1361                                 {\r
1362                                         os::Printer::log("Invalid size of image for PVRTC compressed texture, size of image must be power of two and squared.", ELL_ERROR);\r
1363                                         status = false;\r
1364                                 }\r
1365                                 break;\r
1366                         case ECF_PVRTC2_ARGB2:\r
1367                         case ECF_PVRTC2_ARGB4:\r
1368                                 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC2))\r
1369                                 {\r
1370                                         os::Printer::log("PVRTC2 texture compression not available.", ELL_ERROR);\r
1371                                         status = false;\r
1372                                 }\r
1373                                 break;\r
1374                         case ECF_ETC1:\r
1375                                 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC1))\r
1376                                 {\r
1377                                         os::Printer::log("ETC1 texture compression not available.", ELL_ERROR);\r
1378                                         status = false;\r
1379                                 }\r
1380                                 break;\r
1381                         case ECF_ETC2_RGB:\r
1382                         case ECF_ETC2_ARGB:\r
1383                                 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC2))\r
1384                                 {\r
1385                                         os::Printer::log("ETC2 texture compression not available.", ELL_ERROR);\r
1386                                         status = false;\r
1387                                 }\r
1388                                 break;\r
1389                         default:\r
1390                                 break;\r
1391                         }\r
1392 \r
1393                         if (format != lastFormat || size != lastSize)\r
1394                                 status = false;\r
1395                 }\r
1396         }\r
1397         else\r
1398         {\r
1399                 status = false;\r
1400         }\r
1401 \r
1402         return status;\r
1403 }\r
1404 \r
1405 //! Enables or disables a texture creation flag.\r
1406 void CNullDriver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled)\r
1407 {\r
1408         if (enabled && ((flag == ETCF_ALWAYS_16_BIT) || (flag == ETCF_ALWAYS_32_BIT)\r
1409                 || (flag == ETCF_OPTIMIZED_FOR_QUALITY) || (flag == ETCF_OPTIMIZED_FOR_SPEED)))\r
1410         {\r
1411                 // disable other formats\r
1412                 setTextureCreationFlag(ETCF_ALWAYS_16_BIT, false);\r
1413                 setTextureCreationFlag(ETCF_ALWAYS_32_BIT, false);\r
1414                 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY, false);\r
1415                 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED, false);\r
1416         }\r
1417 \r
1418         // set flag\r
1419         TextureCreationFlags = (TextureCreationFlags & (~flag)) |\r
1420                 ((((u32)!enabled)-1) & flag);\r
1421 }\r
1422 \r
1423 \r
1424 //! Returns if a texture creation flag is enabled or disabled.\r
1425 bool CNullDriver::getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const\r
1426 {\r
1427         return (TextureCreationFlags & flag)!=0;\r
1428 }\r
1429 \r
1430 core::array<IImage*> CNullDriver::createImagesFromFile(const io::path& filename, E_TEXTURE_TYPE* type)\r
1431 {\r
1432         // TO-DO -> use 'move' feature from C++11 standard.\r
1433 \r
1434         core::array<IImage*> imageArray;\r
1435 \r
1436         if (filename.size() > 0)\r
1437         {\r
1438                 io::IReadFile* file = FileSystem->createAndOpenFile(filename);\r
1439 \r
1440                 if (file)\r
1441                 {\r
1442                         imageArray = createImagesFromFile(file, type);\r
1443                         file->drop();\r
1444                 }\r
1445                 else\r
1446                         os::Printer::log("Could not open file of image", filename, ELL_WARNING);\r
1447         }\r
1448 \r
1449         return imageArray;\r
1450 }\r
1451 \r
1452 core::array<IImage*> CNullDriver::createImagesFromFile(io::IReadFile* file, E_TEXTURE_TYPE* type)\r
1453 {\r
1454         // TO-DO -> use 'move' feature from C++11 standard.\r
1455 \r
1456         core::array<IImage*> imageArray;\r
1457 \r
1458         if (file)\r
1459         {\r
1460                 s32 i;\r
1461 \r
1462                 // try to load file based on file extension\r
1463                 for (i = SurfaceLoader.size() - 1; i >= 0; --i)\r
1464                 {\r
1465                         if (SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))\r
1466                         {\r
1467                                 // reset file position which might have changed due to previous loadImage calls\r
1468                                 file->seek(0);\r
1469                                 imageArray = SurfaceLoader[i]->loadImages(file, type);\r
1470 \r
1471                                 if (imageArray.size() == 0)\r
1472                                 {\r
1473                                         file->seek(0);\r
1474                                         IImage* image = SurfaceLoader[i]->loadImage(file);\r
1475 \r
1476                                         if (image)\r
1477                                                 imageArray.push_back(image);\r
1478                                 }\r
1479 \r
1480                                 if (imageArray.size() > 0)\r
1481                                         return imageArray;\r
1482                         }\r
1483                 }\r
1484 \r
1485                 // try to load file based on what is in it\r
1486                 for (i = SurfaceLoader.size() - 1; i >= 0; --i)\r
1487                 {\r
1488                         // dito\r
1489                         file->seek(0);\r
1490                         if (SurfaceLoader[i]->isALoadableFileFormat(file)\r
1491                                 && !SurfaceLoader[i]->isALoadableFileExtension(file->getFileName())     // extension was tried above already\r
1492                                 )\r
1493                         {\r
1494                                 file->seek(0);\r
1495                                 imageArray = SurfaceLoader[i]->loadImages(file, type);\r
1496 \r
1497                                 if (imageArray.size() == 0)\r
1498                                 {\r
1499                                         file->seek(0);\r
1500                                         IImage* image = SurfaceLoader[i]->loadImage(file);\r
1501 \r
1502                                         if (image)\r
1503                                                 imageArray.push_back(image);\r
1504                                 }\r
1505 \r
1506                                 if (imageArray.size() > 0)\r
1507                                         return imageArray;\r
1508                         }\r
1509                 }\r
1510         }\r
1511 \r
1512         return imageArray;\r
1513 }\r
1514 \r
1515 \r
1516 //! Writes the provided image to disk file\r
1517 bool CNullDriver::writeImageToFile(IImage* image, const io::path& filename,u32 param)\r
1518 {\r
1519         io::IWriteFile* file = FileSystem->createAndWriteFile(filename);\r
1520         if(!file)\r
1521                 return false;\r
1522 \r
1523         bool result = writeImageToFile(image, file, param);\r
1524         file->drop();\r
1525 \r
1526         return result;\r
1527 }\r
1528 \r
1529 //! Writes the provided image to a file.\r
1530 bool CNullDriver::writeImageToFile(IImage* image, io::IWriteFile * file, u32 param)\r
1531 {\r
1532         if(!file)\r
1533                 return false;\r
1534 \r
1535         for (s32 i=SurfaceWriter.size()-1; i>=0; --i)\r
1536         {\r
1537                 if (SurfaceWriter[i]->isAWriteableFileExtension(file->getFileName()))\r
1538                 {\r
1539                         bool written = SurfaceWriter[i]->writeImage(file, image, param);\r
1540                         if (written)\r
1541                                 return true;\r
1542                 }\r
1543         }\r
1544         return false; // failed to write\r
1545 }\r
1546 \r
1547 \r
1548 //! Creates a software image from a byte array.\r
1549 IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format,\r
1550         const core::dimension2d<u32>& size, void *data, bool ownForeignMemory,\r
1551         bool deleteMemory)\r
1552 {\r
1553         return new CImage(format, size, data, ownForeignMemory, deleteMemory);\r
1554 }\r
1555 \r
1556 \r
1557 //! Creates an empty software image.\r
1558 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size)\r
1559 {\r
1560         return new CImage(format, size);\r
1561 }\r
1562 \r
1563 \r
1564 //! Creates a software image from another image.\r
1565 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, IImage *imageToCopy)\r
1566 {\r
1567         os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);\r
1568 \r
1569         CImage* tmp = new CImage(format, imageToCopy->getDimension());\r
1570         imageToCopy->copyTo(tmp);\r
1571         return tmp;\r
1572 }\r
1573 \r
1574 \r
1575 //! Creates a software image from part of another image.\r
1576 IImage* CNullDriver::createImage(IImage* imageToCopy, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)\r
1577 {\r
1578         os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);\r
1579         CImage* tmp = new CImage(imageToCopy->getColorFormat(), imageToCopy->getDimension());\r
1580         imageToCopy->copyTo(tmp, core::position2di(0,0), core::recti(pos,size));\r
1581         return tmp;\r
1582 }\r
1583 \r
1584 \r
1585 //! Creates a software image from part of a texture.\r
1586 IImage* CNullDriver::createImage(ITexture* texture, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)\r
1587 {\r
1588         if ((pos==core::position2di(0,0)) && (size == texture->getSize()))\r
1589         {\r
1590                 void * data = texture->lock(ETLM_READ_ONLY);\r
1591                 if ( !data)\r
1592                         return 0;\r
1593                 IImage* image = new CImage(texture->getColorFormat(), size, data, false, false);\r
1594                 texture->unlock();\r
1595                 return image;\r
1596         }\r
1597         else\r
1598         {\r
1599                 // make sure to avoid buffer overruns\r
1600                 // make the vector a separate variable for g++ 3.x\r
1601                 const core::vector2d<u32> leftUpper(core::clamp(static_cast<u32>(pos.X), 0u, texture->getSize().Width),\r
1602                                         core::clamp(static_cast<u32>(pos.Y), 0u, texture->getSize().Height));\r
1603                 const core::rect<u32> clamped(leftUpper,\r
1604                                         core::dimension2du(core::clamp(static_cast<u32>(size.Width), 0u, texture->getSize().Width),\r
1605                                         core::clamp(static_cast<u32>(size.Height), 0u, texture->getSize().Height)));\r
1606                 if (!clamped.isValid())\r
1607                         return 0;\r
1608                 u8* src = static_cast<u8*>(texture->lock(ETLM_READ_ONLY));\r
1609                 if (!src)\r
1610                         return 0;\r
1611                 IImage* image = new CImage(texture->getColorFormat(), clamped.getSize());\r
1612                 u8* dst = static_cast<u8*>(image->getData());\r
1613                 src += clamped.UpperLeftCorner.Y * texture->getPitch() + image->getBytesPerPixel() * clamped.UpperLeftCorner.X;\r
1614                 for (u32 i=0; i<clamped.getHeight(); ++i)\r
1615                 {\r
1616                         video::CColorConverter::convert_viaFormat(src, texture->getColorFormat(), clamped.getWidth(), dst, image->getColorFormat());\r
1617                         src += texture->getPitch();\r
1618                         dst += image->getPitch();\r
1619                 }\r
1620                 texture->unlock();\r
1621                 return image;\r
1622         }\r
1623 }\r
1624 \r
1625 \r
1626 //! Sets the fog mode.\r
1627 void CNullDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, f32 end,\r
1628                 f32 density, bool pixelFog, bool rangeFog)\r
1629 {\r
1630         FogColor = color;\r
1631         FogType = fogType;\r
1632         FogStart = start;\r
1633         FogEnd = end;\r
1634         FogDensity = density;\r
1635         PixelFog = pixelFog;\r
1636         RangeFog = rangeFog;\r
1637 }\r
1638 \r
1639 //! Gets the fog mode.\r
1640 void CNullDriver::getFog(SColor& color, E_FOG_TYPE& fogType, f32& start, f32& end,\r
1641                 f32& density, bool& pixelFog, bool& rangeFog)\r
1642 {\r
1643         color = FogColor;\r
1644         fogType = FogType;\r
1645         start = FogStart;\r
1646         end = FogEnd;\r
1647         density = FogDensity;\r
1648         pixelFog = PixelFog;\r
1649         rangeFog = RangeFog;\r
1650 }\r
1651 \r
1652 //! Draws a mesh buffer\r
1653 void CNullDriver::drawMeshBuffer(const scene::IMeshBuffer* mb)\r
1654 {\r
1655         if (!mb)\r
1656                 return;\r
1657 \r
1658         //IVertexBuffer and IIndexBuffer later\r
1659         SHWBufferLink *HWBuffer=getBufferLink(mb);\r
1660 \r
1661         if (HWBuffer)\r
1662                 drawHardwareBuffer(HWBuffer);\r
1663         else\r
1664                 drawVertexPrimitiveList(mb->getVertices(), mb->getVertexCount(), mb->getIndices(), mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), mb->getIndexType());\r
1665 }\r
1666 \r
1667 \r
1668 //! Draws the normals of a mesh buffer\r
1669 void CNullDriver::drawMeshBufferNormals(const scene::IMeshBuffer* mb, f32 length, SColor color)\r
1670 {\r
1671         const u32 count = mb->getVertexCount();\r
1672         const bool normalize = mb->getMaterial().NormalizeNormals;\r
1673 \r
1674         for (u32 i=0; i < count; ++i)\r
1675         {\r
1676                 core::vector3df normalizedNormal = mb->getNormal(i);\r
1677                 if (normalize)\r
1678                         normalizedNormal.normalize();\r
1679 \r
1680                 const core::vector3df& pos = mb->getPosition(i);\r
1681                 draw3DLine(pos, pos + (normalizedNormal * length), color);\r
1682         }\r
1683 }\r
1684 \r
1685 \r
1686 CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IMeshBuffer* mb)\r
1687 {\r
1688         if (!mb || !isHardwareBufferRecommend(mb))\r
1689                 return 0;\r
1690 \r
1691         //search for hardware links\r
1692         SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());\r
1693         if (HWBuffer)\r
1694                 return HWBuffer;\r
1695 \r
1696         return createHardwareBuffer(mb); //no hardware links, and mesh wants one, create it\r
1697 }\r
1698 \r
1699 \r
1700 //! Update all hardware buffers, remove unused ones\r
1701 void CNullDriver::updateAllHardwareBuffers()\r
1702 {\r
1703         auto it = HWBufferList.begin();\r
1704         while (it != HWBufferList.end()) {\r
1705                 SHWBufferLink *Link = *it;\r
1706                 ++it;\r
1707 \r
1708                 if (!Link->MeshBuffer || Link->MeshBuffer->getReferenceCount() == 1)\r
1709                         deleteHardwareBuffer(Link);\r
1710         }\r
1711 }\r
1712 \r
1713 \r
1714 void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer)\r
1715 {\r
1716         if (!HWBuffer)\r
1717                 return;\r
1718         HWBufferList.erase(HWBuffer->listPosition);\r
1719         delete HWBuffer;\r
1720 }\r
1721 \r
1722 \r
1723 //! Remove hardware buffer\r
1724 void CNullDriver::removeHardwareBuffer(const scene::IMeshBuffer* mb)\r
1725 {\r
1726         if (!mb)\r
1727                 return;\r
1728         SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());\r
1729         if (HWBuffer)\r
1730                 deleteHardwareBuffer(HWBuffer);\r
1731 }\r
1732 \r
1733 \r
1734 //! Remove all hardware buffers\r
1735 void CNullDriver::removeAllHardwareBuffers()\r
1736 {\r
1737         while (!HWBufferList.empty())\r
1738                 deleteHardwareBuffer(HWBufferList.front());\r
1739 }\r
1740 \r
1741 \r
1742 bool CNullDriver::isHardwareBufferRecommend(const scene::IMeshBuffer* mb)\r
1743 {\r
1744         if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))\r
1745                 return false;\r
1746 \r
1747         if (mb->getVertexCount()<MinVertexCountForVBO)\r
1748                 return false;\r
1749 \r
1750         return true;\r
1751 }\r
1752 \r
1753 \r
1754 //! Create occlusion query.\r
1755 /** Use node for identification and mesh for occlusion test. */\r
1756 void CNullDriver::addOcclusionQuery(scene::ISceneNode* node, const scene::IMesh* mesh)\r
1757 {\r
1758         if (!node)\r
1759                 return;\r
1760         if (!mesh)\r
1761         {\r
1762                 if ((node->getType() != scene::ESNT_MESH) && (node->getType() != scene::ESNT_ANIMATED_MESH))\r
1763                         return;\r
1764                 else if (node->getType() == scene::ESNT_MESH)\r
1765                         mesh = static_cast<scene::IMeshSceneNode*>(node)->getMesh();\r
1766                 else\r
1767                         mesh = static_cast<scene::IAnimatedMeshSceneNode*>(node)->getMesh()->getMesh(0);\r
1768                 if (!mesh)\r
1769                         return;\r
1770         }\r
1771 \r
1772         //search for query\r
1773         s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
1774         if (index != -1)\r
1775         {\r
1776                 if (OcclusionQueries[index].Mesh != mesh)\r
1777                 {\r
1778                         OcclusionQueries[index].Mesh->drop();\r
1779                         OcclusionQueries[index].Mesh = mesh;\r
1780                         mesh->grab();\r
1781                 }\r
1782         }\r
1783         else\r
1784         {\r
1785                 OcclusionQueries.push_back(SOccQuery(node, mesh));\r
1786                 node->setAutomaticCulling(node->getAutomaticCulling() | scene::EAC_OCC_QUERY);\r
1787         }\r
1788 }\r
1789 \r
1790 \r
1791 //! Remove occlusion query.\r
1792 void CNullDriver::removeOcclusionQuery(scene::ISceneNode* node)\r
1793 {\r
1794         //search for query\r
1795         s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
1796         if (index != -1)\r
1797         {\r
1798                 node->setAutomaticCulling(node->getAutomaticCulling() & ~scene::EAC_OCC_QUERY);\r
1799                 OcclusionQueries.erase(index);\r
1800         }\r
1801 }\r
1802 \r
1803 \r
1804 //! Remove all occlusion queries.\r
1805 void CNullDriver::removeAllOcclusionQueries()\r
1806 {\r
1807         for (s32 i=OcclusionQueries.size()-1; i>=0; --i)\r
1808         {\r
1809                 removeOcclusionQuery(OcclusionQueries[i].Node);\r
1810         }\r
1811 }\r
1812 \r
1813 \r
1814 //! Run occlusion query. Draws mesh stored in query.\r
1815 /** If the mesh shall be rendered visible, use\r
1816 flag to enable the proper material setting. */\r
1817 void CNullDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible)\r
1818 {\r
1819         if(!node)\r
1820                 return;\r
1821         s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
1822         if (index==-1)\r
1823                 return;\r
1824         OcclusionQueries[index].Run=0;\r
1825         if (!visible)\r
1826         {\r
1827                 SMaterial mat;\r
1828                 mat.Lighting=false;\r
1829                 mat.AntiAliasing=0;\r
1830                 mat.ColorMask=ECP_NONE;\r
1831                 mat.GouraudShading=false;\r
1832                 mat.ZWriteEnable=EZW_OFF;\r
1833                 setMaterial(mat);\r
1834         }\r
1835         setTransform(video::ETS_WORLD, node->getAbsoluteTransformation());\r
1836         const scene::IMesh* mesh = OcclusionQueries[index].Mesh;\r
1837         for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)\r
1838         {\r
1839                 if (visible)\r
1840                         setMaterial(mesh->getMeshBuffer(i)->getMaterial());\r
1841                 drawMeshBuffer(mesh->getMeshBuffer(i));\r
1842         }\r
1843 }\r
1844 \r
1845 \r
1846 //! Run all occlusion queries. Draws all meshes stored in queries.\r
1847 /** If the meshes shall not be rendered visible, use\r
1848 overrideMaterial to disable the color and depth buffer. */\r
1849 void CNullDriver::runAllOcclusionQueries(bool visible)\r
1850 {\r
1851         for (u32 i=0; i<OcclusionQueries.size(); ++i)\r
1852                 runOcclusionQuery(OcclusionQueries[i].Node, visible);\r
1853 }\r
1854 \r
1855 \r
1856 //! Update occlusion query. Retrieves results from GPU.\r
1857 /** If the query shall not block, set the flag to false.\r
1858 Update might not occur in this case, though */\r
1859 void CNullDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block)\r
1860 {\r
1861 }\r
1862 \r
1863 \r
1864 //! Update all occlusion queries. Retrieves results from GPU.\r
1865 /** If the query shall not block, set the flag to false.\r
1866 Update might not occur in this case, though */\r
1867 void CNullDriver::updateAllOcclusionQueries(bool block)\r
1868 {\r
1869         for (u32 i=0; i<OcclusionQueries.size(); ++i)\r
1870         {\r
1871                 if (OcclusionQueries[i].Run==u32(~0))\r
1872                         continue;\r
1873                 updateOcclusionQuery(OcclusionQueries[i].Node, block);\r
1874                 ++OcclusionQueries[i].Run;\r
1875                 if (OcclusionQueries[i].Run>1000)\r
1876                         removeOcclusionQuery(OcclusionQueries[i].Node);\r
1877         }\r
1878 }\r
1879 \r
1880 \r
1881 //! Return query result.\r
1882 /** Return value is the number of visible pixels/fragments.\r
1883 The value is a safe approximation, i.e. can be larger then the\r
1884 actual value of pixels. */\r
1885 u32 CNullDriver::getOcclusionQueryResult(scene::ISceneNode* node) const\r
1886 {\r
1887         return ~0;\r
1888 }\r
1889 \r
1890 \r
1891 //! Create render target.\r
1892 IRenderTarget* CNullDriver::addRenderTarget()\r
1893 {\r
1894         return 0;\r
1895 }\r
1896 \r
1897 \r
1898 //! Remove render target.\r
1899 void CNullDriver::removeRenderTarget(IRenderTarget* renderTarget)\r
1900 {\r
1901         if (!renderTarget)\r
1902                 return;\r
1903 \r
1904         for (u32 i = 0; i < RenderTargets.size(); ++i)\r
1905         {\r
1906                 if (RenderTargets[i] == renderTarget)\r
1907                 {\r
1908                         RenderTargets[i]->drop();\r
1909                         RenderTargets.erase(i);\r
1910 \r
1911                         return;\r
1912                 }\r
1913         }\r
1914 }\r
1915 \r
1916 \r
1917 //! Remove all render targets.\r
1918 void CNullDriver::removeAllRenderTargets()\r
1919 {\r
1920         for (u32 i = 0; i < RenderTargets.size(); ++i)\r
1921                 RenderTargets[i]->drop();\r
1922 \r
1923         RenderTargets.clear();\r
1924 \r
1925         SharedRenderTarget = 0;\r
1926 }\r
1927 \r
1928 \r
1929 //! Only used by the internal engine. Used to notify the driver that\r
1930 //! the window was resized.\r
1931 void CNullDriver::OnResize(const core::dimension2d<u32>& size)\r
1932 {\r
1933         if (ViewPort.getWidth() == (s32)ScreenSize.Width &&\r
1934                 ViewPort.getHeight() == (s32)ScreenSize.Height)\r
1935                 ViewPort = core::rect<s32>(core::position2d<s32>(0,0),\r
1936                                                                         core::dimension2di(size));\r
1937 \r
1938         ScreenSize = size;\r
1939 }\r
1940 \r
1941 \r
1942 // adds a material renderer and drops it afterwards. To be used for internal creation\r
1943 s32 CNullDriver::addAndDropMaterialRenderer(IMaterialRenderer* m)\r
1944 {\r
1945         s32 i = addMaterialRenderer(m);\r
1946 \r
1947         if (m)\r
1948                 m->drop();\r
1949 \r
1950         return i;\r
1951 }\r
1952 \r
1953 \r
1954 //! Adds a new material renderer to the video device.\r
1955 s32 CNullDriver::addMaterialRenderer(IMaterialRenderer* renderer, const char* name)\r
1956 {\r
1957         if (!renderer)\r
1958                 return -1;\r
1959 \r
1960         SMaterialRenderer r;\r
1961         r.Renderer = renderer;\r
1962         r.Name = name;\r
1963 \r
1964         if (name == 0 && (MaterialRenderers.size() < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ))\r
1965         {\r
1966                 // set name of built in renderer so that we don't have to implement name\r
1967                 // setting in all available renderers.\r
1968                 r.Name = sBuiltInMaterialTypeNames[MaterialRenderers.size()];\r
1969         }\r
1970 \r
1971         MaterialRenderers.push_back(r);\r
1972         renderer->grab();\r
1973 \r
1974         return MaterialRenderers.size()-1;\r
1975 }\r
1976 \r
1977 \r
1978 //! Sets the name of a material renderer.\r
1979 void CNullDriver::setMaterialRendererName(s32 idx, const char* name)\r
1980 {\r
1981         if (idx < s32(sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ||\r
1982                 idx >= (s32)MaterialRenderers.size())\r
1983                 return;\r
1984 \r
1985         MaterialRenderers[idx].Name = name;\r
1986 }\r
1987 \r
1988 void CNullDriver::swapMaterialRenderers(u32 idx1, u32 idx2, bool swapNames)\r
1989 {\r
1990         if ( idx1 < MaterialRenderers.size() && idx2 < MaterialRenderers.size() )\r
1991         {\r
1992                 irr::core::swap(MaterialRenderers[idx1].Renderer, MaterialRenderers[idx2].Renderer);\r
1993                 if ( swapNames )\r
1994                         irr::core::swap(MaterialRenderers[idx1].Name, MaterialRenderers[idx2].Name);\r
1995         }\r
1996 }\r
1997 \r
1998 \r
1999 //! Returns driver and operating system specific data about the IVideoDriver.\r
2000 const SExposedVideoData& CNullDriver::getExposedVideoData()\r
2001 {\r
2002         return ExposedData;\r
2003 }\r
2004 \r
2005 \r
2006 //! Returns type of video driver\r
2007 E_DRIVER_TYPE CNullDriver::getDriverType() const\r
2008 {\r
2009         return EDT_NULL;\r
2010 }\r
2011 \r
2012 \r
2013 //! deletes all material renderers\r
2014 void CNullDriver::deleteMaterialRenders()\r
2015 {\r
2016         // delete material renderers\r
2017         for (u32 i=0; i<MaterialRenderers.size(); ++i)\r
2018                 if (MaterialRenderers[i].Renderer)\r
2019                         MaterialRenderers[i].Renderer->drop();\r
2020 \r
2021         MaterialRenderers.clear();\r
2022 }\r
2023 \r
2024 \r
2025 //! Returns pointer to material renderer or null\r
2026 IMaterialRenderer* CNullDriver::getMaterialRenderer(u32 idx) const\r
2027 {\r
2028         if ( idx < MaterialRenderers.size() )\r
2029                 return MaterialRenderers[idx].Renderer;\r
2030         else\r
2031                 return 0;\r
2032 }\r
2033 \r
2034 \r
2035 //! Returns amount of currently available material renderers.\r
2036 u32 CNullDriver::getMaterialRendererCount() const\r
2037 {\r
2038         return MaterialRenderers.size();\r
2039 }\r
2040 \r
2041 \r
2042 //! Returns name of the material renderer\r
2043 const char* CNullDriver::getMaterialRendererName(u32 idx) const\r
2044 {\r
2045         if ( idx < MaterialRenderers.size() )\r
2046                 return MaterialRenderers[idx].Name.c_str();\r
2047 \r
2048         return 0;\r
2049 }\r
2050 \r
2051 \r
2052 //! Returns pointer to the IGPUProgrammingServices interface.\r
2053 IGPUProgrammingServices* CNullDriver::getGPUProgrammingServices()\r
2054 {\r
2055         return this;\r
2056 }\r
2057 \r
2058 \r
2059 //! Adds a new material renderer to the VideoDriver, based on a high level shading language.\r
2060 s32 CNullDriver::addHighLevelShaderMaterial(\r
2061         const c8* vertexShaderProgram,\r
2062         const c8* vertexShaderEntryPointName,\r
2063         E_VERTEX_SHADER_TYPE vsCompileTarget,\r
2064         const c8* pixelShaderProgram,\r
2065         const c8* pixelShaderEntryPointName,\r
2066         E_PIXEL_SHADER_TYPE psCompileTarget,\r
2067         const c8* geometryShaderProgram,\r
2068         const c8* geometryShaderEntryPointName,\r
2069         E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
2070         scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,\r
2071         u32 verticesOut,\r
2072         IShaderConstantSetCallBack* callback,\r
2073         E_MATERIAL_TYPE baseMaterial,\r
2074         s32 userData)\r
2075 {\r
2076         os::Printer::log("High level shader materials not available (yet) in this driver, sorry");\r
2077         return -1;\r
2078 }\r
2079 \r
2080 \r
2081 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),\r
2082 //! but tries to load the programs from files.\r
2083 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(\r
2084                 const io::path& vertexShaderProgramFileName,\r
2085                 const c8* vertexShaderEntryPointName,\r
2086                 E_VERTEX_SHADER_TYPE vsCompileTarget,\r
2087                 const io::path& pixelShaderProgramFileName,\r
2088                 const c8* pixelShaderEntryPointName,\r
2089                 E_PIXEL_SHADER_TYPE psCompileTarget,\r
2090                 const io::path& geometryShaderProgramFileName,\r
2091                 const c8* geometryShaderEntryPointName,\r
2092                 E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
2093                 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,\r
2094                 u32 verticesOut,\r
2095                 IShaderConstantSetCallBack* callback,\r
2096                 E_MATERIAL_TYPE baseMaterial,\r
2097                 s32 userData)\r
2098 {\r
2099         io::IReadFile* vsfile = 0;\r
2100         io::IReadFile* psfile = 0;\r
2101         io::IReadFile* gsfile = 0;\r
2102 \r
2103         if (vertexShaderProgramFileName.size() )\r
2104         {\r
2105                 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);\r
2106                 if (!vsfile)\r
2107                 {\r
2108                         os::Printer::log("Could not open vertex shader program file",\r
2109                                 vertexShaderProgramFileName, ELL_WARNING);\r
2110                 }\r
2111         }\r
2112 \r
2113         if (pixelShaderProgramFileName.size() )\r
2114         {\r
2115                 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);\r
2116                 if (!psfile)\r
2117                 {\r
2118                         os::Printer::log("Could not open pixel shader program file",\r
2119                                 pixelShaderProgramFileName, ELL_WARNING);\r
2120                 }\r
2121         }\r
2122 \r
2123         if (geometryShaderProgramFileName.size() )\r
2124         {\r
2125                 gsfile = FileSystem->createAndOpenFile(geometryShaderProgramFileName);\r
2126                 if (!gsfile)\r
2127                 {\r
2128                         os::Printer::log("Could not open geometry shader program file",\r
2129                                 geometryShaderProgramFileName, ELL_WARNING);\r
2130                 }\r
2131         }\r
2132 \r
2133         s32 result = addHighLevelShaderMaterialFromFiles(\r
2134                 vsfile, vertexShaderEntryPointName, vsCompileTarget,\r
2135                 psfile, pixelShaderEntryPointName, psCompileTarget,\r
2136                 gsfile, geometryShaderEntryPointName, gsCompileTarget,\r
2137                 inType, outType, verticesOut,\r
2138                 callback, baseMaterial, userData);\r
2139 \r
2140         if (psfile)\r
2141                 psfile->drop();\r
2142 \r
2143         if (vsfile)\r
2144                 vsfile->drop();\r
2145 \r
2146         if (gsfile)\r
2147                 gsfile->drop();\r
2148 \r
2149         return result;\r
2150 }\r
2151 \r
2152 \r
2153 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),\r
2154 //! but tries to load the programs from files.\r
2155 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(\r
2156                 io::IReadFile* vertexShaderProgram,\r
2157                 const c8* vertexShaderEntryPointName,\r
2158                 E_VERTEX_SHADER_TYPE vsCompileTarget,\r
2159                 io::IReadFile* pixelShaderProgram,\r
2160                 const c8* pixelShaderEntryPointName,\r
2161                 E_PIXEL_SHADER_TYPE psCompileTarget,\r
2162                 io::IReadFile* geometryShaderProgram,\r
2163                 const c8* geometryShaderEntryPointName,\r
2164                 E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
2165                 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,\r
2166                 u32 verticesOut,\r
2167                 IShaderConstantSetCallBack* callback,\r
2168                 E_MATERIAL_TYPE baseMaterial,\r
2169                 s32 userData)\r
2170 {\r
2171         c8* vs = 0;\r
2172         c8* ps = 0;\r
2173         c8* gs = 0;\r
2174 \r
2175         if (vertexShaderProgram)\r
2176         {\r
2177                 const long size = vertexShaderProgram->getSize();\r
2178                 if (size)\r
2179                 {\r
2180                         vs = new c8[size+1];\r
2181                         vertexShaderProgram->read(vs, size);\r
2182                         vs[size] = 0;\r
2183                 }\r
2184         }\r
2185 \r
2186         if (pixelShaderProgram)\r
2187         {\r
2188                 const long size = pixelShaderProgram->getSize();\r
2189                 if (size)\r
2190                 {\r
2191                         // if both handles are the same we must reset the file\r
2192                         if (pixelShaderProgram==vertexShaderProgram)\r
2193                                 pixelShaderProgram->seek(0);\r
2194                         ps = new c8[size+1];\r
2195                         pixelShaderProgram->read(ps, size);\r
2196                         ps[size] = 0;\r
2197                 }\r
2198         }\r
2199 \r
2200         if (geometryShaderProgram)\r
2201         {\r
2202                 const long size = geometryShaderProgram->getSize();\r
2203                 if (size)\r
2204                 {\r
2205                         // if both handles are the same we must reset the file\r
2206                         if ((geometryShaderProgram==vertexShaderProgram) ||\r
2207                                         (geometryShaderProgram==pixelShaderProgram))\r
2208                                 geometryShaderProgram->seek(0);\r
2209                         gs = new c8[size+1];\r
2210                         geometryShaderProgram->read(gs, size);\r
2211                         gs[size] = 0;\r
2212                 }\r
2213         }\r
2214 \r
2215         s32 result = this->addHighLevelShaderMaterial(\r
2216                 vs, vertexShaderEntryPointName, vsCompileTarget,\r
2217                 ps, pixelShaderEntryPointName, psCompileTarget,\r
2218                 gs, geometryShaderEntryPointName, gsCompileTarget,\r
2219                 inType, outType, verticesOut,\r
2220                 callback, baseMaterial, userData);\r
2221 \r
2222         delete [] vs;\r
2223         delete [] ps;\r
2224         delete [] gs;\r
2225 \r
2226         return result;\r
2227 }\r
2228 \r
2229 \r
2230 //! Adds a new material renderer to the VideoDriver, using pixel and/or\r
2231 //! vertex shaders to render geometry.\r
2232 s32 CNullDriver::addShaderMaterial(const c8* vertexShaderProgram,\r
2233         const c8* pixelShaderProgram,\r
2234         IShaderConstantSetCallBack* callback,\r
2235         E_MATERIAL_TYPE baseMaterial,\r
2236         s32 userData)\r
2237 {\r
2238         os::Printer::log("Shader materials not implemented yet in this driver, sorry.");\r
2239         return -1;\r
2240 }\r
2241 \r
2242 \r
2243 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the\r
2244 //! programs from files.\r
2245 s32 CNullDriver::addShaderMaterialFromFiles(io::IReadFile* vertexShaderProgram,\r
2246         io::IReadFile* pixelShaderProgram,\r
2247         IShaderConstantSetCallBack* callback,\r
2248         E_MATERIAL_TYPE baseMaterial,\r
2249         s32 userData)\r
2250 {\r
2251         c8* vs = 0;\r
2252         c8* ps = 0;\r
2253 \r
2254         if (vertexShaderProgram)\r
2255         {\r
2256                 const long size = vertexShaderProgram->getSize();\r
2257                 if (size)\r
2258                 {\r
2259                         vs = new c8[size+1];\r
2260                         vertexShaderProgram->read(vs, size);\r
2261                         vs[size] = 0;\r
2262                 }\r
2263         }\r
2264 \r
2265         if (pixelShaderProgram)\r
2266         {\r
2267                 const long size = pixelShaderProgram->getSize();\r
2268                 if (size)\r
2269                 {\r
2270                         ps = new c8[size+1];\r
2271                         pixelShaderProgram->read(ps, size);\r
2272                         ps[size] = 0;\r
2273                 }\r
2274         }\r
2275 \r
2276         s32 result = addShaderMaterial(vs, ps, callback, baseMaterial, userData);\r
2277 \r
2278         delete [] vs;\r
2279         delete [] ps;\r
2280 \r
2281         return result;\r
2282 }\r
2283 \r
2284 \r
2285 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the\r
2286 //! programs from files.\r
2287 s32 CNullDriver::addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName,\r
2288         const io::path& pixelShaderProgramFileName,\r
2289         IShaderConstantSetCallBack* callback,\r
2290         E_MATERIAL_TYPE baseMaterial,\r
2291         s32 userData)\r
2292 {\r
2293         io::IReadFile* vsfile = 0;\r
2294         io::IReadFile* psfile = 0;\r
2295 \r
2296         if (vertexShaderProgramFileName.size())\r
2297         {\r
2298                 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);\r
2299                 if (!vsfile)\r
2300                 {\r
2301                         os::Printer::log("Could not open vertex shader program file",\r
2302                                 vertexShaderProgramFileName, ELL_WARNING);\r
2303                         return -1;\r
2304                 }\r
2305         }\r
2306 \r
2307         if (pixelShaderProgramFileName.size())\r
2308         {\r
2309                 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);\r
2310                 if (!psfile)\r
2311                 {\r
2312                         os::Printer::log("Could not open pixel shader program file",\r
2313                                 pixelShaderProgramFileName, ELL_WARNING);\r
2314                         if (vsfile)\r
2315                                 vsfile->drop();\r
2316                         return -1;\r
2317                 }\r
2318         }\r
2319 \r
2320         s32 result = addShaderMaterialFromFiles(vsfile, psfile, callback,\r
2321                 baseMaterial, userData);\r
2322 \r
2323         if (psfile)\r
2324                 psfile->drop();\r
2325 \r
2326         if (vsfile)\r
2327                 vsfile->drop();\r
2328 \r
2329         return result;\r
2330 }\r
2331 \r
2332 \r
2333 //! Creates a render target texture.\r
2334 ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,\r
2335                 const io::path&name, const ECOLOR_FORMAT format)\r
2336 {\r
2337         return 0;\r
2338 }\r
2339 \r
2340 ITexture* CNullDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen,\r
2341                                 const io::path& name, const ECOLOR_FORMAT format)\r
2342 {\r
2343         return 0;\r
2344 }\r
2345 \r
2346 void CNullDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)\r
2347 {\r
2348 }\r
2349 \r
2350 \r
2351 //! Returns a pointer to the mesh manipulator.\r
2352 scene::IMeshManipulator* CNullDriver::getMeshManipulator()\r
2353 {\r
2354         return MeshManipulator;\r
2355 }\r
2356 \r
2357 \r
2358 //! Returns an image created from the last rendered frame.\r
2359 IImage* CNullDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)\r
2360 {\r
2361         return 0;\r
2362 }\r
2363 \r
2364 \r
2365 // prints renderer version\r
2366 void CNullDriver::printVersion()\r
2367 {\r
2368         core::stringw namePrint = L"Using renderer: ";\r
2369         namePrint += getName();\r
2370         os::Printer::log(namePrint.c_str(), ELL_INFORMATION);\r
2371 }\r
2372 \r
2373 \r
2374 //! creates a video driver\r
2375 IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)\r
2376 {\r
2377         CNullDriver* nullDriver = new CNullDriver(io, screenSize);\r
2378 \r
2379         // create empty material renderers\r
2380         for(u32 i=0; sBuiltInMaterialTypeNames[i]; ++i)\r
2381         {\r
2382                 IMaterialRenderer* imr = new IMaterialRenderer();\r
2383                 nullDriver->addMaterialRenderer(imr);\r
2384                 imr->drop();\r
2385         }\r
2386 \r
2387         return nullDriver;\r
2388 }\r
2389 \r
2390 \r
2391 //! Set/unset a clipping plane.\r
2392 //! There are at least 6 clipping planes available for the user to set at will.\r
2393 //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes.\r
2394 //! \param plane: The plane itself.\r
2395 //! \param enable: If true, enable the clipping plane else disable it.\r
2396 bool CNullDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)\r
2397 {\r
2398         return false;\r
2399 }\r
2400 \r
2401 \r
2402 //! Enable/disable a clipping plane.\r
2403 void CNullDriver::enableClipPlane(u32 index, bool enable)\r
2404 {\r
2405         // not necessary\r
2406 }\r
2407 \r
2408 \r
2409 ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d<u32>& size,\r
2410                 const c8* name)\r
2411 {\r
2412         os::Printer::log("createRenderTargetTexture is deprecated, use addRenderTargetTexture instead");\r
2413         ITexture* tex = addRenderTargetTexture(size, name);\r
2414         tex->grab();\r
2415         return tex;\r
2416 }\r
2417 \r
2418 \r
2419 void CNullDriver::setMinHardwareBufferVertexCount(u32 count)\r
2420 {\r
2421         MinVertexCountForVBO = count;\r
2422 }\r
2423 \r
2424 \r
2425 SOverrideMaterial& CNullDriver::getOverrideMaterial()\r
2426 {\r
2427         return OverrideMaterial;\r
2428 }\r
2429 \r
2430 \r
2431 //! Get the 2d override material for altering its values\r
2432 SMaterial& CNullDriver::getMaterial2D()\r
2433 {\r
2434         return OverrideMaterial2D;\r
2435 }\r
2436 \r
2437 \r
2438 //! Enable the 2d override material\r
2439 void CNullDriver::enableMaterial2D(bool enable)\r
2440 {\r
2441         OverrideMaterial2DEnabled=enable;\r
2442 }\r
2443 \r
2444 \r
2445 core::dimension2du CNullDriver::getMaxTextureSize() const\r
2446 {\r
2447         return core::dimension2du(0x10000,0x10000); // maybe large enough\r
2448 }\r
2449 \r
2450 bool CNullDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const\r
2451 {\r
2452         // TODO: I suspect it would be nice if the material had an enum for further control.\r
2453         //              Especially it probably makes sense to allow disabling transparent render pass as soon as material.ZWriteEnable is on.\r
2454         //      But then we might want an enum for the renderpass in material instead of just a transparency flag in material - and that's more work.\r
2455         //      Or we could at least set return false when material.ZWriteEnable is EZW_ON? Still considering that...\r
2456         //              Be careful - this function is deeply connected to getWriteZBuffer as transparent render passes are usually about rendering with\r
2457         //      zwrite disabled and getWriteZBuffer calls this function.\r
2458 \r
2459         video::IMaterialRenderer* rnd = getMaterialRenderer(material.MaterialType);\r
2460         // TODO: I suspect IMaterialRenderer::isTransparent also often could use SMaterial as parameter\r
2461         //       We could for example then get rid of IsTransparent function in SMaterial and move that to the software material renderer.\r
2462         if (rnd && rnd->isTransparent())\r
2463                 return true;\r
2464 \r
2465         return false;\r
2466 }\r
2467 \r
2468 \r
2469 //! Color conversion convenience function\r
2470 /** Convert an image (as array of pixels) from source to destination\r
2471 array, thereby converting the color format. The pixel size is\r
2472 determined by the color formats.\r
2473 \param sP Pointer to source\r
2474 \param sF Color format of source\r
2475 \param sN Number of pixels to convert, both array must be large enough\r
2476 \param dP Pointer to destination\r
2477 \param dF Color format of destination\r
2478 */\r
2479 void CNullDriver::convertColor(const void* sP, ECOLOR_FORMAT sF, s32 sN,\r
2480                 void* dP, ECOLOR_FORMAT dF) const\r
2481 {\r
2482         video::CColorConverter::convert_viaFormat(sP, sF, sN, dP, dF);\r
2483 }\r
2484 \r
2485 \r
2486 } // end namespace\r
2487 } // end namespace\r