]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CNullDriver.cpp
Drop obsolete IVideoDriver features
[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", MATERIAL_MAX_TEXTURES);\r
57         DriverAttributes->addInt("MaxSupportedTextures", 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 axis aligned box.\r
723 void CNullDriver::draw3DBox(const core::aabbox3d<f32>& box, SColor color)\r
724 {\r
725         core::vector3df edges[8];\r
726         box.getEdges(edges);\r
727 \r
728         // TODO: optimize into one big drawIndexPrimitive call.\r
729 \r
730         draw3DLine(edges[5], edges[1], color);\r
731         draw3DLine(edges[1], edges[3], color);\r
732         draw3DLine(edges[3], edges[7], color);\r
733         draw3DLine(edges[7], edges[5], color);\r
734         draw3DLine(edges[0], edges[2], color);\r
735         draw3DLine(edges[2], edges[6], color);\r
736         draw3DLine(edges[6], edges[4], color);\r
737         draw3DLine(edges[4], edges[0], color);\r
738         draw3DLine(edges[1], edges[0], color);\r
739         draw3DLine(edges[3], edges[2], color);\r
740         draw3DLine(edges[7], edges[6], color);\r
741         draw3DLine(edges[5], edges[4], color);\r
742 }\r
743 \r
744 \r
745 \r
746 //! draws an 2d image\r
747 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos, bool useAlphaChannelOfTexture)\r
748 {\r
749         if (!texture)\r
750                 return;\r
751 \r
752         draw2DImage(texture,destPos, core::rect<s32>(core::position2d<s32>(0,0),\r
753                                                                                                 core::dimension2di(texture->getOriginalSize())),\r
754                                                                                                 0,\r
755                                                                                                 SColor(255,255,255,255),\r
756                                                                                                 useAlphaChannelOfTexture\r
757                                                                                                 );\r
758 }\r
759 \r
760 \r
761 //! draws a set of 2d images, using a color and the alpha channel of the\r
762 //! texture if desired.\r
763 void CNullDriver::draw2DImageBatch(const video::ITexture* texture,\r
764                                 const core::array<core::position2d<s32> >& positions,\r
765                                 const core::array<core::rect<s32> >& sourceRects,\r
766                                 const core::rect<s32>* clipRect,\r
767                                 SColor color,\r
768                                 bool useAlphaChannelOfTexture)\r
769 {\r
770         const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());\r
771 \r
772         for (u32 i=0; i<drawCount; ++i)\r
773         {\r
774                 draw2DImage(texture, positions[i], sourceRects[i],\r
775                                 clipRect, color, useAlphaChannelOfTexture);\r
776         }\r
777 }\r
778 \r
779 \r
780 //! Draws a part of the texture into the rectangle.\r
781 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,\r
782         const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,\r
783         const video::SColor* const colors, bool useAlphaChannelOfTexture)\r
784 {\r
785         if (destRect.isValid())\r
786                 draw2DImage(texture, core::position2d<s32>(destRect.UpperLeftCorner),\r
787                                 sourceRect, clipRect, colors?colors[0]:video::SColor(0xffffffff),\r
788                                 useAlphaChannelOfTexture);\r
789 }\r
790 \r
791 \r
792 //! 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
793 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,\r
794                                 const core::rect<s32>& sourceRect,\r
795                                 const core::rect<s32>* clipRect, SColor color,\r
796                                 bool useAlphaChannelOfTexture)\r
797 {\r
798 }\r
799 \r
800 \r
801 //! Draw a 2d rectangle\r
802 void CNullDriver::draw2DRectangle(SColor color, const core::rect<s32>& pos, const core::rect<s32>* clip)\r
803 {\r
804         draw2DRectangle(pos, color, color, color, color, clip);\r
805 }\r
806 \r
807 \r
808 \r
809 //! Draws a 2d rectangle with a gradient.\r
810 void CNullDriver::draw2DRectangle(const core::rect<s32>& pos,\r
811         SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,\r
812         const core::rect<s32>* clip)\r
813 {\r
814 }\r
815 \r
816 \r
817 \r
818 //! Draws a 2d line.\r
819 void CNullDriver::draw2DLine(const core::position2d<s32>& start,\r
820                                 const core::position2d<s32>& end, SColor color)\r
821 {\r
822 }\r
823 \r
824 \r
825 //! returns color format\r
826 ECOLOR_FORMAT CNullDriver::getColorFormat() const\r
827 {\r
828         return ECF_R5G6B5;\r
829 }\r
830 \r
831 \r
832 //! returns screen size\r
833 const core::dimension2d<u32>& CNullDriver::getScreenSize() const\r
834 {\r
835         return ScreenSize;\r
836 }\r
837 \r
838 \r
839 //! get current render target\r
840 IRenderTarget* CNullDriver::getCurrentRenderTarget() const\r
841 {\r
842         return CurrentRenderTarget;\r
843 }\r
844 \r
845 \r
846 const core::dimension2d<u32>& CNullDriver::getCurrentRenderTargetSize() const\r
847 {\r
848         if (CurrentRenderTargetSize.Width == 0)\r
849                 return ScreenSize;\r
850         else\r
851                 return CurrentRenderTargetSize;\r
852 }\r
853 \r
854 \r
855 // returns current frames per second value\r
856 s32 CNullDriver::getFPS() const\r
857 {\r
858         return FPSCounter.getFPS();\r
859 }\r
860 \r
861 \r
862 \r
863 //! returns amount of primitives (mostly triangles) were drawn in the last frame.\r
864 //! very useful method for statistics.\r
865 u32 CNullDriver::getPrimitiveCountDrawn( u32 param ) const\r
866 {\r
867         return (0 == param) ? FPSCounter.getPrimitive() : (1 == param) ? FPSCounter.getPrimitiveAverage() : FPSCounter.getPrimitiveTotal();\r
868 }\r
869 \r
870 \r
871 \r
872 //! Sets the dynamic ambient light color. The default color is\r
873 //! (0,0,0,0) which means it is dark.\r
874 //! \param color: New color of the ambient light.\r
875 void CNullDriver::setAmbientLight(const SColorf& color)\r
876 {\r
877         AmbientLight = color;\r
878 }\r
879 \r
880 const SColorf& CNullDriver::getAmbientLight() const\r
881 {\r
882         return AmbientLight;\r
883 }\r
884 \r
885 //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8\r
886 //! driver, it would return "Direct3D8".\r
887 \r
888 const wchar_t* CNullDriver::getName() const\r
889 {\r
890         return L"Irrlicht NullDevice";\r
891 }\r
892 \r
893 \r
894 //! Creates a boolean alpha channel of the texture based of an color key.\r
895 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,\r
896                                                                         video::SColor color,\r
897                                                                         bool zeroTexels) const\r
898 {\r
899         if (!texture)\r
900                 return;\r
901 \r
902         if (texture->getColorFormat() != ECF_A1R5G5B5 &&\r
903                 texture->getColorFormat() != ECF_A8R8G8B8 )\r
904         {\r
905                 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);\r
906                 return;\r
907         }\r
908 \r
909         if (texture->getColorFormat() == ECF_A1R5G5B5)\r
910         {\r
911                 u16 *p = (u16*)texture->lock();\r
912 \r
913                 if (!p)\r
914                 {\r
915                         os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);\r
916                         return;\r
917                 }\r
918 \r
919                 const core::dimension2d<u32> dim = texture->getSize();\r
920                 const u32 pitch = texture->getPitch() / 2;\r
921 \r
922                 // color with alpha disabled (i.e. fully transparent)\r
923                 const u16 refZeroAlpha = (0x7fff & color.toA1R5G5B5());\r
924 \r
925                 const u32 pixels = pitch * dim.Height;\r
926 \r
927                 for (u32 pixel = 0; pixel < pixels; ++ pixel)\r
928                 {\r
929                         // If the color matches the reference color, ignoring alphas,\r
930                         // set the alpha to zero.\r
931                         if(((*p) & 0x7fff) == refZeroAlpha)\r
932                         {\r
933                                 if(zeroTexels)\r
934                                         (*p) = 0;\r
935                                 else\r
936                                         (*p) = refZeroAlpha;\r
937                         }\r
938 \r
939                         ++p;\r
940                 }\r
941 \r
942                 texture->unlock();\r
943         }\r
944         else\r
945         {\r
946                 u32 *p = (u32*)texture->lock();\r
947 \r
948                 if (!p)\r
949                 {\r
950                         os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);\r
951                         return;\r
952                 }\r
953 \r
954                 core::dimension2d<u32> dim = texture->getSize();\r
955                 u32 pitch = texture->getPitch() / 4;\r
956 \r
957                 // color with alpha disabled (fully transparent)\r
958                 const u32 refZeroAlpha = 0x00ffffff & color.color;\r
959 \r
960                 const u32 pixels = pitch * dim.Height;\r
961                 for (u32 pixel = 0; pixel < pixels; ++ pixel)\r
962                 {\r
963                         // If the color matches the reference color, ignoring alphas,\r
964                         // set the alpha to zero.\r
965                         if(((*p) & 0x00ffffff) == refZeroAlpha)\r
966                         {\r
967                                 if(zeroTexels)\r
968                                         (*p) = 0;\r
969                                 else\r
970                                         (*p) = refZeroAlpha;\r
971                         }\r
972 \r
973                         ++p;\r
974                 }\r
975 \r
976                 texture->unlock();\r
977         }\r
978         texture->regenerateMipMapLevels();\r
979 }\r
980 \r
981 \r
982 \r
983 //! Creates an boolean alpha channel of the texture based of an color key position.\r
984 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,\r
985                                         core::position2d<s32> colorKeyPixelPos,\r
986                                         bool zeroTexels) const\r
987 {\r
988         if (!texture)\r
989                 return;\r
990 \r
991         if (texture->getColorFormat() != ECF_A1R5G5B5 &&\r
992                 texture->getColorFormat() != ECF_A8R8G8B8 )\r
993         {\r
994                 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);\r
995                 return;\r
996         }\r
997 \r
998         SColor colorKey;\r
999 \r
1000         if (texture->getColorFormat() == ECF_A1R5G5B5)\r
1001         {\r
1002                 u16 *p = (u16*)texture->lock(ETLM_READ_ONLY);\r
1003 \r
1004                 if (!p)\r
1005                 {\r
1006                         os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);\r
1007                         return;\r
1008                 }\r
1009 \r
1010                 u32 pitch = texture->getPitch() / 2;\r
1011 \r
1012                 const u16 key16Bit = 0x7fff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];\r
1013 \r
1014                 colorKey = video::A1R5G5B5toA8R8G8B8(key16Bit);\r
1015         }\r
1016         else\r
1017         {\r
1018                 u32 *p = (u32*)texture->lock(ETLM_READ_ONLY);\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                 u32 pitch = texture->getPitch() / 4;\r
1027                 colorKey = 0x00ffffff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];\r
1028         }\r
1029 \r
1030         texture->unlock();\r
1031         makeColorKeyTexture(texture, colorKey, zeroTexels);\r
1032 }\r
1033 \r
1034 \r
1035 //! Returns the maximum amount of primitives (mostly vertices) which\r
1036 //! the device is able to render with one drawIndexedTriangleList\r
1037 //! call.\r
1038 u32 CNullDriver::getMaximalPrimitiveCount() const\r
1039 {\r
1040         return 0xFFFFFFFF;\r
1041 }\r
1042 \r
1043 \r
1044 //! checks triangle count and print warning if wrong\r
1045 bool CNullDriver::checkPrimitiveCount(u32 prmCount) const\r
1046 {\r
1047         const u32 m = getMaximalPrimitiveCount();\r
1048 \r
1049         if (prmCount > m)\r
1050         {\r
1051                 char tmp[128];\r
1052                 snprintf_irr(tmp, sizeof(tmp), "Could not draw triangles, too many primitives(%u), maximum is %u.", prmCount, m);\r
1053                 os::Printer::log(tmp, ELL_ERROR);\r
1054                 return false;\r
1055         }\r
1056 \r
1057         return true;\r
1058 }\r
1059 \r
1060 bool CNullDriver::checkImage(const core::array<IImage*>& image) const\r
1061 {\r
1062         bool status = true;\r
1063 \r
1064         if (image.size() > 0)\r
1065         {\r
1066                 ECOLOR_FORMAT lastFormat = image[0]->getColorFormat();\r
1067                 core::dimension2d<u32> lastSize = image[0]->getDimension();\r
1068 \r
1069                 for (u32 i = 0; i < image.size() && status; ++i)\r
1070                 {\r
1071                         ECOLOR_FORMAT format = image[i]->getColorFormat();\r
1072                         core::dimension2d<u32> size = image[i]->getDimension();\r
1073 \r
1074                         switch (format)\r
1075                         {\r
1076                         case ECF_DXT1:\r
1077                         case ECF_DXT2:\r
1078                         case ECF_DXT3:\r
1079                         case ECF_DXT4:\r
1080                         case ECF_DXT5:\r
1081                                 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_DXT))\r
1082                                 {\r
1083                                         os::Printer::log("DXT texture compression not available.", ELL_ERROR);\r
1084                                         status = false;\r
1085                                 }\r
1086                                 else if (size.getOptimalSize(true, false) != size)\r
1087                                 {\r
1088                                         os::Printer::log("Invalid size of image for DXT texture, size of image must be power of two.", ELL_ERROR);\r
1089                                         status = false;\r
1090                                 }\r
1091                                 break;\r
1092                         case ECF_PVRTC_RGB2:\r
1093                         case ECF_PVRTC_ARGB2:\r
1094                         case ECF_PVRTC_RGB4:\r
1095                         case ECF_PVRTC_ARGB4:\r
1096                                 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC))\r
1097                                 {\r
1098                                         os::Printer::log("PVRTC texture compression not available.", ELL_ERROR);\r
1099                                         status = false;\r
1100                                 }\r
1101                                 else if (size.getOptimalSize(true, false) != size)\r
1102                                 {\r
1103                                         os::Printer::log("Invalid size of image for PVRTC compressed texture, size of image must be power of two and squared.", ELL_ERROR);\r
1104                                         status = false;\r
1105                                 }\r
1106                                 break;\r
1107                         case ECF_PVRTC2_ARGB2:\r
1108                         case ECF_PVRTC2_ARGB4:\r
1109                                 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC2))\r
1110                                 {\r
1111                                         os::Printer::log("PVRTC2 texture compression not available.", ELL_ERROR);\r
1112                                         status = false;\r
1113                                 }\r
1114                                 break;\r
1115                         case ECF_ETC1:\r
1116                                 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC1))\r
1117                                 {\r
1118                                         os::Printer::log("ETC1 texture compression not available.", ELL_ERROR);\r
1119                                         status = false;\r
1120                                 }\r
1121                                 break;\r
1122                         case ECF_ETC2_RGB:\r
1123                         case ECF_ETC2_ARGB:\r
1124                                 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC2))\r
1125                                 {\r
1126                                         os::Printer::log("ETC2 texture compression not available.", ELL_ERROR);\r
1127                                         status = false;\r
1128                                 }\r
1129                                 break;\r
1130                         default:\r
1131                                 break;\r
1132                         }\r
1133 \r
1134                         if (format != lastFormat || size != lastSize)\r
1135                                 status = false;\r
1136                 }\r
1137         }\r
1138         else\r
1139         {\r
1140                 status = false;\r
1141         }\r
1142 \r
1143         return status;\r
1144 }\r
1145 \r
1146 //! Enables or disables a texture creation flag.\r
1147 void CNullDriver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled)\r
1148 {\r
1149         if (enabled && ((flag == ETCF_ALWAYS_16_BIT) || (flag == ETCF_ALWAYS_32_BIT)\r
1150                 || (flag == ETCF_OPTIMIZED_FOR_QUALITY) || (flag == ETCF_OPTIMIZED_FOR_SPEED)))\r
1151         {\r
1152                 // disable other formats\r
1153                 setTextureCreationFlag(ETCF_ALWAYS_16_BIT, false);\r
1154                 setTextureCreationFlag(ETCF_ALWAYS_32_BIT, false);\r
1155                 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY, false);\r
1156                 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED, false);\r
1157         }\r
1158 \r
1159         // set flag\r
1160         TextureCreationFlags = (TextureCreationFlags & (~flag)) |\r
1161                 ((((u32)!enabled)-1) & flag);\r
1162 }\r
1163 \r
1164 \r
1165 //! Returns if a texture creation flag is enabled or disabled.\r
1166 bool CNullDriver::getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const\r
1167 {\r
1168         return (TextureCreationFlags & flag)!=0;\r
1169 }\r
1170 \r
1171 core::array<IImage*> CNullDriver::createImagesFromFile(const io::path& filename, E_TEXTURE_TYPE* type)\r
1172 {\r
1173         // TO-DO -> use 'move' feature from C++11 standard.\r
1174 \r
1175         core::array<IImage*> imageArray;\r
1176 \r
1177         if (filename.size() > 0)\r
1178         {\r
1179                 io::IReadFile* file = FileSystem->createAndOpenFile(filename);\r
1180 \r
1181                 if (file)\r
1182                 {\r
1183                         imageArray = createImagesFromFile(file, type);\r
1184                         file->drop();\r
1185                 }\r
1186                 else\r
1187                         os::Printer::log("Could not open file of image", filename, ELL_WARNING);\r
1188         }\r
1189 \r
1190         return imageArray;\r
1191 }\r
1192 \r
1193 core::array<IImage*> CNullDriver::createImagesFromFile(io::IReadFile* file, E_TEXTURE_TYPE* type)\r
1194 {\r
1195         // TO-DO -> use 'move' feature from C++11 standard.\r
1196 \r
1197         core::array<IImage*> imageArray;\r
1198 \r
1199         if (file)\r
1200         {\r
1201                 s32 i;\r
1202 \r
1203                 // try to load file based on file extension\r
1204                 for (i = SurfaceLoader.size() - 1; i >= 0; --i)\r
1205                 {\r
1206                         if (SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))\r
1207                         {\r
1208                                 // reset file position which might have changed due to previous loadImage calls\r
1209                                 file->seek(0);\r
1210                                 imageArray = SurfaceLoader[i]->loadImages(file, type);\r
1211 \r
1212                                 if (imageArray.size() == 0)\r
1213                                 {\r
1214                                         file->seek(0);\r
1215                                         IImage* image = SurfaceLoader[i]->loadImage(file);\r
1216 \r
1217                                         if (image)\r
1218                                                 imageArray.push_back(image);\r
1219                                 }\r
1220 \r
1221                                 if (imageArray.size() > 0)\r
1222                                         return imageArray;\r
1223                         }\r
1224                 }\r
1225 \r
1226                 // try to load file based on what is in it\r
1227                 for (i = SurfaceLoader.size() - 1; i >= 0; --i)\r
1228                 {\r
1229                         // dito\r
1230                         file->seek(0);\r
1231                         if (SurfaceLoader[i]->isALoadableFileFormat(file)\r
1232                                 && !SurfaceLoader[i]->isALoadableFileExtension(file->getFileName())     // extension was tried above already\r
1233                                 )\r
1234                         {\r
1235                                 file->seek(0);\r
1236                                 imageArray = SurfaceLoader[i]->loadImages(file, type);\r
1237 \r
1238                                 if (imageArray.size() == 0)\r
1239                                 {\r
1240                                         file->seek(0);\r
1241                                         IImage* image = SurfaceLoader[i]->loadImage(file);\r
1242 \r
1243                                         if (image)\r
1244                                                 imageArray.push_back(image);\r
1245                                 }\r
1246 \r
1247                                 if (imageArray.size() > 0)\r
1248                                         return imageArray;\r
1249                         }\r
1250                 }\r
1251         }\r
1252 \r
1253         return imageArray;\r
1254 }\r
1255 \r
1256 \r
1257 //! Writes the provided image to disk file\r
1258 bool CNullDriver::writeImageToFile(IImage* image, const io::path& filename,u32 param)\r
1259 {\r
1260         io::IWriteFile* file = FileSystem->createAndWriteFile(filename);\r
1261         if(!file)\r
1262                 return false;\r
1263 \r
1264         bool result = writeImageToFile(image, file, param);\r
1265         file->drop();\r
1266 \r
1267         return result;\r
1268 }\r
1269 \r
1270 //! Writes the provided image to a file.\r
1271 bool CNullDriver::writeImageToFile(IImage* image, io::IWriteFile * file, u32 param)\r
1272 {\r
1273         if(!file)\r
1274                 return false;\r
1275 \r
1276         for (s32 i=SurfaceWriter.size()-1; i>=0; --i)\r
1277         {\r
1278                 if (SurfaceWriter[i]->isAWriteableFileExtension(file->getFileName()))\r
1279                 {\r
1280                         bool written = SurfaceWriter[i]->writeImage(file, image, param);\r
1281                         if (written)\r
1282                                 return true;\r
1283                 }\r
1284         }\r
1285         return false; // failed to write\r
1286 }\r
1287 \r
1288 \r
1289 //! Creates a software image from a byte array.\r
1290 IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format,\r
1291         const core::dimension2d<u32>& size, void *data, bool ownForeignMemory,\r
1292         bool deleteMemory)\r
1293 {\r
1294         return new CImage(format, size, data, ownForeignMemory, deleteMemory);\r
1295 }\r
1296 \r
1297 \r
1298 //! Creates an empty software image.\r
1299 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size)\r
1300 {\r
1301         return new CImage(format, size);\r
1302 }\r
1303 \r
1304 \r
1305 //! Creates a software image from another image.\r
1306 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, IImage *imageToCopy)\r
1307 {\r
1308         os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);\r
1309 \r
1310         CImage* tmp = new CImage(format, imageToCopy->getDimension());\r
1311         imageToCopy->copyTo(tmp);\r
1312         return tmp;\r
1313 }\r
1314 \r
1315 \r
1316 //! Creates a software image from part of another image.\r
1317 IImage* CNullDriver::createImage(IImage* imageToCopy, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)\r
1318 {\r
1319         os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);\r
1320         CImage* tmp = new CImage(imageToCopy->getColorFormat(), imageToCopy->getDimension());\r
1321         imageToCopy->copyTo(tmp, core::position2di(0,0), core::recti(pos,size));\r
1322         return tmp;\r
1323 }\r
1324 \r
1325 \r
1326 //! Creates a software image from part of a texture.\r
1327 IImage* CNullDriver::createImage(ITexture* texture, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)\r
1328 {\r
1329         if ((pos==core::position2di(0,0)) && (size == texture->getSize()))\r
1330         {\r
1331                 void * data = texture->lock(ETLM_READ_ONLY);\r
1332                 if ( !data)\r
1333                         return 0;\r
1334                 IImage* image = new CImage(texture->getColorFormat(), size, data, false, false);\r
1335                 texture->unlock();\r
1336                 return image;\r
1337         }\r
1338         else\r
1339         {\r
1340                 // make sure to avoid buffer overruns\r
1341                 // make the vector a separate variable for g++ 3.x\r
1342                 const core::vector2d<u32> leftUpper(core::clamp(static_cast<u32>(pos.X), 0u, texture->getSize().Width),\r
1343                                         core::clamp(static_cast<u32>(pos.Y), 0u, texture->getSize().Height));\r
1344                 const core::rect<u32> clamped(leftUpper,\r
1345                                         core::dimension2du(core::clamp(static_cast<u32>(size.Width), 0u, texture->getSize().Width),\r
1346                                         core::clamp(static_cast<u32>(size.Height), 0u, texture->getSize().Height)));\r
1347                 if (!clamped.isValid())\r
1348                         return 0;\r
1349                 u8* src = static_cast<u8*>(texture->lock(ETLM_READ_ONLY));\r
1350                 if (!src)\r
1351                         return 0;\r
1352                 IImage* image = new CImage(texture->getColorFormat(), clamped.getSize());\r
1353                 u8* dst = static_cast<u8*>(image->getData());\r
1354                 src += clamped.UpperLeftCorner.Y * texture->getPitch() + image->getBytesPerPixel() * clamped.UpperLeftCorner.X;\r
1355                 for (u32 i=0; i<clamped.getHeight(); ++i)\r
1356                 {\r
1357                         video::CColorConverter::convert_viaFormat(src, texture->getColorFormat(), clamped.getWidth(), dst, image->getColorFormat());\r
1358                         src += texture->getPitch();\r
1359                         dst += image->getPitch();\r
1360                 }\r
1361                 texture->unlock();\r
1362                 return image;\r
1363         }\r
1364 }\r
1365 \r
1366 \r
1367 //! Sets the fog mode.\r
1368 void CNullDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, f32 end,\r
1369                 f32 density, bool pixelFog, bool rangeFog)\r
1370 {\r
1371         FogColor = color;\r
1372         FogType = fogType;\r
1373         FogStart = start;\r
1374         FogEnd = end;\r
1375         FogDensity = density;\r
1376         PixelFog = pixelFog;\r
1377         RangeFog = rangeFog;\r
1378 }\r
1379 \r
1380 //! Gets the fog mode.\r
1381 void CNullDriver::getFog(SColor& color, E_FOG_TYPE& fogType, f32& start, f32& end,\r
1382                 f32& density, bool& pixelFog, bool& rangeFog)\r
1383 {\r
1384         color = FogColor;\r
1385         fogType = FogType;\r
1386         start = FogStart;\r
1387         end = FogEnd;\r
1388         density = FogDensity;\r
1389         pixelFog = PixelFog;\r
1390         rangeFog = RangeFog;\r
1391 }\r
1392 \r
1393 //! Draws a mesh buffer\r
1394 void CNullDriver::drawMeshBuffer(const scene::IMeshBuffer* mb)\r
1395 {\r
1396         if (!mb)\r
1397                 return;\r
1398 \r
1399         //IVertexBuffer and IIndexBuffer later\r
1400         SHWBufferLink *HWBuffer=getBufferLink(mb);\r
1401 \r
1402         if (HWBuffer)\r
1403                 drawHardwareBuffer(HWBuffer);\r
1404         else\r
1405                 drawVertexPrimitiveList(mb->getVertices(), mb->getVertexCount(), mb->getIndices(), mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), mb->getIndexType());\r
1406 }\r
1407 \r
1408 \r
1409 //! Draws the normals of a mesh buffer\r
1410 void CNullDriver::drawMeshBufferNormals(const scene::IMeshBuffer* mb, f32 length, SColor color)\r
1411 {\r
1412         const u32 count = mb->getVertexCount();\r
1413         const bool normalize = mb->getMaterial().NormalizeNormals;\r
1414 \r
1415         for (u32 i=0; i < count; ++i)\r
1416         {\r
1417                 core::vector3df normalizedNormal = mb->getNormal(i);\r
1418                 if (normalize)\r
1419                         normalizedNormal.normalize();\r
1420 \r
1421                 const core::vector3df& pos = mb->getPosition(i);\r
1422                 draw3DLine(pos, pos + (normalizedNormal * length), color);\r
1423         }\r
1424 }\r
1425 \r
1426 \r
1427 CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IMeshBuffer* mb)\r
1428 {\r
1429         if (!mb || !isHardwareBufferRecommend(mb))\r
1430                 return 0;\r
1431 \r
1432         //search for hardware links\r
1433         SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());\r
1434         if (HWBuffer)\r
1435                 return HWBuffer;\r
1436 \r
1437         return createHardwareBuffer(mb); //no hardware links, and mesh wants one, create it\r
1438 }\r
1439 \r
1440 \r
1441 //! Update all hardware buffers, remove unused ones\r
1442 void CNullDriver::updateAllHardwareBuffers()\r
1443 {\r
1444         auto it = HWBufferList.begin();\r
1445         while (it != HWBufferList.end()) {\r
1446                 SHWBufferLink *Link = *it;\r
1447                 ++it;\r
1448 \r
1449                 if (!Link->MeshBuffer || Link->MeshBuffer->getReferenceCount() == 1)\r
1450                         deleteHardwareBuffer(Link);\r
1451         }\r
1452 }\r
1453 \r
1454 \r
1455 void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer)\r
1456 {\r
1457         if (!HWBuffer)\r
1458                 return;\r
1459         HWBufferList.erase(HWBuffer->listPosition);\r
1460         delete HWBuffer;\r
1461 }\r
1462 \r
1463 \r
1464 //! Remove hardware buffer\r
1465 void CNullDriver::removeHardwareBuffer(const scene::IMeshBuffer* mb)\r
1466 {\r
1467         if (!mb)\r
1468                 return;\r
1469         SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());\r
1470         if (HWBuffer)\r
1471                 deleteHardwareBuffer(HWBuffer);\r
1472 }\r
1473 \r
1474 \r
1475 //! Remove all hardware buffers\r
1476 void CNullDriver::removeAllHardwareBuffers()\r
1477 {\r
1478         while (!HWBufferList.empty())\r
1479                 deleteHardwareBuffer(HWBufferList.front());\r
1480 }\r
1481 \r
1482 \r
1483 bool CNullDriver::isHardwareBufferRecommend(const scene::IMeshBuffer* mb)\r
1484 {\r
1485         if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))\r
1486                 return false;\r
1487 \r
1488         if (mb->getVertexCount()<MinVertexCountForVBO)\r
1489                 return false;\r
1490 \r
1491         return true;\r
1492 }\r
1493 \r
1494 \r
1495 //! Create occlusion query.\r
1496 /** Use node for identification and mesh for occlusion test. */\r
1497 void CNullDriver::addOcclusionQuery(scene::ISceneNode* node, const scene::IMesh* mesh)\r
1498 {\r
1499         if (!node)\r
1500                 return;\r
1501         if (!mesh)\r
1502         {\r
1503                 if ((node->getType() != scene::ESNT_MESH) && (node->getType() != scene::ESNT_ANIMATED_MESH))\r
1504                         return;\r
1505                 else if (node->getType() == scene::ESNT_MESH)\r
1506                         mesh = static_cast<scene::IMeshSceneNode*>(node)->getMesh();\r
1507                 else\r
1508                         mesh = static_cast<scene::IAnimatedMeshSceneNode*>(node)->getMesh()->getMesh(0);\r
1509                 if (!mesh)\r
1510                         return;\r
1511         }\r
1512 \r
1513         //search for query\r
1514         s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
1515         if (index != -1)\r
1516         {\r
1517                 if (OcclusionQueries[index].Mesh != mesh)\r
1518                 {\r
1519                         OcclusionQueries[index].Mesh->drop();\r
1520                         OcclusionQueries[index].Mesh = mesh;\r
1521                         mesh->grab();\r
1522                 }\r
1523         }\r
1524         else\r
1525         {\r
1526                 OcclusionQueries.push_back(SOccQuery(node, mesh));\r
1527                 node->setAutomaticCulling(node->getAutomaticCulling() | scene::EAC_OCC_QUERY);\r
1528         }\r
1529 }\r
1530 \r
1531 \r
1532 //! Remove occlusion query.\r
1533 void CNullDriver::removeOcclusionQuery(scene::ISceneNode* node)\r
1534 {\r
1535         //search for query\r
1536         s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
1537         if (index != -1)\r
1538         {\r
1539                 node->setAutomaticCulling(node->getAutomaticCulling() & ~scene::EAC_OCC_QUERY);\r
1540                 OcclusionQueries.erase(index);\r
1541         }\r
1542 }\r
1543 \r
1544 \r
1545 //! Remove all occlusion queries.\r
1546 void CNullDriver::removeAllOcclusionQueries()\r
1547 {\r
1548         for (s32 i=OcclusionQueries.size()-1; i>=0; --i)\r
1549         {\r
1550                 removeOcclusionQuery(OcclusionQueries[i].Node);\r
1551         }\r
1552 }\r
1553 \r
1554 \r
1555 //! Run occlusion query. Draws mesh stored in query.\r
1556 /** If the mesh shall be rendered visible, use\r
1557 flag to enable the proper material setting. */\r
1558 void CNullDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible)\r
1559 {\r
1560         if(!node)\r
1561                 return;\r
1562         s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
1563         if (index==-1)\r
1564                 return;\r
1565         OcclusionQueries[index].Run=0;\r
1566         if (!visible)\r
1567         {\r
1568                 SMaterial mat;\r
1569                 mat.Lighting=false;\r
1570                 mat.AntiAliasing=0;\r
1571                 mat.ColorMask=ECP_NONE;\r
1572                 mat.GouraudShading=false;\r
1573                 mat.ZWriteEnable=EZW_OFF;\r
1574                 setMaterial(mat);\r
1575         }\r
1576         setTransform(video::ETS_WORLD, node->getAbsoluteTransformation());\r
1577         const scene::IMesh* mesh = OcclusionQueries[index].Mesh;\r
1578         for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)\r
1579         {\r
1580                 if (visible)\r
1581                         setMaterial(mesh->getMeshBuffer(i)->getMaterial());\r
1582                 drawMeshBuffer(mesh->getMeshBuffer(i));\r
1583         }\r
1584 }\r
1585 \r
1586 \r
1587 //! Run all occlusion queries. Draws all meshes stored in queries.\r
1588 /** If the meshes shall not be rendered visible, use\r
1589 overrideMaterial to disable the color and depth buffer. */\r
1590 void CNullDriver::runAllOcclusionQueries(bool visible)\r
1591 {\r
1592         for (u32 i=0; i<OcclusionQueries.size(); ++i)\r
1593                 runOcclusionQuery(OcclusionQueries[i].Node, visible);\r
1594 }\r
1595 \r
1596 \r
1597 //! Update occlusion query. Retrieves results from GPU.\r
1598 /** If the query shall not block, set the flag to false.\r
1599 Update might not occur in this case, though */\r
1600 void CNullDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block)\r
1601 {\r
1602 }\r
1603 \r
1604 \r
1605 //! Update all occlusion queries. Retrieves results from GPU.\r
1606 /** If the query shall not block, set the flag to false.\r
1607 Update might not occur in this case, though */\r
1608 void CNullDriver::updateAllOcclusionQueries(bool block)\r
1609 {\r
1610         for (u32 i=0; i<OcclusionQueries.size(); ++i)\r
1611         {\r
1612                 if (OcclusionQueries[i].Run==u32(~0))\r
1613                         continue;\r
1614                 updateOcclusionQuery(OcclusionQueries[i].Node, block);\r
1615                 ++OcclusionQueries[i].Run;\r
1616                 if (OcclusionQueries[i].Run>1000)\r
1617                         removeOcclusionQuery(OcclusionQueries[i].Node);\r
1618         }\r
1619 }\r
1620 \r
1621 \r
1622 //! Return query result.\r
1623 /** Return value is the number of visible pixels/fragments.\r
1624 The value is a safe approximation, i.e. can be larger then the\r
1625 actual value of pixels. */\r
1626 u32 CNullDriver::getOcclusionQueryResult(scene::ISceneNode* node) const\r
1627 {\r
1628         return ~0;\r
1629 }\r
1630 \r
1631 \r
1632 //! Create render target.\r
1633 IRenderTarget* CNullDriver::addRenderTarget()\r
1634 {\r
1635         return 0;\r
1636 }\r
1637 \r
1638 \r
1639 //! Remove render target.\r
1640 void CNullDriver::removeRenderTarget(IRenderTarget* renderTarget)\r
1641 {\r
1642         if (!renderTarget)\r
1643                 return;\r
1644 \r
1645         for (u32 i = 0; i < RenderTargets.size(); ++i)\r
1646         {\r
1647                 if (RenderTargets[i] == renderTarget)\r
1648                 {\r
1649                         RenderTargets[i]->drop();\r
1650                         RenderTargets.erase(i);\r
1651 \r
1652                         return;\r
1653                 }\r
1654         }\r
1655 }\r
1656 \r
1657 \r
1658 //! Remove all render targets.\r
1659 void CNullDriver::removeAllRenderTargets()\r
1660 {\r
1661         for (u32 i = 0; i < RenderTargets.size(); ++i)\r
1662                 RenderTargets[i]->drop();\r
1663 \r
1664         RenderTargets.clear();\r
1665 \r
1666         SharedRenderTarget = 0;\r
1667 }\r
1668 \r
1669 \r
1670 //! Only used by the internal engine. Used to notify the driver that\r
1671 //! the window was resized.\r
1672 void CNullDriver::OnResize(const core::dimension2d<u32>& size)\r
1673 {\r
1674         if (ViewPort.getWidth() == (s32)ScreenSize.Width &&\r
1675                 ViewPort.getHeight() == (s32)ScreenSize.Height)\r
1676                 ViewPort = core::rect<s32>(core::position2d<s32>(0,0),\r
1677                                                                         core::dimension2di(size));\r
1678 \r
1679         ScreenSize = size;\r
1680 }\r
1681 \r
1682 \r
1683 // adds a material renderer and drops it afterwards. To be used for internal creation\r
1684 s32 CNullDriver::addAndDropMaterialRenderer(IMaterialRenderer* m)\r
1685 {\r
1686         s32 i = addMaterialRenderer(m);\r
1687 \r
1688         if (m)\r
1689                 m->drop();\r
1690 \r
1691         return i;\r
1692 }\r
1693 \r
1694 \r
1695 //! Adds a new material renderer to the video device.\r
1696 s32 CNullDriver::addMaterialRenderer(IMaterialRenderer* renderer, const char* name)\r
1697 {\r
1698         if (!renderer)\r
1699                 return -1;\r
1700 \r
1701         SMaterialRenderer r;\r
1702         r.Renderer = renderer;\r
1703         r.Name = name;\r
1704 \r
1705         if (name == 0 && (MaterialRenderers.size() < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ))\r
1706         {\r
1707                 // set name of built in renderer so that we don't have to implement name\r
1708                 // setting in all available renderers.\r
1709                 r.Name = sBuiltInMaterialTypeNames[MaterialRenderers.size()];\r
1710         }\r
1711 \r
1712         MaterialRenderers.push_back(r);\r
1713         renderer->grab();\r
1714 \r
1715         return MaterialRenderers.size()-1;\r
1716 }\r
1717 \r
1718 \r
1719 //! Sets the name of a material renderer.\r
1720 void CNullDriver::setMaterialRendererName(s32 idx, const char* name)\r
1721 {\r
1722         if (idx < s32(sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ||\r
1723                 idx >= (s32)MaterialRenderers.size())\r
1724                 return;\r
1725 \r
1726         MaterialRenderers[idx].Name = name;\r
1727 }\r
1728 \r
1729 void CNullDriver::swapMaterialRenderers(u32 idx1, u32 idx2, bool swapNames)\r
1730 {\r
1731         if ( idx1 < MaterialRenderers.size() && idx2 < MaterialRenderers.size() )\r
1732         {\r
1733                 irr::core::swap(MaterialRenderers[idx1].Renderer, MaterialRenderers[idx2].Renderer);\r
1734                 if ( swapNames )\r
1735                         irr::core::swap(MaterialRenderers[idx1].Name, MaterialRenderers[idx2].Name);\r
1736         }\r
1737 }\r
1738 \r
1739 \r
1740 //! Returns driver and operating system specific data about the IVideoDriver.\r
1741 const SExposedVideoData& CNullDriver::getExposedVideoData()\r
1742 {\r
1743         return ExposedData;\r
1744 }\r
1745 \r
1746 \r
1747 //! Returns type of video driver\r
1748 E_DRIVER_TYPE CNullDriver::getDriverType() const\r
1749 {\r
1750         return EDT_NULL;\r
1751 }\r
1752 \r
1753 \r
1754 //! deletes all material renderers\r
1755 void CNullDriver::deleteMaterialRenders()\r
1756 {\r
1757         // delete material renderers\r
1758         for (u32 i=0; i<MaterialRenderers.size(); ++i)\r
1759                 if (MaterialRenderers[i].Renderer)\r
1760                         MaterialRenderers[i].Renderer->drop();\r
1761 \r
1762         MaterialRenderers.clear();\r
1763 }\r
1764 \r
1765 \r
1766 //! Returns pointer to material renderer or null\r
1767 IMaterialRenderer* CNullDriver::getMaterialRenderer(u32 idx) const\r
1768 {\r
1769         if ( idx < MaterialRenderers.size() )\r
1770                 return MaterialRenderers[idx].Renderer;\r
1771         else\r
1772                 return 0;\r
1773 }\r
1774 \r
1775 \r
1776 //! Returns amount of currently available material renderers.\r
1777 u32 CNullDriver::getMaterialRendererCount() const\r
1778 {\r
1779         return MaterialRenderers.size();\r
1780 }\r
1781 \r
1782 \r
1783 //! Returns name of the material renderer\r
1784 const char* CNullDriver::getMaterialRendererName(u32 idx) const\r
1785 {\r
1786         if ( idx < MaterialRenderers.size() )\r
1787                 return MaterialRenderers[idx].Name.c_str();\r
1788 \r
1789         return 0;\r
1790 }\r
1791 \r
1792 \r
1793 //! Returns pointer to the IGPUProgrammingServices interface.\r
1794 IGPUProgrammingServices* CNullDriver::getGPUProgrammingServices()\r
1795 {\r
1796         return this;\r
1797 }\r
1798 \r
1799 \r
1800 //! Adds a new material renderer to the VideoDriver, based on a high level shading language.\r
1801 s32 CNullDriver::addHighLevelShaderMaterial(\r
1802         const c8* vertexShaderProgram,\r
1803         const c8* vertexShaderEntryPointName,\r
1804         E_VERTEX_SHADER_TYPE vsCompileTarget,\r
1805         const c8* pixelShaderProgram,\r
1806         const c8* pixelShaderEntryPointName,\r
1807         E_PIXEL_SHADER_TYPE psCompileTarget,\r
1808         const c8* geometryShaderProgram,\r
1809         const c8* geometryShaderEntryPointName,\r
1810         E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
1811         scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,\r
1812         u32 verticesOut,\r
1813         IShaderConstantSetCallBack* callback,\r
1814         E_MATERIAL_TYPE baseMaterial,\r
1815         s32 userData)\r
1816 {\r
1817         os::Printer::log("High level shader materials not available (yet) in this driver, sorry");\r
1818         return -1;\r
1819 }\r
1820 \r
1821 \r
1822 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),\r
1823 //! but tries to load the programs from files.\r
1824 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(\r
1825                 const io::path& vertexShaderProgramFileName,\r
1826                 const c8* vertexShaderEntryPointName,\r
1827                 E_VERTEX_SHADER_TYPE vsCompileTarget,\r
1828                 const io::path& pixelShaderProgramFileName,\r
1829                 const c8* pixelShaderEntryPointName,\r
1830                 E_PIXEL_SHADER_TYPE psCompileTarget,\r
1831                 const io::path& geometryShaderProgramFileName,\r
1832                 const c8* geometryShaderEntryPointName,\r
1833                 E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
1834                 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,\r
1835                 u32 verticesOut,\r
1836                 IShaderConstantSetCallBack* callback,\r
1837                 E_MATERIAL_TYPE baseMaterial,\r
1838                 s32 userData)\r
1839 {\r
1840         io::IReadFile* vsfile = 0;\r
1841         io::IReadFile* psfile = 0;\r
1842         io::IReadFile* gsfile = 0;\r
1843 \r
1844         if (vertexShaderProgramFileName.size() )\r
1845         {\r
1846                 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);\r
1847                 if (!vsfile)\r
1848                 {\r
1849                         os::Printer::log("Could not open vertex shader program file",\r
1850                                 vertexShaderProgramFileName, ELL_WARNING);\r
1851                 }\r
1852         }\r
1853 \r
1854         if (pixelShaderProgramFileName.size() )\r
1855         {\r
1856                 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);\r
1857                 if (!psfile)\r
1858                 {\r
1859                         os::Printer::log("Could not open pixel shader program file",\r
1860                                 pixelShaderProgramFileName, ELL_WARNING);\r
1861                 }\r
1862         }\r
1863 \r
1864         if (geometryShaderProgramFileName.size() )\r
1865         {\r
1866                 gsfile = FileSystem->createAndOpenFile(geometryShaderProgramFileName);\r
1867                 if (!gsfile)\r
1868                 {\r
1869                         os::Printer::log("Could not open geometry shader program file",\r
1870                                 geometryShaderProgramFileName, ELL_WARNING);\r
1871                 }\r
1872         }\r
1873 \r
1874         s32 result = addHighLevelShaderMaterialFromFiles(\r
1875                 vsfile, vertexShaderEntryPointName, vsCompileTarget,\r
1876                 psfile, pixelShaderEntryPointName, psCompileTarget,\r
1877                 gsfile, geometryShaderEntryPointName, gsCompileTarget,\r
1878                 inType, outType, verticesOut,\r
1879                 callback, baseMaterial, userData);\r
1880 \r
1881         if (psfile)\r
1882                 psfile->drop();\r
1883 \r
1884         if (vsfile)\r
1885                 vsfile->drop();\r
1886 \r
1887         if (gsfile)\r
1888                 gsfile->drop();\r
1889 \r
1890         return result;\r
1891 }\r
1892 \r
1893 \r
1894 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),\r
1895 //! but tries to load the programs from files.\r
1896 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(\r
1897                 io::IReadFile* vertexShaderProgram,\r
1898                 const c8* vertexShaderEntryPointName,\r
1899                 E_VERTEX_SHADER_TYPE vsCompileTarget,\r
1900                 io::IReadFile* pixelShaderProgram,\r
1901                 const c8* pixelShaderEntryPointName,\r
1902                 E_PIXEL_SHADER_TYPE psCompileTarget,\r
1903                 io::IReadFile* geometryShaderProgram,\r
1904                 const c8* geometryShaderEntryPointName,\r
1905                 E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
1906                 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,\r
1907                 u32 verticesOut,\r
1908                 IShaderConstantSetCallBack* callback,\r
1909                 E_MATERIAL_TYPE baseMaterial,\r
1910                 s32 userData)\r
1911 {\r
1912         c8* vs = 0;\r
1913         c8* ps = 0;\r
1914         c8* gs = 0;\r
1915 \r
1916         if (vertexShaderProgram)\r
1917         {\r
1918                 const long size = vertexShaderProgram->getSize();\r
1919                 if (size)\r
1920                 {\r
1921                         vs = new c8[size+1];\r
1922                         vertexShaderProgram->read(vs, size);\r
1923                         vs[size] = 0;\r
1924                 }\r
1925         }\r
1926 \r
1927         if (pixelShaderProgram)\r
1928         {\r
1929                 const long size = pixelShaderProgram->getSize();\r
1930                 if (size)\r
1931                 {\r
1932                         // if both handles are the same we must reset the file\r
1933                         if (pixelShaderProgram==vertexShaderProgram)\r
1934                                 pixelShaderProgram->seek(0);\r
1935                         ps = new c8[size+1];\r
1936                         pixelShaderProgram->read(ps, size);\r
1937                         ps[size] = 0;\r
1938                 }\r
1939         }\r
1940 \r
1941         if (geometryShaderProgram)\r
1942         {\r
1943                 const long size = geometryShaderProgram->getSize();\r
1944                 if (size)\r
1945                 {\r
1946                         // if both handles are the same we must reset the file\r
1947                         if ((geometryShaderProgram==vertexShaderProgram) ||\r
1948                                         (geometryShaderProgram==pixelShaderProgram))\r
1949                                 geometryShaderProgram->seek(0);\r
1950                         gs = new c8[size+1];\r
1951                         geometryShaderProgram->read(gs, size);\r
1952                         gs[size] = 0;\r
1953                 }\r
1954         }\r
1955 \r
1956         s32 result = this->addHighLevelShaderMaterial(\r
1957                 vs, vertexShaderEntryPointName, vsCompileTarget,\r
1958                 ps, pixelShaderEntryPointName, psCompileTarget,\r
1959                 gs, geometryShaderEntryPointName, gsCompileTarget,\r
1960                 inType, outType, verticesOut,\r
1961                 callback, baseMaterial, userData);\r
1962 \r
1963         delete [] vs;\r
1964         delete [] ps;\r
1965         delete [] gs;\r
1966 \r
1967         return result;\r
1968 }\r
1969 \r
1970 \r
1971 //! Adds a new material renderer to the VideoDriver, using pixel and/or\r
1972 //! vertex shaders to render geometry.\r
1973 s32 CNullDriver::addShaderMaterial(const c8* vertexShaderProgram,\r
1974         const c8* pixelShaderProgram,\r
1975         IShaderConstantSetCallBack* callback,\r
1976         E_MATERIAL_TYPE baseMaterial,\r
1977         s32 userData)\r
1978 {\r
1979         os::Printer::log("Shader materials not implemented yet in this driver, sorry.");\r
1980         return -1;\r
1981 }\r
1982 \r
1983 \r
1984 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the\r
1985 //! programs from files.\r
1986 s32 CNullDriver::addShaderMaterialFromFiles(io::IReadFile* vertexShaderProgram,\r
1987         io::IReadFile* pixelShaderProgram,\r
1988         IShaderConstantSetCallBack* callback,\r
1989         E_MATERIAL_TYPE baseMaterial,\r
1990         s32 userData)\r
1991 {\r
1992         c8* vs = 0;\r
1993         c8* ps = 0;\r
1994 \r
1995         if (vertexShaderProgram)\r
1996         {\r
1997                 const long size = vertexShaderProgram->getSize();\r
1998                 if (size)\r
1999                 {\r
2000                         vs = new c8[size+1];\r
2001                         vertexShaderProgram->read(vs, size);\r
2002                         vs[size] = 0;\r
2003                 }\r
2004         }\r
2005 \r
2006         if (pixelShaderProgram)\r
2007         {\r
2008                 const long size = pixelShaderProgram->getSize();\r
2009                 if (size)\r
2010                 {\r
2011                         ps = new c8[size+1];\r
2012                         pixelShaderProgram->read(ps, size);\r
2013                         ps[size] = 0;\r
2014                 }\r
2015         }\r
2016 \r
2017         s32 result = addShaderMaterial(vs, ps, callback, baseMaterial, userData);\r
2018 \r
2019         delete [] vs;\r
2020         delete [] ps;\r
2021 \r
2022         return result;\r
2023 }\r
2024 \r
2025 \r
2026 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the\r
2027 //! programs from files.\r
2028 s32 CNullDriver::addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName,\r
2029         const io::path& pixelShaderProgramFileName,\r
2030         IShaderConstantSetCallBack* callback,\r
2031         E_MATERIAL_TYPE baseMaterial,\r
2032         s32 userData)\r
2033 {\r
2034         io::IReadFile* vsfile = 0;\r
2035         io::IReadFile* psfile = 0;\r
2036 \r
2037         if (vertexShaderProgramFileName.size())\r
2038         {\r
2039                 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);\r
2040                 if (!vsfile)\r
2041                 {\r
2042                         os::Printer::log("Could not open vertex shader program file",\r
2043                                 vertexShaderProgramFileName, ELL_WARNING);\r
2044                         return -1;\r
2045                 }\r
2046         }\r
2047 \r
2048         if (pixelShaderProgramFileName.size())\r
2049         {\r
2050                 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);\r
2051                 if (!psfile)\r
2052                 {\r
2053                         os::Printer::log("Could not open pixel shader program file",\r
2054                                 pixelShaderProgramFileName, ELL_WARNING);\r
2055                         if (vsfile)\r
2056                                 vsfile->drop();\r
2057                         return -1;\r
2058                 }\r
2059         }\r
2060 \r
2061         s32 result = addShaderMaterialFromFiles(vsfile, psfile, callback,\r
2062                 baseMaterial, userData);\r
2063 \r
2064         if (psfile)\r
2065                 psfile->drop();\r
2066 \r
2067         if (vsfile)\r
2068                 vsfile->drop();\r
2069 \r
2070         return result;\r
2071 }\r
2072 \r
2073 \r
2074 //! Creates a render target texture.\r
2075 ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,\r
2076                 const io::path&name, const ECOLOR_FORMAT format)\r
2077 {\r
2078         return 0;\r
2079 }\r
2080 \r
2081 ITexture* CNullDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen,\r
2082                                 const io::path& name, const ECOLOR_FORMAT format)\r
2083 {\r
2084         return 0;\r
2085 }\r
2086 \r
2087 void CNullDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)\r
2088 {\r
2089 }\r
2090 \r
2091 \r
2092 //! Returns a pointer to the mesh manipulator.\r
2093 scene::IMeshManipulator* CNullDriver::getMeshManipulator()\r
2094 {\r
2095         return MeshManipulator;\r
2096 }\r
2097 \r
2098 \r
2099 //! Returns an image created from the last rendered frame.\r
2100 IImage* CNullDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)\r
2101 {\r
2102         return 0;\r
2103 }\r
2104 \r
2105 \r
2106 // prints renderer version\r
2107 void CNullDriver::printVersion()\r
2108 {\r
2109         core::stringw namePrint = L"Using renderer: ";\r
2110         namePrint += getName();\r
2111         os::Printer::log(namePrint.c_str(), ELL_INFORMATION);\r
2112 }\r
2113 \r
2114 \r
2115 //! creates a video driver\r
2116 IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)\r
2117 {\r
2118         CNullDriver* nullDriver = new CNullDriver(io, screenSize);\r
2119 \r
2120         // create empty material renderers\r
2121         for(u32 i=0; sBuiltInMaterialTypeNames[i]; ++i)\r
2122         {\r
2123                 IMaterialRenderer* imr = new IMaterialRenderer();\r
2124                 nullDriver->addMaterialRenderer(imr);\r
2125                 imr->drop();\r
2126         }\r
2127 \r
2128         return nullDriver;\r
2129 }\r
2130 \r
2131 \r
2132 //! Set/unset a clipping plane.\r
2133 //! There are at least 6 clipping planes available for the user to set at will.\r
2134 //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes.\r
2135 //! \param plane: The plane itself.\r
2136 //! \param enable: If true, enable the clipping plane else disable it.\r
2137 bool CNullDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)\r
2138 {\r
2139         return false;\r
2140 }\r
2141 \r
2142 \r
2143 //! Enable/disable a clipping plane.\r
2144 void CNullDriver::enableClipPlane(u32 index, bool enable)\r
2145 {\r
2146         // not necessary\r
2147 }\r
2148 \r
2149 \r
2150 ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d<u32>& size,\r
2151                 const c8* name)\r
2152 {\r
2153         os::Printer::log("createRenderTargetTexture is deprecated, use addRenderTargetTexture instead");\r
2154         ITexture* tex = addRenderTargetTexture(size, name);\r
2155         tex->grab();\r
2156         return tex;\r
2157 }\r
2158 \r
2159 \r
2160 void CNullDriver::setMinHardwareBufferVertexCount(u32 count)\r
2161 {\r
2162         MinVertexCountForVBO = count;\r
2163 }\r
2164 \r
2165 \r
2166 SOverrideMaterial& CNullDriver::getOverrideMaterial()\r
2167 {\r
2168         return OverrideMaterial;\r
2169 }\r
2170 \r
2171 \r
2172 //! Get the 2d override material for altering its values\r
2173 SMaterial& CNullDriver::getMaterial2D()\r
2174 {\r
2175         return OverrideMaterial2D;\r
2176 }\r
2177 \r
2178 \r
2179 //! Enable the 2d override material\r
2180 void CNullDriver::enableMaterial2D(bool enable)\r
2181 {\r
2182         OverrideMaterial2DEnabled=enable;\r
2183 }\r
2184 \r
2185 \r
2186 core::dimension2du CNullDriver::getMaxTextureSize() const\r
2187 {\r
2188         return core::dimension2du(0x10000,0x10000); // maybe large enough\r
2189 }\r
2190 \r
2191 bool CNullDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const\r
2192 {\r
2193         // TODO: I suspect it would be nice if the material had an enum for further control.\r
2194         //              Especially it probably makes sense to allow disabling transparent render pass as soon as material.ZWriteEnable is on.\r
2195         //      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
2196         //      Or we could at least set return false when material.ZWriteEnable is EZW_ON? Still considering that...\r
2197         //              Be careful - this function is deeply connected to getWriteZBuffer as transparent render passes are usually about rendering with\r
2198         //      zwrite disabled and getWriteZBuffer calls this function.\r
2199 \r
2200         video::IMaterialRenderer* rnd = getMaterialRenderer(material.MaterialType);\r
2201         // TODO: I suspect IMaterialRenderer::isTransparent also often could use SMaterial as parameter\r
2202         //       We could for example then get rid of IsTransparent function in SMaterial and move that to the software material renderer.\r
2203         if (rnd && rnd->isTransparent())\r
2204                 return true;\r
2205 \r
2206         return false;\r
2207 }\r
2208 \r
2209 \r
2210 //! Color conversion convenience function\r
2211 /** Convert an image (as array of pixels) from source to destination\r
2212 array, thereby converting the color format. The pixel size is\r
2213 determined by the color formats.\r
2214 \param sP Pointer to source\r
2215 \param sF Color format of source\r
2216 \param sN Number of pixels to convert, both array must be large enough\r
2217 \param dP Pointer to destination\r
2218 \param dF Color format of destination\r
2219 */\r
2220 void CNullDriver::convertColor(const void* sP, ECOLOR_FORMAT sF, s32 sN,\r
2221                 void* dP, ECOLOR_FORMAT dF) const\r
2222 {\r
2223         video::CColorConverter::convert_viaFormat(sP, sF, sN, dP, dF);\r
2224 }\r
2225 \r
2226 \r
2227 } // end namespace\r
2228 } // end namespace\r