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