]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CNullDriver.cpp
d3b72804f18ca83ea70dcb8acb1109982b089061
[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                 return imageArray;\r
1201 \r
1202         // try to load file based on file extension\r
1203         for (int i = SurfaceLoader.size() - 1; i >= 0; --i) {\r
1204                 if (!SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))\r
1205                         continue;\r
1206 \r
1207                 file->seek(0); // reset file position which might have changed due to previous loadImage calls\r
1208                 if (IImage *image = SurfaceLoader[i]->loadImage(file)) {\r
1209                         imageArray.push_back(image);\r
1210                         return imageArray;\r
1211                 }\r
1212         }\r
1213 \r
1214         // try to load file based on what is in it\r
1215         for (int i = SurfaceLoader.size() - 1; i >= 0; --i) {\r
1216                 if (SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))\r
1217                         continue; // extension was tried above already\r
1218                 file->seek(0); // dito\r
1219                 if (!SurfaceLoader[i]->isALoadableFileFormat(file))\r
1220                         continue;\r
1221 \r
1222                 file->seek(0);\r
1223                 if (IImage *image = SurfaceLoader[i]->loadImage(file)) {\r
1224                         imageArray.push_back(image);\r
1225                         return imageArray;\r
1226                 }\r
1227         }\r
1228 \r
1229         return imageArray;\r
1230 }\r
1231 \r
1232 \r
1233 //! Writes the provided image to disk file\r
1234 bool CNullDriver::writeImageToFile(IImage* image, const io::path& filename,u32 param)\r
1235 {\r
1236         io::IWriteFile* file = FileSystem->createAndWriteFile(filename);\r
1237         if(!file)\r
1238                 return false;\r
1239 \r
1240         bool result = writeImageToFile(image, file, param);\r
1241         file->drop();\r
1242 \r
1243         return result;\r
1244 }\r
1245 \r
1246 //! Writes the provided image to a file.\r
1247 bool CNullDriver::writeImageToFile(IImage* image, io::IWriteFile * file, u32 param)\r
1248 {\r
1249         if(!file)\r
1250                 return false;\r
1251 \r
1252         for (s32 i=SurfaceWriter.size()-1; i>=0; --i)\r
1253         {\r
1254                 if (SurfaceWriter[i]->isAWriteableFileExtension(file->getFileName()))\r
1255                 {\r
1256                         bool written = SurfaceWriter[i]->writeImage(file, image, param);\r
1257                         if (written)\r
1258                                 return true;\r
1259                 }\r
1260         }\r
1261         return false; // failed to write\r
1262 }\r
1263 \r
1264 \r
1265 //! Creates a software image from a byte array.\r
1266 IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format,\r
1267         const core::dimension2d<u32>& size, void *data, bool ownForeignMemory,\r
1268         bool deleteMemory)\r
1269 {\r
1270         return new CImage(format, size, data, ownForeignMemory, deleteMemory);\r
1271 }\r
1272 \r
1273 \r
1274 //! Creates an empty software image.\r
1275 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size)\r
1276 {\r
1277         return new CImage(format, size);\r
1278 }\r
1279 \r
1280 \r
1281 //! Creates a software image from another image.\r
1282 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, IImage *imageToCopy)\r
1283 {\r
1284         os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);\r
1285 \r
1286         CImage* tmp = new CImage(format, imageToCopy->getDimension());\r
1287         imageToCopy->copyTo(tmp);\r
1288         return tmp;\r
1289 }\r
1290 \r
1291 \r
1292 //! Creates a software image from part of another image.\r
1293 IImage* CNullDriver::createImage(IImage* imageToCopy, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)\r
1294 {\r
1295         os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);\r
1296         CImage* tmp = new CImage(imageToCopy->getColorFormat(), imageToCopy->getDimension());\r
1297         imageToCopy->copyTo(tmp, core::position2di(0,0), core::recti(pos,size));\r
1298         return tmp;\r
1299 }\r
1300 \r
1301 \r
1302 //! Creates a software image from part of a texture.\r
1303 IImage* CNullDriver::createImage(ITexture* texture, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)\r
1304 {\r
1305         if ((pos==core::position2di(0,0)) && (size == texture->getSize()))\r
1306         {\r
1307                 void * data = texture->lock(ETLM_READ_ONLY);\r
1308                 if ( !data)\r
1309                         return 0;\r
1310                 IImage* image = new CImage(texture->getColorFormat(), size, data, false, false);\r
1311                 texture->unlock();\r
1312                 return image;\r
1313         }\r
1314         else\r
1315         {\r
1316                 // make sure to avoid buffer overruns\r
1317                 // make the vector a separate variable for g++ 3.x\r
1318                 const core::vector2d<u32> leftUpper(core::clamp(static_cast<u32>(pos.X), 0u, texture->getSize().Width),\r
1319                                         core::clamp(static_cast<u32>(pos.Y), 0u, texture->getSize().Height));\r
1320                 const core::rect<u32> clamped(leftUpper,\r
1321                                         core::dimension2du(core::clamp(static_cast<u32>(size.Width), 0u, texture->getSize().Width),\r
1322                                         core::clamp(static_cast<u32>(size.Height), 0u, texture->getSize().Height)));\r
1323                 if (!clamped.isValid())\r
1324                         return 0;\r
1325                 u8* src = static_cast<u8*>(texture->lock(ETLM_READ_ONLY));\r
1326                 if (!src)\r
1327                         return 0;\r
1328                 IImage* image = new CImage(texture->getColorFormat(), clamped.getSize());\r
1329                 u8* dst = static_cast<u8*>(image->getData());\r
1330                 src += clamped.UpperLeftCorner.Y * texture->getPitch() + image->getBytesPerPixel() * clamped.UpperLeftCorner.X;\r
1331                 for (u32 i=0; i<clamped.getHeight(); ++i)\r
1332                 {\r
1333                         video::CColorConverter::convert_viaFormat(src, texture->getColorFormat(), clamped.getWidth(), dst, image->getColorFormat());\r
1334                         src += texture->getPitch();\r
1335                         dst += image->getPitch();\r
1336                 }\r
1337                 texture->unlock();\r
1338                 return image;\r
1339         }\r
1340 }\r
1341 \r
1342 \r
1343 //! Sets the fog mode.\r
1344 void CNullDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, f32 end,\r
1345                 f32 density, bool pixelFog, bool rangeFog)\r
1346 {\r
1347         FogColor = color;\r
1348         FogType = fogType;\r
1349         FogStart = start;\r
1350         FogEnd = end;\r
1351         FogDensity = density;\r
1352         PixelFog = pixelFog;\r
1353         RangeFog = rangeFog;\r
1354 }\r
1355 \r
1356 //! Gets the fog mode.\r
1357 void CNullDriver::getFog(SColor& color, E_FOG_TYPE& fogType, f32& start, f32& end,\r
1358                 f32& density, bool& pixelFog, bool& rangeFog)\r
1359 {\r
1360         color = FogColor;\r
1361         fogType = FogType;\r
1362         start = FogStart;\r
1363         end = FogEnd;\r
1364         density = FogDensity;\r
1365         pixelFog = PixelFog;\r
1366         rangeFog = RangeFog;\r
1367 }\r
1368 \r
1369 //! Draws a mesh buffer\r
1370 void CNullDriver::drawMeshBuffer(const scene::IMeshBuffer* mb)\r
1371 {\r
1372         if (!mb)\r
1373                 return;\r
1374 \r
1375         //IVertexBuffer and IIndexBuffer later\r
1376         SHWBufferLink *HWBuffer=getBufferLink(mb);\r
1377 \r
1378         if (HWBuffer)\r
1379                 drawHardwareBuffer(HWBuffer);\r
1380         else\r
1381                 drawVertexPrimitiveList(mb->getVertices(), mb->getVertexCount(), mb->getIndices(), mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), mb->getIndexType());\r
1382 }\r
1383 \r
1384 \r
1385 //! Draws the normals of a mesh buffer\r
1386 void CNullDriver::drawMeshBufferNormals(const scene::IMeshBuffer* mb, f32 length, SColor color)\r
1387 {\r
1388         const u32 count = mb->getVertexCount();\r
1389         const bool normalize = mb->getMaterial().NormalizeNormals;\r
1390 \r
1391         for (u32 i=0; i < count; ++i)\r
1392         {\r
1393                 core::vector3df normalizedNormal = mb->getNormal(i);\r
1394                 if (normalize)\r
1395                         normalizedNormal.normalize();\r
1396 \r
1397                 const core::vector3df& pos = mb->getPosition(i);\r
1398                 draw3DLine(pos, pos + (normalizedNormal * length), color);\r
1399         }\r
1400 }\r
1401 \r
1402 \r
1403 CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IMeshBuffer* mb)\r
1404 {\r
1405         if (!mb || !isHardwareBufferRecommend(mb))\r
1406                 return 0;\r
1407 \r
1408         //search for hardware links\r
1409         SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());\r
1410         if (HWBuffer)\r
1411                 return HWBuffer;\r
1412 \r
1413         return createHardwareBuffer(mb); //no hardware links, and mesh wants one, create it\r
1414 }\r
1415 \r
1416 \r
1417 //! Update all hardware buffers, remove unused ones\r
1418 void CNullDriver::updateAllHardwareBuffers()\r
1419 {\r
1420         auto it = HWBufferList.begin();\r
1421         while (it != HWBufferList.end()) {\r
1422                 SHWBufferLink *Link = *it;\r
1423                 ++it;\r
1424 \r
1425                 if (!Link->MeshBuffer || Link->MeshBuffer->getReferenceCount() == 1)\r
1426                         deleteHardwareBuffer(Link);\r
1427         }\r
1428 }\r
1429 \r
1430 \r
1431 void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer)\r
1432 {\r
1433         if (!HWBuffer)\r
1434                 return;\r
1435         HWBufferList.erase(HWBuffer->listPosition);\r
1436         delete HWBuffer;\r
1437 }\r
1438 \r
1439 \r
1440 //! Remove hardware buffer\r
1441 void CNullDriver::removeHardwareBuffer(const scene::IMeshBuffer* mb)\r
1442 {\r
1443         if (!mb)\r
1444                 return;\r
1445         SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());\r
1446         if (HWBuffer)\r
1447                 deleteHardwareBuffer(HWBuffer);\r
1448 }\r
1449 \r
1450 \r
1451 //! Remove all hardware buffers\r
1452 void CNullDriver::removeAllHardwareBuffers()\r
1453 {\r
1454         while (!HWBufferList.empty())\r
1455                 deleteHardwareBuffer(HWBufferList.front());\r
1456 }\r
1457 \r
1458 \r
1459 bool CNullDriver::isHardwareBufferRecommend(const scene::IMeshBuffer* mb)\r
1460 {\r
1461         if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))\r
1462                 return false;\r
1463 \r
1464         if (mb->getVertexCount()<MinVertexCountForVBO)\r
1465                 return false;\r
1466 \r
1467         return true;\r
1468 }\r
1469 \r
1470 \r
1471 //! Create occlusion query.\r
1472 /** Use node for identification and mesh for occlusion test. */\r
1473 void CNullDriver::addOcclusionQuery(scene::ISceneNode* node, const scene::IMesh* mesh)\r
1474 {\r
1475         if (!node)\r
1476                 return;\r
1477         if (!mesh)\r
1478         {\r
1479                 if ((node->getType() != scene::ESNT_MESH) && (node->getType() != scene::ESNT_ANIMATED_MESH))\r
1480                         return;\r
1481                 else if (node->getType() == scene::ESNT_MESH)\r
1482                         mesh = static_cast<scene::IMeshSceneNode*>(node)->getMesh();\r
1483                 else\r
1484                         mesh = static_cast<scene::IAnimatedMeshSceneNode*>(node)->getMesh()->getMesh(0);\r
1485                 if (!mesh)\r
1486                         return;\r
1487         }\r
1488 \r
1489         //search for query\r
1490         s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
1491         if (index != -1)\r
1492         {\r
1493                 if (OcclusionQueries[index].Mesh != mesh)\r
1494                 {\r
1495                         OcclusionQueries[index].Mesh->drop();\r
1496                         OcclusionQueries[index].Mesh = mesh;\r
1497                         mesh->grab();\r
1498                 }\r
1499         }\r
1500         else\r
1501         {\r
1502                 OcclusionQueries.push_back(SOccQuery(node, mesh));\r
1503                 node->setAutomaticCulling(node->getAutomaticCulling() | scene::EAC_OCC_QUERY);\r
1504         }\r
1505 }\r
1506 \r
1507 \r
1508 //! Remove occlusion query.\r
1509 void CNullDriver::removeOcclusionQuery(scene::ISceneNode* node)\r
1510 {\r
1511         //search for query\r
1512         s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
1513         if (index != -1)\r
1514         {\r
1515                 node->setAutomaticCulling(node->getAutomaticCulling() & ~scene::EAC_OCC_QUERY);\r
1516                 OcclusionQueries.erase(index);\r
1517         }\r
1518 }\r
1519 \r
1520 \r
1521 //! Remove all occlusion queries.\r
1522 void CNullDriver::removeAllOcclusionQueries()\r
1523 {\r
1524         for (s32 i=OcclusionQueries.size()-1; i>=0; --i)\r
1525         {\r
1526                 removeOcclusionQuery(OcclusionQueries[i].Node);\r
1527         }\r
1528 }\r
1529 \r
1530 \r
1531 //! Run occlusion query. Draws mesh stored in query.\r
1532 /** If the mesh shall be rendered visible, use\r
1533 flag to enable the proper material setting. */\r
1534 void CNullDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible)\r
1535 {\r
1536         if(!node)\r
1537                 return;\r
1538         s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
1539         if (index==-1)\r
1540                 return;\r
1541         OcclusionQueries[index].Run=0;\r
1542         if (!visible)\r
1543         {\r
1544                 SMaterial mat;\r
1545                 mat.Lighting=false;\r
1546                 mat.AntiAliasing=0;\r
1547                 mat.ColorMask=ECP_NONE;\r
1548                 mat.GouraudShading=false;\r
1549                 mat.ZWriteEnable=EZW_OFF;\r
1550                 setMaterial(mat);\r
1551         }\r
1552         setTransform(video::ETS_WORLD, node->getAbsoluteTransformation());\r
1553         const scene::IMesh* mesh = OcclusionQueries[index].Mesh;\r
1554         for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)\r
1555         {\r
1556                 if (visible)\r
1557                         setMaterial(mesh->getMeshBuffer(i)->getMaterial());\r
1558                 drawMeshBuffer(mesh->getMeshBuffer(i));\r
1559         }\r
1560 }\r
1561 \r
1562 \r
1563 //! Run all occlusion queries. Draws all meshes stored in queries.\r
1564 /** If the meshes shall not be rendered visible, use\r
1565 overrideMaterial to disable the color and depth buffer. */\r
1566 void CNullDriver::runAllOcclusionQueries(bool visible)\r
1567 {\r
1568         for (u32 i=0; i<OcclusionQueries.size(); ++i)\r
1569                 runOcclusionQuery(OcclusionQueries[i].Node, visible);\r
1570 }\r
1571 \r
1572 \r
1573 //! Update occlusion query. Retrieves results from GPU.\r
1574 /** If the query shall not block, set the flag to false.\r
1575 Update might not occur in this case, though */\r
1576 void CNullDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block)\r
1577 {\r
1578 }\r
1579 \r
1580 \r
1581 //! Update all occlusion queries. Retrieves results from GPU.\r
1582 /** If the query shall not block, set the flag to false.\r
1583 Update might not occur in this case, though */\r
1584 void CNullDriver::updateAllOcclusionQueries(bool block)\r
1585 {\r
1586         for (u32 i=0; i<OcclusionQueries.size(); ++i)\r
1587         {\r
1588                 if (OcclusionQueries[i].Run==u32(~0))\r
1589                         continue;\r
1590                 updateOcclusionQuery(OcclusionQueries[i].Node, block);\r
1591                 ++OcclusionQueries[i].Run;\r
1592                 if (OcclusionQueries[i].Run>1000)\r
1593                         removeOcclusionQuery(OcclusionQueries[i].Node);\r
1594         }\r
1595 }\r
1596 \r
1597 \r
1598 //! Return query result.\r
1599 /** Return value is the number of visible pixels/fragments.\r
1600 The value is a safe approximation, i.e. can be larger then the\r
1601 actual value of pixels. */\r
1602 u32 CNullDriver::getOcclusionQueryResult(scene::ISceneNode* node) const\r
1603 {\r
1604         return ~0;\r
1605 }\r
1606 \r
1607 \r
1608 //! Create render target.\r
1609 IRenderTarget* CNullDriver::addRenderTarget()\r
1610 {\r
1611         return 0;\r
1612 }\r
1613 \r
1614 \r
1615 //! Remove render target.\r
1616 void CNullDriver::removeRenderTarget(IRenderTarget* renderTarget)\r
1617 {\r
1618         if (!renderTarget)\r
1619                 return;\r
1620 \r
1621         for (u32 i = 0; i < RenderTargets.size(); ++i)\r
1622         {\r
1623                 if (RenderTargets[i] == renderTarget)\r
1624                 {\r
1625                         RenderTargets[i]->drop();\r
1626                         RenderTargets.erase(i);\r
1627 \r
1628                         return;\r
1629                 }\r
1630         }\r
1631 }\r
1632 \r
1633 \r
1634 //! Remove all render targets.\r
1635 void CNullDriver::removeAllRenderTargets()\r
1636 {\r
1637         for (u32 i = 0; i < RenderTargets.size(); ++i)\r
1638                 RenderTargets[i]->drop();\r
1639 \r
1640         RenderTargets.clear();\r
1641 \r
1642         SharedRenderTarget = 0;\r
1643 }\r
1644 \r
1645 \r
1646 //! Only used by the internal engine. Used to notify the driver that\r
1647 //! the window was resized.\r
1648 void CNullDriver::OnResize(const core::dimension2d<u32>& size)\r
1649 {\r
1650         if (ViewPort.getWidth() == (s32)ScreenSize.Width &&\r
1651                 ViewPort.getHeight() == (s32)ScreenSize.Height)\r
1652                 ViewPort = core::rect<s32>(core::position2d<s32>(0,0),\r
1653                                                                         core::dimension2di(size));\r
1654 \r
1655         ScreenSize = size;\r
1656 }\r
1657 \r
1658 \r
1659 // adds a material renderer and drops it afterwards. To be used for internal creation\r
1660 s32 CNullDriver::addAndDropMaterialRenderer(IMaterialRenderer* m)\r
1661 {\r
1662         s32 i = addMaterialRenderer(m);\r
1663 \r
1664         if (m)\r
1665                 m->drop();\r
1666 \r
1667         return i;\r
1668 }\r
1669 \r
1670 \r
1671 //! Adds a new material renderer to the video device.\r
1672 s32 CNullDriver::addMaterialRenderer(IMaterialRenderer* renderer, const char* name)\r
1673 {\r
1674         if (!renderer)\r
1675                 return -1;\r
1676 \r
1677         SMaterialRenderer r;\r
1678         r.Renderer = renderer;\r
1679         r.Name = name;\r
1680 \r
1681         if (name == 0 && (MaterialRenderers.size() < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ))\r
1682         {\r
1683                 // set name of built in renderer so that we don't have to implement name\r
1684                 // setting in all available renderers.\r
1685                 r.Name = sBuiltInMaterialTypeNames[MaterialRenderers.size()];\r
1686         }\r
1687 \r
1688         MaterialRenderers.push_back(r);\r
1689         renderer->grab();\r
1690 \r
1691         return MaterialRenderers.size()-1;\r
1692 }\r
1693 \r
1694 \r
1695 //! Sets the name of a material renderer.\r
1696 void CNullDriver::setMaterialRendererName(u32 idx, const char* name)\r
1697 {\r
1698         if (idx < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ||\r
1699                 idx >= MaterialRenderers.size())\r
1700                 return;\r
1701 \r
1702         MaterialRenderers[idx].Name = name;\r
1703 }\r
1704 \r
1705 void CNullDriver::swapMaterialRenderers(u32 idx1, u32 idx2, bool swapNames)\r
1706 {\r
1707         if ( idx1 < MaterialRenderers.size() && idx2 < MaterialRenderers.size() )\r
1708         {\r
1709                 irr::core::swap(MaterialRenderers[idx1].Renderer, MaterialRenderers[idx2].Renderer);\r
1710                 if ( swapNames )\r
1711                         irr::core::swap(MaterialRenderers[idx1].Name, MaterialRenderers[idx2].Name);\r
1712         }\r
1713 }\r
1714 \r
1715 \r
1716 //! Returns driver and operating system specific data about the IVideoDriver.\r
1717 const SExposedVideoData& CNullDriver::getExposedVideoData()\r
1718 {\r
1719         return ExposedData;\r
1720 }\r
1721 \r
1722 \r
1723 //! Returns type of video driver\r
1724 E_DRIVER_TYPE CNullDriver::getDriverType() const\r
1725 {\r
1726         return EDT_NULL;\r
1727 }\r
1728 \r
1729 \r
1730 //! deletes all material renderers\r
1731 void CNullDriver::deleteMaterialRenders()\r
1732 {\r
1733         // delete material renderers\r
1734         for (u32 i=0; i<MaterialRenderers.size(); ++i)\r
1735                 if (MaterialRenderers[i].Renderer)\r
1736                         MaterialRenderers[i].Renderer->drop();\r
1737 \r
1738         MaterialRenderers.clear();\r
1739 }\r
1740 \r
1741 \r
1742 //! Returns pointer to material renderer or null\r
1743 IMaterialRenderer* CNullDriver::getMaterialRenderer(u32 idx) const\r
1744 {\r
1745         if ( idx < MaterialRenderers.size() )\r
1746                 return MaterialRenderers[idx].Renderer;\r
1747         else\r
1748                 return 0;\r
1749 }\r
1750 \r
1751 \r
1752 //! Returns amount of currently available material renderers.\r
1753 u32 CNullDriver::getMaterialRendererCount() const\r
1754 {\r
1755         return MaterialRenderers.size();\r
1756 }\r
1757 \r
1758 \r
1759 //! Returns name of the material renderer\r
1760 const char* CNullDriver::getMaterialRendererName(u32 idx) const\r
1761 {\r
1762         if ( idx < MaterialRenderers.size() )\r
1763                 return MaterialRenderers[idx].Name.c_str();\r
1764 \r
1765         return 0;\r
1766 }\r
1767 \r
1768 \r
1769 //! Returns pointer to the IGPUProgrammingServices interface.\r
1770 IGPUProgrammingServices* CNullDriver::getGPUProgrammingServices()\r
1771 {\r
1772         return this;\r
1773 }\r
1774 \r
1775 \r
1776 //! Adds a new material renderer to the VideoDriver, based on a high level shading language.\r
1777 s32 CNullDriver::addHighLevelShaderMaterial(\r
1778         const c8* vertexShaderProgram,\r
1779         const c8* vertexShaderEntryPointName,\r
1780         E_VERTEX_SHADER_TYPE vsCompileTarget,\r
1781         const c8* pixelShaderProgram,\r
1782         const c8* pixelShaderEntryPointName,\r
1783         E_PIXEL_SHADER_TYPE psCompileTarget,\r
1784         const c8* geometryShaderProgram,\r
1785         const c8* geometryShaderEntryPointName,\r
1786         E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
1787         scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,\r
1788         u32 verticesOut,\r
1789         IShaderConstantSetCallBack* callback,\r
1790         E_MATERIAL_TYPE baseMaterial,\r
1791         s32 userData)\r
1792 {\r
1793         os::Printer::log("High level shader materials not available (yet) in this driver, sorry");\r
1794         return -1;\r
1795 }\r
1796 \r
1797 \r
1798 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),\r
1799 //! but tries to load the programs from files.\r
1800 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(\r
1801                 const io::path& vertexShaderProgramFileName,\r
1802                 const c8* vertexShaderEntryPointName,\r
1803                 E_VERTEX_SHADER_TYPE vsCompileTarget,\r
1804                 const io::path& pixelShaderProgramFileName,\r
1805                 const c8* pixelShaderEntryPointName,\r
1806                 E_PIXEL_SHADER_TYPE psCompileTarget,\r
1807                 const io::path& geometryShaderProgramFileName,\r
1808                 const c8* geometryShaderEntryPointName,\r
1809                 E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
1810                 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,\r
1811                 u32 verticesOut,\r
1812                 IShaderConstantSetCallBack* callback,\r
1813                 E_MATERIAL_TYPE baseMaterial,\r
1814                 s32 userData)\r
1815 {\r
1816         io::IReadFile* vsfile = 0;\r
1817         io::IReadFile* psfile = 0;\r
1818         io::IReadFile* gsfile = 0;\r
1819 \r
1820         if (vertexShaderProgramFileName.size() )\r
1821         {\r
1822                 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);\r
1823                 if (!vsfile)\r
1824                 {\r
1825                         os::Printer::log("Could not open vertex shader program file",\r
1826                                 vertexShaderProgramFileName, ELL_WARNING);\r
1827                 }\r
1828         }\r
1829 \r
1830         if (pixelShaderProgramFileName.size() )\r
1831         {\r
1832                 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);\r
1833                 if (!psfile)\r
1834                 {\r
1835                         os::Printer::log("Could not open pixel shader program file",\r
1836                                 pixelShaderProgramFileName, ELL_WARNING);\r
1837                 }\r
1838         }\r
1839 \r
1840         if (geometryShaderProgramFileName.size() )\r
1841         {\r
1842                 gsfile = FileSystem->createAndOpenFile(geometryShaderProgramFileName);\r
1843                 if (!gsfile)\r
1844                 {\r
1845                         os::Printer::log("Could not open geometry shader program file",\r
1846                                 geometryShaderProgramFileName, ELL_WARNING);\r
1847                 }\r
1848         }\r
1849 \r
1850         s32 result = addHighLevelShaderMaterialFromFiles(\r
1851                 vsfile, vertexShaderEntryPointName, vsCompileTarget,\r
1852                 psfile, pixelShaderEntryPointName, psCompileTarget,\r
1853                 gsfile, geometryShaderEntryPointName, gsCompileTarget,\r
1854                 inType, outType, verticesOut,\r
1855                 callback, baseMaterial, userData);\r
1856 \r
1857         if (psfile)\r
1858                 psfile->drop();\r
1859 \r
1860         if (vsfile)\r
1861                 vsfile->drop();\r
1862 \r
1863         if (gsfile)\r
1864                 gsfile->drop();\r
1865 \r
1866         return result;\r
1867 }\r
1868 \r
1869 \r
1870 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),\r
1871 //! but tries to load the programs from files.\r
1872 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(\r
1873                 io::IReadFile* vertexShaderProgram,\r
1874                 const c8* vertexShaderEntryPointName,\r
1875                 E_VERTEX_SHADER_TYPE vsCompileTarget,\r
1876                 io::IReadFile* pixelShaderProgram,\r
1877                 const c8* pixelShaderEntryPointName,\r
1878                 E_PIXEL_SHADER_TYPE psCompileTarget,\r
1879                 io::IReadFile* geometryShaderProgram,\r
1880                 const c8* geometryShaderEntryPointName,\r
1881                 E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
1882                 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,\r
1883                 u32 verticesOut,\r
1884                 IShaderConstantSetCallBack* callback,\r
1885                 E_MATERIAL_TYPE baseMaterial,\r
1886                 s32 userData)\r
1887 {\r
1888         c8* vs = 0;\r
1889         c8* ps = 0;\r
1890         c8* gs = 0;\r
1891 \r
1892         if (vertexShaderProgram)\r
1893         {\r
1894                 const long size = vertexShaderProgram->getSize();\r
1895                 if (size)\r
1896                 {\r
1897                         vs = new c8[size+1];\r
1898                         vertexShaderProgram->read(vs, size);\r
1899                         vs[size] = 0;\r
1900                 }\r
1901         }\r
1902 \r
1903         if (pixelShaderProgram)\r
1904         {\r
1905                 const long size = pixelShaderProgram->getSize();\r
1906                 if (size)\r
1907                 {\r
1908                         // if both handles are the same we must reset the file\r
1909                         if (pixelShaderProgram==vertexShaderProgram)\r
1910                                 pixelShaderProgram->seek(0);\r
1911                         ps = new c8[size+1];\r
1912                         pixelShaderProgram->read(ps, size);\r
1913                         ps[size] = 0;\r
1914                 }\r
1915         }\r
1916 \r
1917         if (geometryShaderProgram)\r
1918         {\r
1919                 const long size = geometryShaderProgram->getSize();\r
1920                 if (size)\r
1921                 {\r
1922                         // if both handles are the same we must reset the file\r
1923                         if ((geometryShaderProgram==vertexShaderProgram) ||\r
1924                                         (geometryShaderProgram==pixelShaderProgram))\r
1925                                 geometryShaderProgram->seek(0);\r
1926                         gs = new c8[size+1];\r
1927                         geometryShaderProgram->read(gs, size);\r
1928                         gs[size] = 0;\r
1929                 }\r
1930         }\r
1931 \r
1932         s32 result = this->addHighLevelShaderMaterial(\r
1933                 vs, vertexShaderEntryPointName, vsCompileTarget,\r
1934                 ps, pixelShaderEntryPointName, psCompileTarget,\r
1935                 gs, geometryShaderEntryPointName, gsCompileTarget,\r
1936                 inType, outType, verticesOut,\r
1937                 callback, baseMaterial, userData);\r
1938 \r
1939         delete [] vs;\r
1940         delete [] ps;\r
1941         delete [] gs;\r
1942 \r
1943         return result;\r
1944 }\r
1945 \r
1946 \r
1947 //! Adds a new material renderer to the VideoDriver, using pixel and/or\r
1948 //! vertex shaders to render geometry.\r
1949 s32 CNullDriver::addShaderMaterial(const c8* vertexShaderProgram,\r
1950         const c8* pixelShaderProgram,\r
1951         IShaderConstantSetCallBack* callback,\r
1952         E_MATERIAL_TYPE baseMaterial,\r
1953         s32 userData)\r
1954 {\r
1955         os::Printer::log("Shader materials not implemented yet in this driver, sorry.");\r
1956         return -1;\r
1957 }\r
1958 \r
1959 \r
1960 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the\r
1961 //! programs from files.\r
1962 s32 CNullDriver::addShaderMaterialFromFiles(io::IReadFile* vertexShaderProgram,\r
1963         io::IReadFile* pixelShaderProgram,\r
1964         IShaderConstantSetCallBack* callback,\r
1965         E_MATERIAL_TYPE baseMaterial,\r
1966         s32 userData)\r
1967 {\r
1968         c8* vs = 0;\r
1969         c8* ps = 0;\r
1970 \r
1971         if (vertexShaderProgram)\r
1972         {\r
1973                 const long size = vertexShaderProgram->getSize();\r
1974                 if (size)\r
1975                 {\r
1976                         vs = new c8[size+1];\r
1977                         vertexShaderProgram->read(vs, size);\r
1978                         vs[size] = 0;\r
1979                 }\r
1980         }\r
1981 \r
1982         if (pixelShaderProgram)\r
1983         {\r
1984                 const long size = pixelShaderProgram->getSize();\r
1985                 if (size)\r
1986                 {\r
1987                         ps = new c8[size+1];\r
1988                         pixelShaderProgram->read(ps, size);\r
1989                         ps[size] = 0;\r
1990                 }\r
1991         }\r
1992 \r
1993         s32 result = addShaderMaterial(vs, ps, callback, baseMaterial, userData);\r
1994 \r
1995         delete [] vs;\r
1996         delete [] ps;\r
1997 \r
1998         return result;\r
1999 }\r
2000 \r
2001 \r
2002 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the\r
2003 //! programs from files.\r
2004 s32 CNullDriver::addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName,\r
2005         const io::path& pixelShaderProgramFileName,\r
2006         IShaderConstantSetCallBack* callback,\r
2007         E_MATERIAL_TYPE baseMaterial,\r
2008         s32 userData)\r
2009 {\r
2010         io::IReadFile* vsfile = 0;\r
2011         io::IReadFile* psfile = 0;\r
2012 \r
2013         if (vertexShaderProgramFileName.size())\r
2014         {\r
2015                 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);\r
2016                 if (!vsfile)\r
2017                 {\r
2018                         os::Printer::log("Could not open vertex shader program file",\r
2019                                 vertexShaderProgramFileName, ELL_WARNING);\r
2020                         return -1;\r
2021                 }\r
2022         }\r
2023 \r
2024         if (pixelShaderProgramFileName.size())\r
2025         {\r
2026                 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);\r
2027                 if (!psfile)\r
2028                 {\r
2029                         os::Printer::log("Could not open pixel shader program file",\r
2030                                 pixelShaderProgramFileName, ELL_WARNING);\r
2031                         if (vsfile)\r
2032                                 vsfile->drop();\r
2033                         return -1;\r
2034                 }\r
2035         }\r
2036 \r
2037         s32 result = addShaderMaterialFromFiles(vsfile, psfile, callback,\r
2038                 baseMaterial, userData);\r
2039 \r
2040         if (psfile)\r
2041                 psfile->drop();\r
2042 \r
2043         if (vsfile)\r
2044                 vsfile->drop();\r
2045 \r
2046         return result;\r
2047 }\r
2048 \r
2049 \r
2050 //! Creates a render target texture.\r
2051 ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,\r
2052                 const io::path&name, const ECOLOR_FORMAT format)\r
2053 {\r
2054         return 0;\r
2055 }\r
2056 \r
2057 ITexture* CNullDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen,\r
2058                                 const io::path& name, const ECOLOR_FORMAT format)\r
2059 {\r
2060         return 0;\r
2061 }\r
2062 \r
2063 void CNullDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)\r
2064 {\r
2065 }\r
2066 \r
2067 \r
2068 //! Returns a pointer to the mesh manipulator.\r
2069 scene::IMeshManipulator* CNullDriver::getMeshManipulator()\r
2070 {\r
2071         return MeshManipulator;\r
2072 }\r
2073 \r
2074 \r
2075 //! Returns an image created from the last rendered frame.\r
2076 IImage* CNullDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)\r
2077 {\r
2078         return 0;\r
2079 }\r
2080 \r
2081 \r
2082 // prints renderer version\r
2083 void CNullDriver::printVersion()\r
2084 {\r
2085         core::stringw namePrint = L"Using renderer: ";\r
2086         namePrint += getName();\r
2087         os::Printer::log(namePrint.c_str(), ELL_INFORMATION);\r
2088 }\r
2089 \r
2090 \r
2091 //! creates a video driver\r
2092 IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)\r
2093 {\r
2094         CNullDriver* nullDriver = new CNullDriver(io, screenSize);\r
2095 \r
2096         // create empty material renderers\r
2097         for(u32 i=0; sBuiltInMaterialTypeNames[i]; ++i)\r
2098         {\r
2099                 IMaterialRenderer* imr = new IMaterialRenderer();\r
2100                 nullDriver->addMaterialRenderer(imr);\r
2101                 imr->drop();\r
2102         }\r
2103 \r
2104         return nullDriver;\r
2105 }\r
2106 \r
2107 \r
2108 //! Set/unset a clipping plane.\r
2109 //! There are at least 6 clipping planes available for the user to set at will.\r
2110 //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes.\r
2111 //! \param plane: The plane itself.\r
2112 //! \param enable: If true, enable the clipping plane else disable it.\r
2113 bool CNullDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)\r
2114 {\r
2115         return false;\r
2116 }\r
2117 \r
2118 \r
2119 //! Enable/disable a clipping plane.\r
2120 void CNullDriver::enableClipPlane(u32 index, bool enable)\r
2121 {\r
2122         // not necessary\r
2123 }\r
2124 \r
2125 \r
2126 ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d<u32>& size,\r
2127                 const c8* name)\r
2128 {\r
2129         os::Printer::log("createRenderTargetTexture is deprecated, use addRenderTargetTexture instead");\r
2130         ITexture* tex = addRenderTargetTexture(size, name);\r
2131         tex->grab();\r
2132         return tex;\r
2133 }\r
2134 \r
2135 \r
2136 void CNullDriver::setMinHardwareBufferVertexCount(u32 count)\r
2137 {\r
2138         MinVertexCountForVBO = count;\r
2139 }\r
2140 \r
2141 \r
2142 SOverrideMaterial& CNullDriver::getOverrideMaterial()\r
2143 {\r
2144         return OverrideMaterial;\r
2145 }\r
2146 \r
2147 \r
2148 //! Get the 2d override material for altering its values\r
2149 SMaterial& CNullDriver::getMaterial2D()\r
2150 {\r
2151         return OverrideMaterial2D;\r
2152 }\r
2153 \r
2154 \r
2155 //! Enable the 2d override material\r
2156 void CNullDriver::enableMaterial2D(bool enable)\r
2157 {\r
2158         OverrideMaterial2DEnabled=enable;\r
2159 }\r
2160 \r
2161 \r
2162 core::dimension2du CNullDriver::getMaxTextureSize() const\r
2163 {\r
2164         return core::dimension2du(0x10000,0x10000); // maybe large enough\r
2165 }\r
2166 \r
2167 bool CNullDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const\r
2168 {\r
2169         // TODO: I suspect it would be nice if the material had an enum for further control.\r
2170         //              Especially it probably makes sense to allow disabling transparent render pass as soon as material.ZWriteEnable is on.\r
2171         //      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
2172         //      Or we could at least set return false when material.ZWriteEnable is EZW_ON? Still considering that...\r
2173         //              Be careful - this function is deeply connected to getWriteZBuffer as transparent render passes are usually about rendering with\r
2174         //      zwrite disabled and getWriteZBuffer calls this function.\r
2175 \r
2176         video::IMaterialRenderer* rnd = getMaterialRenderer(material.MaterialType);\r
2177         // TODO: I suspect IMaterialRenderer::isTransparent also often could use SMaterial as parameter\r
2178         //       We could for example then get rid of IsTransparent function in SMaterial and move that to the software material renderer.\r
2179         if (rnd && rnd->isTransparent())\r
2180                 return true;\r
2181 \r
2182         return false;\r
2183 }\r
2184 \r
2185 \r
2186 //! Color conversion convenience function\r
2187 /** Convert an image (as array of pixels) from source to destination\r
2188 array, thereby converting the color format. The pixel size is\r
2189 determined by the color formats.\r
2190 \param sP Pointer to source\r
2191 \param sF Color format of source\r
2192 \param sN Number of pixels to convert, both array must be large enough\r
2193 \param dP Pointer to destination\r
2194 \param dF Color format of destination\r
2195 */\r
2196 void CNullDriver::convertColor(const void* sP, ECOLOR_FORMAT sF, s32 sN,\r
2197                 void* dP, ECOLOR_FORMAT dF) const\r
2198 {\r
2199         video::CColorConverter::convert_viaFormat(sP, sF, sN, dP, dF);\r
2200 }\r
2201 \r
2202 \r
2203 } // end namespace\r
2204 } // end namespace\r