|
|
@@ -56,7 +56,7 @@ Texture::~Texture()
|
|
|
{
|
|
|
if (_handle)
|
|
|
{
|
|
|
- glDeleteTextures(1, &_handle);
|
|
|
+ GL_ASSERT( glDeleteTextures(1, &_handle) );
|
|
|
_handle = 0;
|
|
|
}
|
|
|
|
|
|
@@ -73,10 +73,13 @@ Texture::~Texture()
|
|
|
|
|
|
Texture* Texture::create(const char* path, bool generateMipmaps)
|
|
|
{
|
|
|
+ GP_ASSERT(path);
|
|
|
+
|
|
|
// Search texture cache first.
|
|
|
for (unsigned int i = 0, count = __textureCache.size(); i < count; ++i)
|
|
|
{
|
|
|
Texture* t = __textureCache[i];
|
|
|
+ GP_ASSERT(t);
|
|
|
if (t->_path == path)
|
|
|
{
|
|
|
// If 'generateMipmaps' is true, call Texture::generateMipamps() to force the
|
|
|
@@ -111,7 +114,7 @@ Texture* Texture::create(const char* path, bool generateMipmaps)
|
|
|
}
|
|
|
else if (tolower(ext[1]) == 'p' && tolower(ext[2]) == 'v' && tolower(ext[3]) == 'r')
|
|
|
{
|
|
|
- // PowerVR Compressed Texture RGBA
|
|
|
+ // PowerVR Compressed Texture RGBA.
|
|
|
texture = createCompressedPVRTC(path);
|
|
|
}
|
|
|
else if (tolower(ext[1]) == 'd' && tolower(ext[2]) == 'd' && tolower(ext[3]) == 's')
|
|
|
@@ -134,21 +137,24 @@ Texture* Texture::create(const char* path, bool generateMipmaps)
|
|
|
return texture;
|
|
|
}
|
|
|
|
|
|
- GP_ERROR("Failed to load texture: %s", path);
|
|
|
+ GP_ERROR("Failed to load texture from file '%s'.", path);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
Texture* Texture::create(Image* image, bool generateMipmaps)
|
|
|
{
|
|
|
+ GP_ASSERT(image);
|
|
|
+
|
|
|
switch (image->getFormat())
|
|
|
{
|
|
|
case Image::RGB:
|
|
|
return create(Texture::RGB, image->getWidth(), image->getHeight(), image->getData(), generateMipmaps);
|
|
|
case Image::RGBA:
|
|
|
return create(Texture::RGBA, image->getWidth(), image->getHeight(), image->getData(), generateMipmaps);
|
|
|
+ default:
|
|
|
+ GP_ERROR("Unsupported image format (%d).", image->getFormat());
|
|
|
+ return NULL;
|
|
|
}
|
|
|
-
|
|
|
- return NULL;
|
|
|
}
|
|
|
|
|
|
Texture* Texture::create(Format format, unsigned int width, unsigned int height, unsigned char* data, bool generateMipmaps)
|
|
|
@@ -168,7 +174,7 @@ Texture* Texture::create(Format format, unsigned int width, unsigned int height,
|
|
|
GL_ASSERT( glTexImage2D(GL_TEXTURE_2D, 0, (GLenum)format, width, height, 0, (GLenum)format, GL_UNSIGNED_BYTE, data) );
|
|
|
}
|
|
|
|
|
|
- // Set initial minification filter based on whether or not mipmaping was enabled
|
|
|
+ // Set initial minification filter based on whether or not mipmaping was enabled.
|
|
|
GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, generateMipmaps ? GL_NEAREST_MIPMAP_LINEAR : GL_LINEAR) );
|
|
|
|
|
|
Texture* texture = new Texture();
|
|
|
@@ -212,20 +218,38 @@ Texture* Texture::createCompressedPVRTC(const char* path)
|
|
|
FILE* file = FileSystem::openFile(path, "rb");
|
|
|
if (file == NULL)
|
|
|
{
|
|
|
- GP_ERROR("Failed to load file: %s", path);
|
|
|
+ GP_ERROR("Failed to load file '%s'.", path);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
- // Read first 4 bytes to determine PVRTC format
|
|
|
+ // Read first 4 bytes to determine PVRTC format.
|
|
|
unsigned int read;
|
|
|
unsigned int version;
|
|
|
read = fread(&version, sizeof(unsigned int), 1, file);
|
|
|
- assert(read == 1);
|
|
|
+ if (read != 1)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to read PVR version.");
|
|
|
+ if (fclose(file) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close PVR file '%s'.", path);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
- // Rewind to start of header
|
|
|
- fseek(file, 0, SEEK_SET);
|
|
|
+ // Rewind to start of header.
|
|
|
+ if (fseek(file, 0, SEEK_SET) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to seek backwards to beginning of file after reading PVR version.");
|
|
|
+ if (fclose(file) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close PVR file '%s'.", path);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
- // Read texture data
|
|
|
+ // Read texture data.
|
|
|
GLsizei width, height;
|
|
|
GLenum format;
|
|
|
GLubyte* data = NULL;
|
|
|
@@ -233,60 +257,75 @@ Texture* Texture::createCompressedPVRTC(const char* path)
|
|
|
|
|
|
if (version == 0x03525650)
|
|
|
{
|
|
|
- // Modern PVR file format.
|
|
|
- data = readCompressedPVRTC(path, file, &width, &height, &format, &mipMapCount);
|
|
|
+ // Modern PVR file format.
|
|
|
+ data = readCompressedPVRTC(path, file, &width, &height, &format, &mipMapCount);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- // Legacy PVR file format.
|
|
|
- data = readCompressedPVRTCLegacy(path, file, &width, &height, &format, &mipMapCount);
|
|
|
+ // Legacy PVR file format.
|
|
|
+ data = readCompressedPVRTCLegacy(path, file, &width, &height, &format, &mipMapCount);
|
|
|
}
|
|
|
-
|
|
|
- fclose(file);
|
|
|
-
|
|
|
if (data == NULL)
|
|
|
{
|
|
|
- GP_ERROR("Failed to read PVR file: %s", path);
|
|
|
- return NULL;
|
|
|
+ GP_ERROR("Failed to read texture data from PVR file '%s'.", path);
|
|
|
+ if (fclose(file) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close PVR file '%s'.", path);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fclose(file) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close PVR file '%s'.", path);
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
int bpp = (format == GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG || format == GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG) ? 2 : 4;
|
|
|
|
|
|
// Generate our texture.
|
|
|
- GLuint textureId;
|
|
|
- GL_ASSERT( glGenTextures(1, &textureId) );
|
|
|
- GL_ASSERT( glBindTexture(GL_TEXTURE_2D, textureId) );
|
|
|
- GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipMapCount > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) );
|
|
|
-
|
|
|
- Texture* texture = new Texture();
|
|
|
- texture->_handle = textureId;
|
|
|
- texture->_width = width;
|
|
|
- texture->_height = height;
|
|
|
- texture->_mipmapped = mipMapCount > 1;
|
|
|
- texture->_compressed = true;
|
|
|
-
|
|
|
- // Load the data for each level
|
|
|
- GLubyte* ptr = data;
|
|
|
- for (unsigned int level = 0; level < mipMapCount; ++level)
|
|
|
- {
|
|
|
- unsigned int dataSize = computePVRTCDataSize(width, height, bpp);
|
|
|
-
|
|
|
- // Upload data to GL
|
|
|
- GL_ASSERT( glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, dataSize, ptr) );
|
|
|
-
|
|
|
- width = std::max(width >> 1, 1);
|
|
|
- height = std::max(height >> 1, 1);
|
|
|
- ptr += dataSize;
|
|
|
- }
|
|
|
-
|
|
|
- // Free data
|
|
|
- SAFE_DELETE_ARRAY(data);
|
|
|
+ GLuint textureId;
|
|
|
+ GL_ASSERT( glGenTextures(1, &textureId) );
|
|
|
+ GL_ASSERT( glBindTexture(GL_TEXTURE_2D, textureId) );
|
|
|
+ GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipMapCount > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) );
|
|
|
+
|
|
|
+ Texture* texture = new Texture();
|
|
|
+ texture->_handle = textureId;
|
|
|
+ texture->_width = width;
|
|
|
+ texture->_height = height;
|
|
|
+ texture->_mipmapped = mipMapCount > 1;
|
|
|
+ texture->_compressed = true;
|
|
|
+
|
|
|
+ // Load the data for each level.
|
|
|
+ GLubyte* ptr = data;
|
|
|
+ for (unsigned int level = 0; level < mipMapCount; ++level)
|
|
|
+ {
|
|
|
+ unsigned int dataSize = computePVRTCDataSize(width, height, bpp);
|
|
|
+
|
|
|
+ // Upload data to GL.
|
|
|
+ GL_ASSERT( glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, dataSize, ptr) );
|
|
|
+
|
|
|
+ width = std::max(width >> 1, 1);
|
|
|
+ height = std::max(height >> 1, 1);
|
|
|
+ ptr += dataSize;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Free data.
|
|
|
+ SAFE_DELETE_ARRAY(data);
|
|
|
|
|
|
return texture;
|
|
|
}
|
|
|
|
|
|
GLubyte* Texture::readCompressedPVRTC(const char* path, FILE* file, GLsizei* width, GLsizei* height, GLenum* format, unsigned int* mipMapCount)
|
|
|
{
|
|
|
+ GP_ASSERT(file);
|
|
|
+ GP_ASSERT(path);
|
|
|
+ GP_ASSERT(width);
|
|
|
+ GP_ASSERT(height);
|
|
|
+ GP_ASSERT(format);
|
|
|
+ GP_ASSERT(mipMapCount);
|
|
|
+
|
|
|
struct pvrtc_file_header
|
|
|
{
|
|
|
unsigned int version;
|
|
|
@@ -305,15 +344,19 @@ GLubyte* Texture::readCompressedPVRTC(const char* path, FILE* file, GLsizei* wid
|
|
|
|
|
|
unsigned int read;
|
|
|
|
|
|
- // Read header data
|
|
|
+ // Read header data.
|
|
|
pvrtc_file_header header;
|
|
|
read = fread(&header, sizeof(pvrtc_file_header), 1, file);
|
|
|
- assert(read == 1);
|
|
|
+ if (read != 1)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to read PVR header data for file '%s'.", path);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
if (header.pixelFormat[1] != 0)
|
|
|
{
|
|
|
- // Unsupported pixel format
|
|
|
- GP_ERROR("Unsupported pixel format in PVR file (MSB == %d != 0): %s", header.pixelFormat[1], path);
|
|
|
+ // Unsupported pixel format.
|
|
|
+ GP_ERROR("Unsupported pixel format in PVR file '%s'. (MSB == %d != 0)", path, header.pixelFormat[1]);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
@@ -337,8 +380,8 @@ GLubyte* Texture::readCompressedPVRTC(const char* path, FILE* file, GLsizei* wid
|
|
|
bpp = 4;
|
|
|
break;
|
|
|
default:
|
|
|
- // Unsupported format
|
|
|
- GP_ERROR("Unsupported pixel format value (%d) in PVR file: %s", header.pixelFormat[0], path);
|
|
|
+ // Unsupported format.
|
|
|
+ GP_ERROR("Unsupported pixel format value (%d) in PVR file '%s'.", header.pixelFormat[0], path);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
@@ -346,8 +389,12 @@ GLubyte* Texture::readCompressedPVRTC(const char* path, FILE* file, GLsizei* wid
|
|
|
*height = (GLsizei)header.height;
|
|
|
*mipMapCount = header.mipMapCount;
|
|
|
|
|
|
- // Skip meta-data
|
|
|
- assert( fseek(file, header.metaDataSize, SEEK_CUR) == 0 );
|
|
|
+ // Skip meta-data.
|
|
|
+ if (fseek(file, header.metaDataSize, SEEK_CUR) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to seek past header meta data in PVR file '%s'.", path);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
// Compute total size of data to be read.
|
|
|
int w = *width;
|
|
|
@@ -356,14 +403,18 @@ GLubyte* Texture::readCompressedPVRTC(const char* path, FILE* file, GLsizei* wid
|
|
|
for (unsigned int level = 0; level < header.mipMapCount; ++level)
|
|
|
{
|
|
|
dataSize += computePVRTCDataSize(w, h, bpp);
|
|
|
- w = std::max(w>>1, 1);
|
|
|
- h = std::max(h>>1, 1);
|
|
|
+ w = std::max(w>>1, 1);
|
|
|
+ h = std::max(h>>1, 1);
|
|
|
}
|
|
|
|
|
|
- // Read data
|
|
|
+ // Read data.
|
|
|
GLubyte* data = new GLubyte[dataSize];
|
|
|
read = fread(data, 1, dataSize, file);
|
|
|
- assert(read == dataSize);
|
|
|
+ if (read != dataSize)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to read texture data from PVR file '%s'.", path);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
return data;
|
|
|
}
|
|
|
@@ -389,28 +440,35 @@ GLubyte* Texture::readCompressedPVRTCLegacy(const char* path, FILE* file, GLsize
|
|
|
unsigned int surfaceCount; // number of surfaces present in the pvrtc
|
|
|
};
|
|
|
|
|
|
- // Read the file header
|
|
|
+ // Read the file header.
|
|
|
unsigned int size = sizeof(pvrtc_file_header_legacy);
|
|
|
pvrtc_file_header_legacy header;
|
|
|
unsigned int read = (int)fread(&header, 1, size, file);
|
|
|
- GP_ASSERT(read == size);
|
|
|
if (read != size)
|
|
|
{
|
|
|
- GP_ERROR("Read file header error for pvrtc file: %s (%d < %d)", path, (int)read, (int)size);
|
|
|
+ GP_ERROR("Failed to read file header for pvrtc file '%s'.", path);
|
|
|
+ if (fclose(file) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
- // Proper file header identifier
|
|
|
+ // Proper file header identifier.
|
|
|
if (PVRTCIdentifier[0] != (char)((header.pvrtcTag >> 0) & 0xff) ||
|
|
|
PVRTCIdentifier[1] != (char)((header.pvrtcTag >> 8) & 0xff) ||
|
|
|
PVRTCIdentifier[2] != (char)((header.pvrtcTag >> 16) & 0xff) ||
|
|
|
PVRTCIdentifier[3] != (char)((header.pvrtcTag >> 24) & 0xff))
|
|
|
{
|
|
|
- GP_ERROR("Invalid PVRTC compressed texture file: %s", path);
|
|
|
+ GP_ERROR("Failed to load pvrtc file '%s': invalid header.", path);
|
|
|
+ if (fclose(file) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
- // Format flags for GLenum format
|
|
|
+ // Format flags for GLenum format.
|
|
|
if (header.bpp == 4)
|
|
|
{
|
|
|
*format = header.alphaBitMask ? GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
|
|
|
@@ -421,7 +479,11 @@ GLubyte* Texture::readCompressedPVRTCLegacy(const char* path, FILE* file, GLsize
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- GP_ERROR("Invalid PVRTC compressed texture format flags for file: %s", path);
|
|
|
+ GP_ERROR("Failed to load pvrtc file '%s': invalid pvrtc compressed texture format flags.", path);
|
|
|
+ if (fclose(file) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
@@ -431,10 +493,13 @@ GLubyte* Texture::readCompressedPVRTCLegacy(const char* path, FILE* file, GLsize
|
|
|
|
|
|
GLubyte* data = new GLubyte[header.dataSize];
|
|
|
read = (int)fread(data, 1, header.dataSize, file);
|
|
|
- GP_ASSERT(read == header.dataSize);
|
|
|
if (read != header.dataSize)
|
|
|
{
|
|
|
- GP_ERROR("Read file data error for pvrtc file: %s (%d < %d)", path, (int)read, (int)header.dataSize);
|
|
|
+ GP_ERROR("Failed to load texture data for pvrtc file '%s'.", path);
|
|
|
+ if (fclose(file) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
SAFE_DELETE_ARRAY(data);
|
|
|
return NULL;
|
|
|
}
|
|
|
@@ -444,7 +509,9 @@ GLubyte* Texture::readCompressedPVRTCLegacy(const char* path, FILE* file, GLsize
|
|
|
|
|
|
Texture* Texture::createCompressedDDS(const char* path)
|
|
|
{
|
|
|
- // DDS file structures
|
|
|
+ GP_ASSERT(path);
|
|
|
+
|
|
|
+ // DDS file structures.
|
|
|
struct dds_pixel_format
|
|
|
{
|
|
|
unsigned int dwSize;
|
|
|
@@ -485,28 +552,45 @@ Texture* Texture::createCompressedDDS(const char* path)
|
|
|
|
|
|
Texture* texture = NULL;
|
|
|
|
|
|
- // Read DDS file
|
|
|
+ // Read DDS file.
|
|
|
FILE* fp = FileSystem::openFile(path, "rb");
|
|
|
if (fp == NULL)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to open file '%s'.", path);
|
|
|
return NULL;
|
|
|
+ }
|
|
|
|
|
|
- // Validate DDS magic number
|
|
|
+ // Validate DDS magic number.
|
|
|
char code[4];
|
|
|
if (fread(code, 1, 4, fp) != 4 || strncmp(code, "DDS ", 4) != 0)
|
|
|
- return NULL; // not a valid dds file
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to read DDS file '%s': invalid DDS magic number.", path);
|
|
|
+ if (fclose(fp) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
- // Read DDS header
|
|
|
+ // Read DDS header.
|
|
|
dds_header header;
|
|
|
if (fread(&header, sizeof(dds_header), 1, fp) != 1)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to read header for DDS file '%s'.", path);
|
|
|
+ if (fclose(fp) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
return NULL;
|
|
|
+ }
|
|
|
|
|
|
if ((header.dwFlags & 0x20000/*DDSD_MIPMAPCOUNT*/) == 0)
|
|
|
{
|
|
|
- // Mipmap count not specified (non-mipmapped texture)
|
|
|
+ // Mipmap count not specified (non-mipmapped texture).
|
|
|
header.dwMipMapCount = 1;
|
|
|
}
|
|
|
|
|
|
- // Allocate mip level structures
|
|
|
+ // Allocate mip level structures.
|
|
|
dds_mip_level* mipLevels = new dds_mip_level[header.dwMipMapCount];
|
|
|
memset(mipLevels, 0, sizeof(dds_mip_level) * header.dwMipMapCount);
|
|
|
|
|
|
@@ -520,7 +604,7 @@ Texture* Texture::createCompressedDDS(const char* path)
|
|
|
{
|
|
|
compressed = true;
|
|
|
|
|
|
- // Compressed
|
|
|
+ // Compressed.
|
|
|
switch (header.ddspf.dwFourCC)
|
|
|
{
|
|
|
case ('D'|('X'<<8)|('T'<<16)|('1'<<24)):
|
|
|
@@ -548,7 +632,11 @@ Texture* Texture::createCompressedDDS(const char* path)
|
|
|
bytesPerBlock = 16;
|
|
|
break;
|
|
|
default:
|
|
|
- // Unsupported
|
|
|
+ GP_ERROR("Unsupported compressed texture format (%d) for DDS file '%s'.", header.ddspf.dwFourCC, path);
|
|
|
+ if (fclose(fp) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
@@ -562,7 +650,17 @@ Texture* Texture::createCompressedDDS(const char* path)
|
|
|
if (fread(mipLevels[i].data, 1, mipLevels[i].size, fp) != (unsigned int)mipLevels[i].size)
|
|
|
{
|
|
|
GP_ERROR("Failed to load dds compressed texture bytes for texture: %s", path);
|
|
|
- goto cleanup;
|
|
|
+
|
|
|
+ // Cleanup mip data.
|
|
|
+ for (unsigned int i = 0; i < header.dwMipMapCount; ++i)
|
|
|
+ SAFE_DELETE_ARRAY(mipLevels[i].data);
|
|
|
+ SAFE_DELETE_ARRAY(mipLevels);
|
|
|
+
|
|
|
+ if (fclose(fp) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
+ return texture;
|
|
|
}
|
|
|
|
|
|
width = std::max(1, width >> 1);
|
|
|
@@ -573,27 +671,48 @@ Texture* Texture::createCompressedDDS(const char* path)
|
|
|
{
|
|
|
// RGB (uncompressed)
|
|
|
// Note: Use GL_BGR as internal format to flip bytes.
|
|
|
- return NULL; // unsupported
|
|
|
+ GP_ERROR("Failed to create texture from DDS file '%s': uncompressed RGB format is not supported.", path);
|
|
|
+ if (fclose(fp) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
}
|
|
|
else if (header.ddspf.dwFlags == 0x41/*DDPF_RGB|DDPF_ALPHAPIXELS*/)
|
|
|
{
|
|
|
// RGBA (uncompressed)
|
|
|
// Note: Use GL_BGRA as internal format to flip bytes.
|
|
|
- return NULL; // unsupported
|
|
|
+ GP_ERROR("Failed to create texture from DDS file '%s': uncompressed RGBA format is not supported.", path);
|
|
|
+ if (fclose(fp) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- // Unsupported
|
|
|
+ // Unsupported.
|
|
|
+ GP_ERROR("Failed to create texture from DDS file '%s': unsupported flags (%d).", path, header.ddspf.dwFlags);
|
|
|
+ if (fclose(fp) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
return NULL;
|
|
|
}
|
|
|
+
|
|
|
+ // Close file.
|
|
|
+ if (fclose(fp) != 0)
|
|
|
+ {
|
|
|
+ GP_ERROR("Failed to close file '%s'.", path);
|
|
|
+ }
|
|
|
|
|
|
- // Generate GL texture
|
|
|
+ // Generate GL texture.
|
|
|
GLuint textureId;
|
|
|
GL_ASSERT( glGenTextures(1, &textureId) );
|
|
|
GL_ASSERT( glBindTexture(GL_TEXTURE_2D, textureId) );
|
|
|
GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, header.dwMipMapCount > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) );
|
|
|
|
|
|
- // Create gameplay texture
|
|
|
+ // Create gameplay texture.
|
|
|
texture = new Texture();
|
|
|
texture->_handle = textureId;
|
|
|
texture->_width = header.dwWidth;
|
|
|
@@ -601,7 +720,7 @@ Texture* Texture::createCompressedDDS(const char* path)
|
|
|
texture->_compressed = compressed;
|
|
|
texture->_mipmapped = header.dwMipMapCount > 1;
|
|
|
|
|
|
- // Load texture data
|
|
|
+ // Load texture data.
|
|
|
for (unsigned int i = 0; i < header.dwMipMapCount; ++i)
|
|
|
{
|
|
|
if (compressed)
|
|
|
@@ -613,14 +732,7 @@ Texture* Texture::createCompressedDDS(const char* path)
|
|
|
GL_ASSERT( glTexImage2D(GL_TEXTURE_2D, i, internalFormat, mipLevels[i].width, mipLevels[i].height, 0, format, GL_UNSIGNED_INT, mipLevels[i].data) );
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-cleanup:
|
|
|
-
|
|
|
- // Cleanup mip data
|
|
|
- for (unsigned int i = 0; i < header.dwMipMapCount; ++i)
|
|
|
- SAFE_DELETE_ARRAY(mipLevels[i].data);
|
|
|
- SAFE_DELETE_ARRAY(mipLevels);
|
|
|
-
|
|
|
+
|
|
|
return texture;
|
|
|
}
|
|
|
|
|
|
@@ -686,6 +798,7 @@ bool Texture::isCompressed() const
|
|
|
Texture::Sampler::Sampler(Texture* texture)
|
|
|
: _texture(texture), _wrapS(Texture::REPEAT), _wrapT(Texture::REPEAT), _magFilter(Texture::LINEAR)
|
|
|
{
|
|
|
+ GP_ASSERT(texture);
|
|
|
_minFilter = texture->isMipmapped() ? Texture::NEAREST_MIPMAP_LINEAR : Texture::LINEAR;
|
|
|
}
|
|
|
|
|
|
@@ -696,8 +809,7 @@ Texture::Sampler::~Sampler()
|
|
|
|
|
|
Texture::Sampler* Texture::Sampler::create(Texture* texture)
|
|
|
{
|
|
|
- GP_ASSERT(texture != NULL);
|
|
|
-
|
|
|
+ GP_ASSERT(texture);
|
|
|
texture->addRef();
|
|
|
return new Sampler(texture);
|
|
|
}
|
|
|
@@ -727,6 +839,8 @@ Texture* Texture::Sampler::getTexture() const
|
|
|
|
|
|
void Texture::Sampler::bind()
|
|
|
{
|
|
|
+ GP_ASSERT(_texture);
|
|
|
+
|
|
|
GL_ASSERT( glBindTexture(GL_TEXTURE_2D, _texture->_handle) );
|
|
|
GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (GLenum)_wrapS) );
|
|
|
GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (GLenum)_wrapT) );
|