1 // Copyright (C) 2013 Patryk Nadrowski
2 // Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt
3 // OpenGL ES driver implemented by Christian Stehno and first OpenGL ES 2.0
4 // driver implemented by Amundis.
5 // This file is part of the "Irrlicht Engine".
6 // For conditions of distribution and use, see copyright notice in Irrlicht.h
7 
8 #include "IrrCompileConfig.h"
9 
10 #ifdef _IRR_COMPILE_WITH_OGLES2_
11 
12 #include "irrTypes.h"
13 #include "COGLES2Texture.h"
14 #include "COGLES2Driver.h"
15 #include "os.h"
16 #include "CImage.h"
17 #include "CColorConverter.h"
18 #include "IAttributes.h"
19 #include "IrrlichtDevice.h"
20 
21 #include "irrString.h"
22 
23 #ifndef IOS_STK
24 #include <GLES2/gl2.h>
25 #include <GLES2/gl2ext.h>
26 #include <EGL/egl.h>
27 #endif
28 
29 namespace
30 {
31 #ifndef GL_BGRA
32 // we need to do this for the IMG_BGRA8888 extension
33 int GL_BGRA=GL_RGBA;
34 #endif
35 }
36 
37 namespace irr
38 {
39 namespace video
40 {
41 
42 //! constructor for usual textures
COGLES2Texture(IImage * origImage,const io::path & name,void * mipmapData,COGLES2Driver * driver)43 COGLES2Texture::COGLES2Texture(IImage* origImage, const io::path& name, void* mipmapData, COGLES2Driver* driver)
44 	: ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
45 	TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
46 	PixelType(GL_UNSIGNED_BYTE), MipLevelStored(0),
47 	IsRenderTarget(false), AutomaticMipmapUpdate(false),
48 	ReadOnlyLock(false), KeepImage(true)
49 {
50 	#ifdef _DEBUG
51 	setDebugName("COGLES2Texture");
52 	#endif
53 
54 	HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
55 	getImageValues(origImage);
56 
57 	glGenTextures(1, &TextureName);
58 
59 	if (ImageSize==TextureSize)
60 	{
61 		Image = Driver->createImage(ColorFormat, ImageSize);
62 		origImage->copyTo(Image);
63 	}
64 	else
65 	{
66 		Image = Driver->createImage(ColorFormat, TextureSize);
67 		// scale texture
68 		origImage->copyToScaling(Image);
69 	}
70 	uploadTexture(true, mipmapData);
71 	if (!KeepImage)
72 	{
73 		Image->drop();
74 		Image=0;
75 	}
76 }
77 
78 
79 //! constructor for basic setup (only for derived classes)
COGLES2Texture(const io::path & name,COGLES2Driver * driver)80 COGLES2Texture::COGLES2Texture(const io::path& name, COGLES2Driver* driver)
81 	: ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
82 	TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
83 	PixelType(GL_UNSIGNED_BYTE), MipLevelStored(0), HasMipMaps(true),
84 	IsRenderTarget(false), AutomaticMipmapUpdate(false),
85 	ReadOnlyLock(false), KeepImage(true)
86 {
87 	#ifdef _DEBUG
88 	setDebugName("COGLES2Texture");
89 	#endif
90 }
91 
92 
93 //! destructor
~COGLES2Texture()94 COGLES2Texture::~COGLES2Texture()
95 {
96 	if (TextureName)
97 		glDeleteTextures(1, &TextureName);
98 	if (Image)
99 		Image->drop();
100 }
101 
102 
103 //! Choose best matching color format, based on texture creation flags
getBestColorFormat(ECOLOR_FORMAT format)104 ECOLOR_FORMAT COGLES2Texture::getBestColorFormat(ECOLOR_FORMAT format)
105 {
106 	ECOLOR_FORMAT destFormat = ECF_A8R8G8B8;
107 	switch (format)
108 	{
109 		case ECF_A1R5G5B5:
110 			if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))
111 				destFormat = ECF_A1R5G5B5;
112 		break;
113 		case ECF_R5G6B5:
114 			if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))
115 				destFormat = ECF_A1R5G5B5;
116 		break;
117 		case ECF_A8R8G8B8:
118 			if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) ||
119 					Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
120 				destFormat = ECF_A1R5G5B5;
121 		break;
122 		case ECF_R8G8B8:
123 			if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) ||
124 					Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
125 				destFormat = ECF_A1R5G5B5;
126 		default:
127 		break;
128 	}
129 	if (Driver->getTextureCreationFlag(ETCF_NO_ALPHA_CHANNEL))
130 	{
131 		switch (destFormat)
132 		{
133 			case ECF_A1R5G5B5:
134 				destFormat = ECF_R5G6B5;
135 			break;
136 			case ECF_A8R8G8B8:
137 				destFormat = ECF_R8G8B8;
138 			break;
139 			default:
140 			break;
141 		}
142 	}
143 	return destFormat;
144 }
145 
146 
147 // prepare values ImageSize, TextureSize, and ColorFormat based on image
getImageValues(IImage * image)148 void COGLES2Texture::getImageValues(IImage* image)
149 {
150 	if (!image)
151 	{
152 		os::Printer::log("No image for OpenGL texture.", ELL_ERROR);
153 		return;
154 	}
155 
156 	ImageSize = image->getDimension();
157 
158 	if ( !ImageSize.Width || !ImageSize.Height)
159 	{
160 		os::Printer::log("Invalid size of image for OpenGL Texture.", ELL_ERROR);
161 		return;
162 	}
163 
164 	const f32 ratio = (f32)ImageSize.Width/(f32)ImageSize.Height;
165 	if ((ImageSize.Width>Driver->MaxTextureSize) && (ratio >= 1.0f))
166 	{
167 		ImageSize.Width = Driver->MaxTextureSize;
168 		ImageSize.Height = (u32)(Driver->MaxTextureSize/ratio);
169 	}
170 	else if (ImageSize.Height>Driver->MaxTextureSize)
171 	{
172 		ImageSize.Height = Driver->MaxTextureSize;
173 		ImageSize.Width = (u32)(Driver->MaxTextureSize*ratio);
174 	}
175 	TextureSize=ImageSize.getOptimalSize(false);
176     const core::dimension2du max_size = Driver->getDriverAttributes()
177                                  .getAttributeAsDimension2d("MAX_TEXTURE_SIZE");
178 
179     if (max_size.Width> 0 && TextureSize.Width > max_size.Width)
180     {
181         TextureSize.Width = max_size.Width;
182     }
183     if (max_size.Height> 0 && TextureSize.Height > max_size.Height)
184     {
185         TextureSize.Height = max_size.Height;
186     }
187 
188 	ColorFormat = getBestColorFormat(image->getColorFormat());
189 }
190 
191 
192 //! copies the the texture into an open gl texture.
uploadTexture(bool newTexture,void * mipmapData,u32 level)193 void COGLES2Texture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
194 {
195 	// check which image needs to be uploaded
196 	IImage* image = level?MipImage:Image;
197 	if (!image)
198 	{
199 		os::Printer::log("No image for OGLES2 texture to upload", ELL_ERROR);
200 		return;
201 	}
202 
203 #ifndef GL_BGRA
204 	// whoa, pretty badly implemented extension...
205 	if (Driver->FeatureAvailable[COGLES2ExtensionHandler::IRR_IMG_texture_format_BGRA8888] || Driver->FeatureAvailable[COGLES2ExtensionHandler::IRR_EXT_texture_format_BGRA8888])
206 		GL_BGRA=0x80E1;
207 	else
208 		GL_BGRA=GL_RGBA;
209 #endif
210 
211 	GLenum oldInternalFormat = InternalFormat;
212 	void(*convert)(const void*, s32, void*)=0;
213 	switch (Image->getColorFormat())
214 	{
215 		case ECF_A1R5G5B5:
216 			InternalFormat=GL_RGBA;
217 			PixelFormat=GL_RGBA;
218 			PixelType=GL_UNSIGNED_SHORT_5_5_5_1;
219 			convert=CColorConverter::convert_A1R5G5B5toR5G5B5A1;
220 			break;
221 		case ECF_R5G6B5:
222 			InternalFormat=GL_RGB;
223 			PixelFormat=GL_RGB;
224 			PixelType=GL_UNSIGNED_SHORT_5_6_5;
225 			break;
226 		case ECF_R8G8B8:
227 			InternalFormat=GL_RGB;
228 			PixelFormat=GL_RGB;
229 			PixelType=GL_UNSIGNED_BYTE;
230 			convert=CColorConverter::convert_R8G8B8toB8G8R8;
231 			break;
232 		case ECF_A8R8G8B8:
233 			PixelType=GL_UNSIGNED_BYTE;
234 			if (!Driver->queryOpenGLFeature(COGLES2ExtensionHandler::IRR_IMG_texture_format_BGRA8888) && !Driver->queryOpenGLFeature(COGLES2ExtensionHandler::IRR_EXT_texture_format_BGRA8888))
235 			{
236 				convert=CColorConverter::convert_A8R8G8B8toA8B8G8R8;
237 				InternalFormat=GL_RGBA;
238 				PixelFormat=GL_RGBA;
239 			}
240 			else
241 			{
242 				InternalFormat=GL_BGRA;
243 				PixelFormat=GL_BGRA;
244 			}
245 			break;
246 		default:
247 			os::Printer::log("Unsupported texture format", ELL_ERROR);
248 			break;
249 	}
250 	// Hack for iPhone SDK, which requires a different InternalFormat
251 #ifdef _IRR_IOS_PLATFORM_
252 	if (InternalFormat==GL_BGRA)
253 		InternalFormat=GL_RGBA;
254 #endif
255 	// make sure we don't change the internal format of existing matrices
256 	if (!newTexture)
257 		InternalFormat=oldInternalFormat;
258 
259     Driver->setActiveTexture(0, this);
260 	Driver->getBridgeCalls()->setTexture(0);
261 
262 	if (Driver->testGLError())
263 		os::Printer::log("Could not bind Texture", ELL_ERROR);
264 
265 	// mipmap handling for main texture
266 	if (!level && newTexture)
267 	{
268 #ifndef DISABLE_MIPMAPPING
269 		// auto generate if possible and no mipmap data is given
270 		if (HasMipMaps && !mipmapData)
271 		{
272 			if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
273 				glHint(GL_GENERATE_MIPMAP_HINT, GL_FASTEST);
274 			else if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY))
275 				glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
276 			else
277 				glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE);
278 
279 			AutomaticMipmapUpdate=true;
280 		}
281 		else
282 		{
283 			// Either generate manually due to missing capability
284 			// or use predefined mipmap data
285 			AutomaticMipmapUpdate=false;
286 			regenerateMipMapLevels(mipmapData);
287 		}
288 
289 		if (HasMipMaps) // might have changed in regenerateMipMapLevels
290 		{
291 			// enable bilinear mipmap filter
292 			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
293 			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
294 
295             StatesCache.BilinearFilter = true;
296             StatesCache.TrilinearFilter = false;
297             StatesCache.MipMapStatus = true;
298 		}
299 		else
300 #else
301 			HasMipMaps=false;
302 			os::Printer::log("Did not create OpenGL texture mip maps.", ELL_INFORMATION);
303 #endif
304 		{
305 			// enable bilinear filter without mipmaps
306 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
307 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
308 
309             StatesCache.BilinearFilter = true;
310             StatesCache.TrilinearFilter = false;
311             StatesCache.MipMapStatus = false;
312 		}
313 	}
314 
315 	// now get image data and upload to GPU
316 	void* source = image->lock();
317 	IImage* tmpImage=0;
318 
319 	if (convert)
320 	{
321 		tmpImage = new CImage(image->getColorFormat(), image->getDimension());
322 		void* dest = tmpImage->lock();
323 		convert(source, image->getDimension().getArea(), dest);
324 		image->unlock();
325 		source = dest;
326 	}
327 
328 	if (newTexture)
329 		glTexImage2D(GL_TEXTURE_2D, level, InternalFormat, image->getDimension().Width,
330 			image->getDimension().Height, 0, PixelFormat, PixelType, source);
331 	else
332 		glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, image->getDimension().Width,
333 			image->getDimension().Height, PixelFormat, PixelType, source);
334 
335 	if (convert)
336 	{
337 		tmpImage->unlock();
338 		tmpImage->drop();
339 	}
340 	else
341 		image->unlock();
342 
343 	if (AutomaticMipmapUpdate)
344 		glGenerateMipmap(GL_TEXTURE_2D);
345 
346 	if (Driver->testGLError())
347 		os::Printer::log("Could not glTexImage2D", ELL_ERROR);
348 }
349 
350 
351 //! lock function
lock(E_TEXTURE_LOCK_MODE mode,u32 mipmapLevel)352 void* COGLES2Texture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
353 {
354 	// store info about which image is locked
355 	IImage* image = (mipmapLevel==0)?Image:MipImage;
356 
357 	return image->lock();
358 }
359 
360 
361 //! unlock function
unlock()362 void COGLES2Texture::unlock()
363 {
364 	// test if miplevel or main texture was locked
365 	IImage* image = MipImage?MipImage:Image;
366 	if (!image)
367 		return;
368 	// unlock image to see changes
369 	image->unlock();
370 	// copy texture data to GPU
371 	if (!ReadOnlyLock)
372 		uploadTexture(false, 0, MipLevelStored);
373 	ReadOnlyLock = false;
374 	// cleanup local image
375 	if (MipImage)
376 	{
377 		MipImage->drop();
378 		MipImage=0;
379 	}
380 	else if (!KeepImage)
381 	{
382 		Image->drop();
383 		Image=0;
384 	}
385 	// update information
386 	if (Image)
387 		ColorFormat=Image->getColorFormat();
388 	else
389 		ColorFormat=ECF_A8R8G8B8;
390 }
391 
392 
393 //! Returns size of the original image.
getOriginalSize() const394 const core::dimension2d<u32>& COGLES2Texture::getOriginalSize() const
395 {
396 	return ImageSize;
397 }
398 
399 
400 //! Returns size of the texture.
getSize() const401 const core::dimension2d<u32>& COGLES2Texture::getSize() const
402 {
403 	return TextureSize;
404 }
405 
406 
407 //! returns driver type of texture, i.e. the driver, which created the texture
getDriverType() const408 E_DRIVER_TYPE COGLES2Texture::getDriverType() const
409 {
410 	return EDT_OGLES2;
411 }
412 
413 
414 //! returns color format of texture
getColorFormat() const415 ECOLOR_FORMAT COGLES2Texture::getColorFormat() const
416 {
417 	return ColorFormat;
418 }
419 
420 
421 //! returns pitch of texture (in bytes)
getPitch() const422 u32 COGLES2Texture::getPitch() const
423 {
424 	if (Image)
425 		return Image->getPitch();
426 	else
427 		return 0;
428 }
429 
430 
431 //! return open gl texture name
getOpenGLTextureName() const432 GLuint COGLES2Texture::getOpenGLTextureName() const
433 {
434 	return TextureName;
435 }
436 
437 
438 //! Returns whether this texture has mipmaps
hasMipMaps() const439 bool COGLES2Texture::hasMipMaps() const
440 {
441 	return HasMipMaps;
442 }
443 
444 
445 //! Regenerates the mip map levels of the texture. Useful after locking and
446 //! modifying the texture
regenerateMipMapLevels(void * mipmapData)447 void COGLES2Texture::regenerateMipMapLevels(void* mipmapData)
448 {
449 	if (AutomaticMipmapUpdate || !HasMipMaps || !Image)
450 		return;
451 	if ((Image->getDimension().Width==1) && (Image->getDimension().Height==1))
452 		return;
453 
454 	// Manually create mipmaps or use prepared version
455 	u32 width=Image->getDimension().Width;
456 	u32 height=Image->getDimension().Height;
457 	u32 i=0;
458 	u8* target = static_cast<u8*>(mipmapData);
459 	do
460 	{
461 		if (width>1)
462 			width>>=1;
463 		if (height>1)
464 			height>>=1;
465 		++i;
466 		if (!target)
467 			target = new u8[width*height*Image->getBytesPerPixel()];
468 		// create scaled version if no mipdata available
469 		if (!mipmapData)
470 			Image->copyToScaling(target, width, height, Image->getColorFormat());
471 		glTexImage2D(GL_TEXTURE_2D, i, InternalFormat, width, height,
472 				0, PixelFormat, PixelType, target);
473 		// get next prepared mipmap data if available
474 		if (mipmapData)
475 		{
476 			mipmapData = static_cast<u8*>(mipmapData)+width*height*Image->getBytesPerPixel();
477 			target = static_cast<u8*>(mipmapData);
478 		}
479 	}
480 	while (width!=1 || height!=1);
481 	// cleanup
482 	if (!mipmapData)
483 		delete [] target;
484 }
485 
486 
isRenderTarget() const487 bool COGLES2Texture::isRenderTarget() const
488 {
489 	return IsRenderTarget;
490 }
491 
492 
setIsRenderTarget(bool isTarget)493 void COGLES2Texture::setIsRenderTarget(bool isTarget)
494 {
495 	IsRenderTarget = isTarget;
496 }
497 
498 
isFrameBufferObject() const499 bool COGLES2Texture::isFrameBufferObject() const
500 {
501 	return false;
502 }
503 
504 
505 //! Bind Render Target Texture
bindRTT()506 void COGLES2Texture::bindRTT()
507 {
508 }
509 
510 
511 //! Unbind Render Target Texture
unbindRTT()512 void COGLES2Texture::unbindRTT()
513 {
514 }
515 
516 
517 //! Get an access to texture states cache.
getStatesCache() const518 COGLES2Texture::SStatesCache& COGLES2Texture::getStatesCache() const
519 {
520 	return StatesCache;
521 }
522 
523 
524 /* FBO Textures */
525 
526 // helper function for render to texture
527 static bool checkOGLES2FBOStatus(COGLES2Driver* Driver);
528 
529 //! RTT ColorFrameBuffer constructor
COGLES2FBOTexture(const core::dimension2d<u32> & size,const io::path & name,COGLES2Driver * driver,ECOLOR_FORMAT format)530 COGLES2FBOTexture::COGLES2FBOTexture(const core::dimension2d<u32>& size,
531 					const io::path& name, COGLES2Driver* driver,
532 					ECOLOR_FORMAT format)
533 	: COGLES2Texture(name, driver), DepthTexture(0), ColorFrameBuffer(0)
534 {
535 	#ifdef _DEBUG
536 	setDebugName("COGLES2Texture_FBO");
537 	#endif
538 
539 	ImageSize = size;
540 	TextureSize = size;
541 	HasMipMaps = false;
542 	IsRenderTarget = true;
543 	ColorFormat = getBestColorFormat(format);
544 
545 	switch (ColorFormat)
546 	{
547 	case ECF_A8R8G8B8:
548 		InternalFormat = GL_RGBA;
549 		PixelFormat = GL_RGBA;
550 		PixelType = GL_UNSIGNED_BYTE;
551 		break;
552 	case ECF_R8G8B8:
553 		InternalFormat = GL_RGB;
554 		PixelFormat = GL_RGB;
555 		PixelType = GL_UNSIGNED_BYTE;
556 		break;
557 		break;
558 	case ECF_A1R5G5B5:
559 		InternalFormat = GL_RGBA;
560 		PixelFormat = GL_RGBA;
561 		PixelType = GL_UNSIGNED_SHORT_5_5_5_1;
562 		break;
563 		break;
564 	case ECF_R5G6B5:
565 		InternalFormat = GL_RGB;
566 		PixelFormat = GL_RGB;
567 		PixelType = GL_UNSIGNED_SHORT_5_6_5;
568 		break;
569 	default:
570 		os::Printer::log( "color format not handled", ELL_WARNING );
571 		break;
572 	}
573 
574 	// generate frame buffer
575 	glGenFramebuffers(1, &ColorFrameBuffer);
576 	bindRTT();
577 
578 	// generate color texture
579 	glGenTextures(1, &TextureName);
580 
581     Driver->setActiveTexture(0, this);
582 	Driver->getBridgeCalls()->setTexture(0);
583 
584 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
585 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
586 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
587 
588 	StatesCache.BilinearFilter = true;
589     StatesCache.WrapU = ETC_CLAMP_TO_EDGE;
590     StatesCache.WrapV = ETC_CLAMP_TO_EDGE;
591 
592 	glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, ImageSize.Width, ImageSize.Height, 0, PixelFormat, PixelType, 0);
593 
594 #ifdef _DEBUG
595 	driver->testGLError();
596 #endif
597 
598 	// attach color texture to frame buffer
599 	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, TextureName, 0);
600 #ifdef _DEBUG
601 	checkOGLES2FBOStatus(Driver);
602 #endif
603 
604 	unbindRTT();
605 }
606 
607 
608 //! destructor
~COGLES2FBOTexture()609 COGLES2FBOTexture::~COGLES2FBOTexture()
610 {
611 	if (DepthTexture)
612 		if (DepthTexture->drop())
613 			Driver->removeDepthTexture(DepthTexture);
614 	if (ColorFrameBuffer)
615 		glDeleteFramebuffers(1, &ColorFrameBuffer);
616 }
617 
618 
isFrameBufferObject() const619 bool COGLES2FBOTexture::isFrameBufferObject() const
620 {
621 	return true;
622 }
623 
624 
625 //! Bind Render Target Texture
bindRTT()626 void COGLES2FBOTexture::bindRTT()
627 {
628 	if (ColorFrameBuffer != 0)
629 		glBindFramebuffer(GL_FRAMEBUFFER, ColorFrameBuffer);
630 }
631 
632 
633 //! Unbind Render Target Texture
unbindRTT()634 void COGLES2FBOTexture::unbindRTT()
635 {
636 	if (ColorFrameBuffer != 0)
637 		glBindFramebuffer(GL_FRAMEBUFFER, Driver->getDefaultFramebuffer());
638 }
639 
640 
641 /* FBO Depth Textures */
642 
643 //! RTT DepthBuffer constructor
COGLES2FBODepthTexture(const core::dimension2d<u32> & size,const io::path & name,COGLES2Driver * driver,bool useStencil)644 COGLES2FBODepthTexture::COGLES2FBODepthTexture(
645 		const core::dimension2d<u32>& size,
646 		const io::path& name,
647 		COGLES2Driver* driver,
648 		bool useStencil)
649 	: COGLES2Texture(name, driver), DepthRenderBuffer(0),
650 	StencilRenderBuffer(0), UseStencil(useStencil)
651 {
652 #ifdef _DEBUG
653 	setDebugName("COGLES2TextureFBO_Depth");
654 #endif
655 
656 	ImageSize = size;
657 	TextureSize = size;
658 	InternalFormat = GL_RGBA;
659 	PixelFormat = GL_RGBA;
660 	PixelType = GL_UNSIGNED_BYTE;
661 	HasMipMaps = false;
662 
663 	if (useStencil)
664 	{
665 		glGenRenderbuffers(1, &DepthRenderBuffer);
666 		glBindRenderbuffer(GL_RENDERBUFFER, DepthRenderBuffer);
667 #ifdef GL_OES_packed_depth_stencil
668 		if (Driver->queryOpenGLFeature(COGLES2ExtensionHandler::IRR_OES_packed_depth_stencil))
669 		{
670 			// generate packed depth stencil buffer
671 			glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, ImageSize.Width, ImageSize.Height);
672 			StencilRenderBuffer = DepthRenderBuffer; // stencil is packed with depth
673 		}
674 		else // generate separate stencil and depth textures
675 #endif
676 		{
677 			glRenderbufferStorage(GL_RENDERBUFFER, Driver->getZBufferBits(), ImageSize.Width, ImageSize.Height);
678 
679 			glGenRenderbuffers(1, &StencilRenderBuffer);
680 			glBindRenderbuffer(GL_RENDERBUFFER, StencilRenderBuffer);
681 			glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, ImageSize.Width, ImageSize.Height);
682 		}
683 	}
684 	else
685 	{
686 		// generate depth buffer
687 		glGenRenderbuffers(1, &DepthRenderBuffer);
688 		glBindRenderbuffer(GL_RENDERBUFFER, DepthRenderBuffer);
689 		glRenderbufferStorage(GL_RENDERBUFFER, Driver->getZBufferBits(), ImageSize.Width, ImageSize.Height);
690 	}
691 }
692 
693 
694 //! destructor
~COGLES2FBODepthTexture()695 COGLES2FBODepthTexture::~COGLES2FBODepthTexture()
696 {
697 	if (DepthRenderBuffer)
698 		glDeleteRenderbuffers(1, &DepthRenderBuffer);
699 
700 	if (StencilRenderBuffer && StencilRenderBuffer != DepthRenderBuffer)
701 		glDeleteRenderbuffers(1, &StencilRenderBuffer);
702 }
703 
704 
705 //combine depth texture and rtt
attach(ITexture * renderTex)706 bool COGLES2FBODepthTexture::attach(ITexture* renderTex)
707 {
708 	if (!renderTex)
709 		return false;
710 	COGLES2FBOTexture* rtt = static_cast<COGLES2FBOTexture*>(renderTex);
711 	rtt->bindRTT();
712 
713 	// attach stencil texture to stencil buffer
714 	if (UseStencil)
715 		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, StencilRenderBuffer);
716 
717 	// attach depth renderbuffer to depth buffer
718 	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, DepthRenderBuffer);
719 
720 	// check the status
721 	if (!checkOGLES2FBOStatus(Driver))
722 	{
723 		os::Printer::log("FBO incomplete");
724 		return false;
725 	}
726 	rtt->DepthTexture=this;
727 	rtt->DepthBufferTexture = DepthRenderBuffer;
728 	grab(); // grab the depth buffer, not the RTT
729 	rtt->unbindRTT();
730 	return true;
731 }
732 
733 
734 //! Bind Render Target Texture
bindRTT()735 void COGLES2FBODepthTexture::bindRTT()
736 {
737 }
738 
739 
740 //! Unbind Render Target Texture
unbindRTT()741 void COGLES2FBODepthTexture::unbindRTT()
742 {
743 }
744 
745 
checkOGLES2FBOStatus(COGLES2Driver * Driver)746 bool checkOGLES2FBOStatus(COGLES2Driver* Driver)
747 {
748 	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
749 
750 	switch (status)
751 	{
752 		case GL_FRAMEBUFFER_COMPLETE:
753 			return true;
754 
755 		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
756 			os::Printer::log("FBO has one or several incomplete image attachments", ELL_ERROR);
757 			break;
758 
759 		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
760 			os::Printer::log("FBO missing an image attachment", ELL_ERROR);
761 			break;
762 
763 		case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
764 			os::Printer::log("FBO has one or several image attachments with different dimensions", ELL_ERROR);
765 			break;
766 
767 		case GL_FRAMEBUFFER_UNSUPPORTED:
768 			os::Printer::log("FBO format unsupported", ELL_ERROR);
769 			break;
770 
771 		default:
772 			break;
773 	}
774 
775 	os::Printer::log("FBO error", ELL_ERROR);
776 
777 	return false;
778 }
779 
780 
781 } // end namespace video
782 } // end namespace irr
783 
784 #endif // _IRR_COMPILE_WITH_OGLES2_
785 
786