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