Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Images/nv_image.cpp')
-rw-r--r--Source/Images/nv_image.cpp497
1 files changed, 497 insertions, 0 deletions
diff --git a/Source/Images/nv_image.cpp b/Source/Images/nv_image.cpp
new file mode 100644
index 00000000..b7b7e1b9
--- /dev/null
+++ b/Source/Images/nv_image.cpp
@@ -0,0 +1,497 @@
+//-----------------------------------------------------------------------------
+// Name: nv_image.cpp
+// Developer: Wolfire Games LLC
+// Description: This is a file from an Nvidia image library, with some
+// modification made by Wolfire.
+// License: Read below
+//-----------------------------------------------------------------------------
+//
+// nvImage.cpp - Image support class
+//
+// The nvImage class implements an interface for a multipurpose image
+// object. This class is useful for loading and formating images
+// for use as textures. The class supports dds, png, and hdr formats.
+//
+// This file implements the format independent interface.
+//
+// Author: Evan Hart
+// Email: sdkfeedback@nvidia.com
+//
+// Copyright (c) NVIDIA Corporation. All rights reserved.
+////////////////////////////////////////////////////////////////////////////////
+#include "nv_image.h"
+
+#include <Utility/assert.h>
+
+#include <cstring>
+#include <algorithm>
+
+using std::vector;
+using std::max;
+
+#ifdef WIN32
+#define strcasecmp _stricmp
+#endif
+
+namespace nv2 {
+
+Image::FormatInfo Image::formatTable[] = {
+ { "dds", Image::readDDS, 0}
+};
+
+
+//
+//
+////////////////////////////////////////////////////////////
+Image::Image() : _width(0), _height(0), _depth(0), _levelCount(0), _faces(0), _format(GL_RGBA),
+ _internalFormat(GL_RGBA8), _type(GL_UNSIGNED_BYTE), _elementSize(0) {
+}
+
+//
+//
+////////////////////////////////////////////////////////////
+Image::~Image() {
+ freeData();
+}
+
+//
+//
+////////////////////////////////////////////////////////////
+void Image::freeData() {
+ for (vector<GLubyte*>::iterator it = _data.begin(); it != _data.end(); it++) {
+ delete []*it;
+ }
+ _data.clear();
+}
+
+//
+//
+////////////////////////////////////////////////////////////
+int Image::getImageSize( int level) const {
+ bool compressed = isCompressed();
+ int w = _width >> level;
+ int h = _height >> level;
+ int d = _depth >> level;
+ w = (w) ? w : 1;
+ h = (h) ? h : 1;
+ d = (d) ? d : 1;
+ int bw = (compressed) ? ( w + 3 ) / 4 : w;
+ int bh = (compressed) ? ( h + 3 ) / 4 : h;
+ int elementSize = _elementSize;
+
+ return bw*bh*d*elementSize;
+}
+
+
+//
+//
+////////////////////////////////////////////////////////////
+const void* Image::getLevel( int level, GLenum face) const {
+ LOG_ASSERT( level < _levelCount);
+ LOG_ASSERT( _faces == 0 || ( face >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z));
+
+ face = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+
+ LOG_ASSERT( (face*_levelCount + level) < _data.size());
+ return _data[ face*_levelCount + level];
+}
+
+//
+//
+////////////////////////////////////////////////////////////
+void* Image::getLevel( int level, GLenum face) {
+ LOG_ASSERT( level < _levelCount);
+ LOG_ASSERT( _faces == 0 || ( face >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z));
+
+ face = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+
+ LOG_ASSERT( (face*_levelCount + level) < _data.size());
+ return _data[ face*_levelCount + level];
+}
+
+//
+//
+////////////////////////////////////////////////////////////
+bool Image::loadImageFromFile( const char* file) {
+ const char* extension;
+ extension = strrchr( file, '.');
+
+ if (extension)
+ extension++; //start looking after the .
+ else
+ return false;
+
+ int formatCount = sizeof(Image::formatTable) / sizeof(Image::FormatInfo);
+
+ //try to match by format first
+ for ( int ii = 0; ii < formatCount; ii++) {
+ if ( ! strcasecmp( formatTable[ii].extension, extension)) {
+ //extension matches, load it
+ return formatTable[ii].reader( file, *this);
+ }
+ }
+
+
+ return false;
+}
+
+//
+//
+////////////////////////////////////////////////////////////
+void Image::flipSurface(GLubyte *surf, int width, int height, int depth)
+{
+ unsigned int lineSize;
+
+ depth = (depth) ? depth : 1;
+
+ if (!isCompressed()) {
+ lineSize = _elementSize * width;
+ unsigned int sliceSize = lineSize * height;
+
+ GLubyte *tempBuf = new GLubyte[lineSize];
+
+ for ( int ii = 0; ii < depth; ii++) {
+ GLubyte *top = surf + ii*sliceSize;
+ GLubyte *bottom = top + (sliceSize - lineSize);
+
+ for ( int jj = 0; jj < (height >> 1); jj++) {
+ memcpy( tempBuf, top, lineSize);
+ memcpy( top, bottom, lineSize);
+ memcpy( bottom, tempBuf, lineSize);
+
+ top += lineSize;
+ bottom -= lineSize;
+ }
+ }
+
+ delete []tempBuf;
+ }
+ else
+ {
+ void (*flipblocks)(GLubyte*, unsigned int);
+ width = (width + 3) / 4;
+ height = (height + 3) / 4;
+ unsigned int blockSize = 0;
+
+ switch (_format)
+ {
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ blockSize = 8;
+ flipblocks = &Image::flip_blocks_dxtc1;
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ blockSize = 16;
+ flipblocks = &Image::flip_blocks_dxtc3;
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ blockSize = 16;
+ flipblocks = &Image::flip_blocks_dxtc5;
+ break;
+ default:
+ return;
+ }
+
+ lineSize = width * blockSize;
+ GLubyte *tempBuf = new GLubyte[lineSize];
+
+ GLubyte *top = surf;
+ GLubyte *bottom = surf + (height-1) * lineSize;
+
+ for (unsigned int j = 0; j < max( (unsigned int)height >> 1, (unsigned int)1); j++)
+ {
+ if (top == bottom)
+ {
+ flipblocks(top, width);
+ break;
+ }
+
+ flipblocks(top, width);
+ flipblocks(bottom, width);
+
+ memcpy( tempBuf, top, lineSize);
+ memcpy( top, bottom, lineSize);
+ memcpy( bottom, tempBuf, lineSize);
+
+ top += lineSize;
+ bottom -= lineSize;
+ }
+ delete []tempBuf;
+ }
+}
+
+//
+//
+////////////////////////////////////////////////////////////
+bool Image::convertCrossToCubemap() {
+ //can't already be a cubemap
+ if (isCubeMap())
+ return false;
+
+ //mipmaps are not supported
+ if (_levelCount != 1)
+ return false;
+
+ //compressed textures are not supported
+ if (isCompressed())
+ return false;
+
+ //this function only supports vertical cross format for now (3 wide by 4 high)
+ if ( (_width / 3 != _height / 4) || (_width % 3 != 0) || (_height % 4 != 0) || (_depth != 0))
+ return false;
+
+ //get the source data
+ GLubyte *data = _data[0];
+
+ int fWidth = _width / 3;
+ int fHeight = _height / 4;
+
+ //remove the old pointer from the vector
+ _data.pop_back();
+
+ GLubyte *face = new GLubyte[ fWidth * fHeight * _elementSize];
+ GLubyte *ptr;
+
+ //extract the faces
+
+ // positive X
+ ptr = face;
+ for (int j=0; j<fHeight; j++) {
+ memcpy( ptr, &data[((_height - (fHeight + j + 1))*_width + 2 * fWidth) * _elementSize], fWidth*_elementSize);
+ ptr += fWidth*_elementSize;
+ }
+ _data.push_back(face);
+
+ // negative X
+ face = new GLubyte[ fWidth * fHeight * _elementSize];
+ ptr = face;
+ for (int j=0; j<fHeight; j++) {
+ memcpy( ptr, &data[(_height - (fHeight + j + 1))*_width*_elementSize], fWidth*_elementSize);
+ ptr += fWidth*_elementSize;
+ }
+ _data.push_back(face);
+
+ // positive Y
+ face = new GLubyte[ fWidth * fHeight * _elementSize];
+ ptr = face;
+ for (int j=0; j<fHeight; j++) {
+ memcpy( ptr, &data[((4 * fHeight - j - 1)*_width + fWidth)*_elementSize], fWidth*_elementSize);
+ ptr += fWidth*_elementSize;
+ }
+ _data.push_back(face);
+
+ // negative Y
+ face = new GLubyte[ fWidth * fHeight * _elementSize];
+ ptr = face;
+ for (int j=0; j<fHeight; j++) {
+ memcpy( ptr, &data[((2*fHeight - j - 1)*_width + fWidth)*_elementSize], fWidth*_elementSize);
+ ptr += fWidth*_elementSize;
+ }
+ _data.push_back(face);
+
+ // positive Z
+ face = new GLubyte[ fWidth * fHeight * _elementSize];
+ ptr = face;
+ for (int j=0; j<fHeight; j++) {
+ memcpy( ptr, &data[((_height - (fHeight + j + 1))*_width + fWidth) * _elementSize], fWidth*_elementSize);
+ ptr += fWidth*_elementSize;
+ }
+ _data.push_back(face);
+
+ // negative Z
+ face = new GLubyte[ fWidth * fHeight * _elementSize];
+ ptr = face;
+ for (int j=0; j<fHeight; j++) {
+ for (int i=0; i<fWidth; i++) {
+ memcpy( ptr, &data[(j*_width + 2 * fWidth - (i + 1))*_elementSize], _elementSize);
+ ptr += _elementSize;
+ }
+ }
+ _data.push_back(face);
+
+ //set the new # of faces, width and height
+ _faces = 6;
+ _width = fWidth;
+ _height = fHeight;
+
+ //delete the old pointer
+ delete []data;
+
+ return true;
+}
+
+//
+//
+////////////////////////////////////////////////////////////
+bool Image::setImage( int width, int height, GLenum format, GLenum type, const void* data){
+ //check parameters before destroying the old image
+ int elementSize;
+ GLenum internalFormat;
+
+ switch (format) {
+ case GL_ALPHA:
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ internalFormat = GL_ALPHA8;
+ elementSize = 1;
+ break;
+ case GL_UNSIGNED_SHORT:
+ internalFormat = GL_ALPHA16;
+ elementSize = 2;
+ break;
+ case GL_FLOAT:
+ internalFormat = GL_ALPHA32F_ARB;
+ elementSize = 4;
+ break;
+ case GL_HALF_FLOAT:
+ internalFormat = GL_ALPHA16F_ARB;
+ elementSize = 2;
+ break;
+ default:
+ return false; //format/type combo not supported
+ }
+ break;
+ case GL_LUMINANCE:
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ internalFormat = GL_LUMINANCE8;
+ elementSize = 1;
+ break;
+ case GL_UNSIGNED_SHORT:
+ internalFormat = GL_LUMINANCE16;
+ elementSize = 2;
+ break;
+ case GL_FLOAT:
+ internalFormat = GL_LUMINANCE32F_ARB;
+ elementSize = 4;
+ break;
+ case GL_HALF_FLOAT:
+ internalFormat = GL_LUMINANCE16F_ARB;
+ elementSize = 2;
+ break;
+ default:
+ return false; //format/type combo not supported
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ internalFormat = GL_LUMINANCE8_ALPHA8;
+ elementSize = 2;
+ break;
+ case GL_UNSIGNED_SHORT:
+ internalFormat = GL_LUMINANCE16_ALPHA16;
+ elementSize = 4;
+ break;
+ case GL_FLOAT:
+ internalFormat = GL_LUMINANCE_ALPHA32F_ARB;
+ elementSize = 8;
+ break;
+ case GL_HALF_FLOAT:
+ internalFormat = GL_LUMINANCE_ALPHA16F_ARB;
+ elementSize = 4;
+ break;
+ default:
+ return false; //format/type combo not supported
+ }
+ break;
+ case GL_RGB:
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ internalFormat = GL_RGB8;
+ elementSize = 3;
+ break;
+ case GL_UNSIGNED_SHORT:
+ internalFormat = GL_RGB16;
+ elementSize = 6;
+ break;
+ case GL_FLOAT:
+ internalFormat = GL_RGB32F;
+ elementSize = 12;
+ break;
+ case GL_HALF_FLOAT:
+ internalFormat = GL_RGB16F;
+ elementSize = 6;
+ break;
+ default:
+ return false; //format/type combo not supported
+ }
+ break;
+ case GL_RGBA:
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ internalFormat = GL_RGBA8;
+ elementSize = 4;
+ break;
+ case GL_UNSIGNED_SHORT:
+ internalFormat = GL_RGBA16;
+ elementSize = 8;
+ break;
+ case GL_FLOAT:
+ internalFormat = GL_RGBA32F;
+ elementSize = 16;
+ break;
+ case GL_HALF_FLOAT:
+ internalFormat = GL_RGBA16F;
+ elementSize = 8;
+ break;
+ default:
+ return false; //format/type combo not supported
+ }
+ break;
+ default:
+ //bad format
+ return false;
+ break;
+ }
+
+
+ //clear old data
+ freeData();
+
+ GLubyte *newImage = new GLubyte[width*height*elementSize];
+ memcpy( newImage, data, width*height*elementSize);
+
+ _data.push_back(newImage);
+
+ _width = width;
+ _height = height;
+ _elementSize = elementSize;
+ _internalFormat = internalFormat;
+ _levelCount = 1;
+ _faces = 0;
+ _depth = 0;
+ _format = format;
+ _type = type;
+
+ return true;
+}
+
+//
+//
+////////////////////////////////////////////////////////////
+bool Image::saveImageToFile( const char* file) {
+ const char* extension;
+ extension = strrchr( file, '.');
+
+ if (extension)
+ extension++; //start looking after the .
+ else
+ return false;
+
+ int formatCount = sizeof(Image::formatTable) / sizeof(Image::FormatInfo);
+
+ //try to match by format first
+ for ( int ii = 0; ii < formatCount; ii++) {
+ if ( ! strcasecmp( formatTable[ii].extension, extension)) {
+ //extension matches, load it
+ if (formatTable[ii].writer) {
+ return formatTable[ii].writer( file, *this);
+ }
+ }
+ }
+
+
+ return false;
+}
+
+}