void RenderDevice::uploadTextureData( uint32 texObj, int slice, int mipLevel, const void *pixels ) { const RDITexture &tex = _textures.getRef( texObj ); TextureFormats::List format = tex.format; glActiveTexture( GL_TEXTURE15 ); glBindTexture( tex.type, tex.glObj ); int inputFormat = GL_BGRA, inputType = GL_UNSIGNED_BYTE; bool compressed = (format == TextureFormats::DXT1) || (format == TextureFormats::DXT3) || (format == TextureFormats::DXT5); switch( format ) { case TextureFormats::RGBA16F: inputFormat = GL_RGBA; inputType = GL_FLOAT; break; case TextureFormats::RGBA32F: inputFormat = GL_RGBA; inputType = GL_FLOAT; break; case TextureFormats::DEPTH: inputFormat = GL_DEPTH_COMPONENT; inputType = GL_FLOAT; }; // Calculate size of next mipmap using "floor" convention int width = std::max( tex.width >> mipLevel, 1 ), height = std::max( tex.height >> mipLevel, 1 ); if( tex.type == TextureTypes::Tex2D || tex.type == TextureTypes::TexCube ) { int target = (tex.type == TextureTypes::Tex2D) ? GL_TEXTURE_2D : (GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice); if( compressed ) glCompressedTexImage2D( target, mipLevel, tex.glFmt, width, height, 0, calcTextureSize( format, width, height, 1 ), pixels ); else glTexImage2D( target, mipLevel, tex.glFmt, width, height, 0, inputFormat, inputType, pixels ); } else if( tex.type == TextureTypes::Tex3D ) { int depth = std::max( tex.depth >> mipLevel, 1 ); if( compressed ) glCompressedTexImage3D( GL_TEXTURE_3D, mipLevel, tex.glFmt, width, height, depth, 0, calcTextureSize( format, width, height, depth ), pixels ); else glTexImage3D( GL_TEXTURE_3D, mipLevel, tex.glFmt, width, height, depth, 0, inputFormat, inputType, pixels ); }
bool utTextureLoadKTX( const char *data, int size, utTextureInfo* info ) { ASSERT_STATIC( sizeof( KTXHeader ) == 64 ); info->_surfaces = NULL; memcpy( &ktxHeader, data, 64 ); // Check header if( memcmp(ktxHeader.identifier, ktxIdentifier, 12) !=0 ) { Modules::log().writeError( "Invalid KTX header" ); return false; } // Store properties info->_width = ktxHeader.pixelWidth; info->_height = ktxHeader.pixelHeight; info->_depth = 1; info->_format = utTextureFormats::Unknown; info->_mipCount = ktxHeader.numberOfMipmapLevels; // Get texture type if( ktxHeader.numberOfFaces > 1 ) { if( ktxHeader.numberOfFaces != 6 ) { Modules::log().writeError( "Wrong number of cube texture faces (should be 6)" ); return false; } else { info->_type = utTextureTypes::TexCube; } } else if( ktxHeader.pixelDepth > 1 ) { info->_depth = ktxHeader.pixelDepth; info->_type = utTextureTypes::Tex3D; } else info->_type = utTextureTypes::Tex2D; // Texture arrays are not supported yet if( ktxHeader.numberOfArrayElements > 1 ) { Modules::log().writeWarning( "Texture Arrays not supported. using first array element only" ); } // Get pixel format switch( ktxHeader.glInternalFormat ) { case GL_RGB8: info->_format = utTextureFormats::RGB8; break; case GL_RGBA8: info->_format = utTextureFormats::BGRA8; break; case GL_BGRA: info->_format = utTextureFormats::BGRA8; break; case GL_RGBA16F: info->_format = utTextureFormats::RGBA16F; break; case GL_RGBA32F: info->_format = utTextureFormats::RGBA32F; break; case GL_COMPRESSED_RGBA_S3TC_DXT1: info->_format = utTextureFormats::DXT1; break; case GL_COMPRESSED_RGBA_S3TC_DXT3: info->_format = utTextureFormats::DXT3; break; case GL_COMPRESSED_RGBA_S3TC_DXT5: info->_format = utTextureFormats::DXT5; break; case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: info->_format = utTextureFormats::PVRTCI_2BPP; break; case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: info->_format = utTextureFormats::PVRTCI_A2BPP; break; case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: info->_format = utTextureFormats::PVRTCI_4BPP; break; case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: info->_format = utTextureFormats::PVRTCI_A4BPP; break; case GL_ETC1_RGB8_OES: info->_format = utTextureFormats::ETC1; break; } if( info->_format == utTextureFormats::Unknown ) { Modules::log().writeError( "Unsupported KTX pixel format" ); return false; } info->_sliceCount = info->_type == utTextureTypes::TexCube ? 6 : 1; unsigned char *pixels = (unsigned char *)(data + 128); uint32 surfaceIndex = 0; info->_surfaceCount = info->_sliceCount * info->_mipCount; info->_surfaces = new utTextureSurfaceInfo[info->_surfaceCount]; int width = info->_width, height = info->_height, depth = info->_depth; for( uint32 i = 0; i < info->_mipCount; ++i ) { size_t mipSize = calcTextureSize( info->_format, width, height, depth ); if( pixels + mipSize > (unsigned char *)data + size ) { Modules::log().writeError( "Corrupt KTX" ); return false; } for( uint32 j = 0; j < ktxHeader.numberOfArrayElements; ++j ) { for( uint32 k = 0; k < ktxHeader.numberOfFaces; ++k ) { if ( j == 0) { // using only first element of array now utTextureSurfaceInfo& surface = info->_surfaces[surfaceIndex++]; surface._mip = i; surface._slice = k; surface._data = pixels; surface._size = (uint32)mipSize; } pixels += mipSize; } } if( width > 1 ) width >>= 1; if( height > 1 ) height >>= 1; if( depth > 1 ) depth >>= 1; } ASSERT( pixels == (unsigned char *)data + size ); return true; }
bool utTextureLoadPVR( const char* data, uint32 size, utTextureInfo* info) { // Load pvr ASSERT_STATIC( sizeof( PVRHeader ) == 52 ); info->_surfaces = NULL; memcpy( &pvrHeader, data, 52 ); // Store properties info->_width = pvrHeader.dwWidth; info->_height = pvrHeader.dwHeight; info->_depth = 1; info->_format = utTextureFormats::Unknown; info->_mipCount = pvrHeader.dwMipMapCount; // Get texture type if( pvrHeader.dwNumFaces == 6 ) { info->_type = utTextureTypes::TexCube; } else { info->_type = utTextureTypes::Tex2D; } // Get pixel format if (pvrHeader.dwPixelFormatHigh == 0 ) { switch(pvrHeader.dwPixelFormatLow) { case ePVRTPF_PVRTCI_2bpp_RGBA: info->_format = utTextureFormats::PVRTCI_A2BPP; break; case ePVRTPF_PVRTCI_4bpp_RGBA: info->_format = utTextureFormats::PVRTCI_A4BPP; break; case ePVRTPF_DXT1: info->_format = utTextureFormats::DXT1; break; case ePVRTPF_DXT3: info->_format = utTextureFormats::DXT3; break; case ePVRTPF_DXT5: info->_format = utTextureFormats::DXT5; break; case ePVRTPF_PVRTCI_2bpp_RGB: info->_format = utTextureFormats::PVRTCI_2BPP; break; case ePVRTPF_PVRTCI_4bpp_RGB: info->_format = utTextureFormats::PVRTCI_4BPP; break; case ePVRTPF_ETC1: info->_format = utTextureFormats::ETC1; break; } } if( info->_format == utTextureFormats::Unknown ) { Modules().log().writeError( "Unsupported PVR pixel format" ); return false; } // Upload texture subresources info->_sliceCount = info->_type == utTextureTypes::TexCube ? 6 : 1; unsigned char *pixels = (unsigned char *)(data + 52); uint32 surfaceIndex = 0; info->_surfaceCount = info->_sliceCount * info->_mipCount; info->_surfaces = new utTextureSurfaceInfo[info->_surfaceCount]; for( uint32 i = 0; i < info->_sliceCount; ++i ) { int width = pvrHeader.dwWidth, height = pvrHeader.dwHeight; for( uint32 j = 0; j < info->_mipCount; ++j ) { size_t mipSize = calcTextureSize( info->_format, width, height, 1 ); if( pixels + mipSize > (unsigned char *)data + size ) { Modules::log().writeError( "Corrupt PVR" ); return false; } utTextureSurfaceInfo& surface = info->_surfaces[surfaceIndex++]; surface._mip = j; surface._slice = i; surface._data = pixels; surface._size = (uint32)mipSize; pixels += mipSize; if( width > 1 ) width >>= 1; if( height > 1 ) height >>= 1; } } ASSERT( pixels == (unsigned char *)data + size); return true; }
uint32 RenderDevice::createTexture( TextureTypes::List type, int width, int height, int depth, TextureFormats::List format, bool hasMips, bool genMips, bool compress, bool sRGB ) { if( !_caps.texNPOT ) { // Check if texture is NPOT if( (width & (width-1)) != 0 || (height & (height-1)) != 0 ) Modules::log().writeWarning( "Texture has non-power-of-two dimensions although NPOT is not supported by GPU" ); } RDITexture tex; tex.type = type; tex.format = format; tex.width = width; tex.height = height; tex.depth = (type == TextureTypes::Tex3D ? depth : 1); tex.sRGB = sRGB && Modules::config().sRGBLinearization; tex.genMips = genMips; tex.hasMips = hasMips; switch( format ) { case TextureFormats::BGRA8: tex.glFmt = tex.sRGB ? GL_SRGB8_ALPHA8_EXT : GL_RGBA8; break; case TextureFormats::DXT1: tex.glFmt = tex.sRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; case TextureFormats::DXT3: tex.glFmt = tex.sRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT : GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; case TextureFormats::DXT5: tex.glFmt = tex.sRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; case TextureFormats::RGBA16F: tex.glFmt = GL_RGBA16F_ARB; break; case TextureFormats::RGBA32F: tex.glFmt = GL_RGBA32F_ARB; break; case TextureFormats::DEPTH: tex.glFmt = _depthFormat; break; default: ASSERT( 0 ); break; }; glGenTextures( 1, &tex.glObj ); glActiveTexture( GL_TEXTURE15 ); glBindTexture( tex.type, tex.glObj ); float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor ); tex.samplerState = 0; applySamplerState( tex ); glBindTexture( tex.type, 0 ); if( _texSlots[15].texObj ) glBindTexture( _textures.getRef( _texSlots[15].texObj ).type, _textures.getRef( _texSlots[15].texObj ).glObj ); // Calculate memory requirements tex.memSize = calcTextureSize( format, width, height, depth ); if( hasMips || genMips ) tex.memSize += ftoi_r( tex.memSize * 1.0f / 3.0f ); if( type == TextureTypes::TexCube ) tex.memSize *= 6; _textureMem += tex.memSize; return _textures.add( tex ); }
void RenderDevice::uploadTextureData( uint32 texObj, int slice, int mipLevel, const void *pixels ) { const RDITexture &tex = _textures.getRef( texObj ); TextureFormats::List format = tex.format; glActiveTexture( GL_TEXTURE0 ); glBindTexture( tex.type, tex.glObj ); #ifdef PLATFORM_ES2 int inputFormat = GL_RGBA, inputType = GL_UNSIGNED_BYTE; #else int inputFormat = GL_BGRA, inputType = GL_UNSIGNED_BYTE; #endif bool compressed = (format == TextureFormats::DXT1) || (format == TextureFormats::DXT3) || (format == TextureFormats::DXT5) || (format == TextureFormats::PVRTC2) || (format == TextureFormats::PVRTCA2) || (format == TextureFormats::PVRTC4) || (format == TextureFormats::PVRTCA4); switch( format ) { case TextureFormats::RGBA16F: inputFormat = GL_RGBA; #ifdef PLATFORM_ES2 // GL_HALF_FLOAT_OES seems not to work on 3GS, 4G and iPad1 // http://stackoverflow.com/questions/3850569/render-to-floating-point-texture-under-ios inputType = glExt::OES_texture_half_float ? GL_HALF_FLOAT_OES : GL_RGBA ; #else inputType = GL_FLOAT; #endif break; case TextureFormats::RGBA32F: inputFormat = GL_RGBA; inputType = GL_FLOAT; break; case TextureFormats::DEPTH: inputFormat = GL_DEPTH_COMPONENT; #ifdef PLATFORM_ES2 inputType = GL_UNSIGNED_SHORT; #else inputType = GL_FLOAT; #endif default: break; }; // Calculate size of next mipmap using "floor" convention int width = std::max( tex.width >> mipLevel, 1 ), height = std::max( tex.height >> mipLevel, 1 ); if ( (tex.type == TextureTypes::Tex2D && (width>_maxTextureSize || height>_maxTextureSize)) || (tex.type == TextureTypes::TexCube && (width>_maxCubeTextureSize || height>_maxCubeTextureSize))) goto UPLOADE_TEXUTURE_EXIT;//return; if( tex.type == TextureTypes::Tex2D || tex.type == TextureTypes::TexCube ) { int target = (tex.type == TextureTypes::Tex2D) ? GL_TEXTURE_2D : (GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice); if( compressed ) glCompressedTexImage2D( target, mipLevel, tex.glFmt, width, height, 0, calcTextureSize( format, width, height, 1 ), pixels ); else glTexImage2D( target, mipLevel, tex.glFmt, width, height, 0, inputFormat, inputType, pixels ); } else if( tex.type == TextureTypes::Tex3D ) { #if !defined(PLATFORM_ES2) int depth = std::max( tex.depth >> mipLevel, 1 ); if( compressed ) glCompressedTexImage3D( GL_TEXTURE_3D, mipLevel, tex.glFmt, width, height, depth, 0, calcTextureSize( format, width, height, depth ), pixels ); else glTexImage3D( GL_TEXTURE_3D, mipLevel, tex.glFmt, width, height, depth, 0, inputFormat, inputType, pixels ); #endif }