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