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