diff --git a/Source/Core/Common/Common.vcproj b/Source/Core/Common/Common.vcproj
index a1021c6aaa..eb08db5fa9 100644
--- a/Source/Core/Common/Common.vcproj
+++ b/Source/Core/Common/Common.vcproj
@@ -88,6 +88,149 @@
Name="VCPostBuildEventTool"
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -752,7 +744,7 @@
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
@@ -2303,14 +2295,6 @@
UsePrecompiledHeader="1"
/>
-
-
-
@@ -2320,7 +2304,7 @@
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1124,6 +1116,14 @@
RelativePath=".\Src\InfoWindow.h"
>
+
+
+
+
@@ -1188,14 +1188,6 @@
Name="VCCLCompilerTool"
/>
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
@@ -1280,14 +1272,6 @@
UsePrecompiledHeader="0"
/>
-
-
-
@@ -1297,7 +1281,7 @@
/>
+
+
+
+
+
+
+#include
+#include "SOIL/SOIL.h"
+#include "CommonPaths.h"
+#include "FileUtil.h"
+#include "FileSearch.h"
+
+namespace HiresTextures
+{
+
+std::map textureMap;
+
+void Init(const char *gameCode)
+{
+ CFileSearch::XStringVector Directories;
+ Directories.push_back(std::string(FULL_HIRES_TEXTURES_DIR));
+
+ for(u32 i = 0; i < Directories.size(); i++)
+ {
+ File::FSTEntry FST_Temp;
+ File::ScanDirectoryTree(Directories.at(i).c_str(), FST_Temp);
+ for(u32 j = 0; j < FST_Temp.children.size(); j++)
+ {
+ if(FST_Temp.children.at(j).isDirectory)
+ {
+ bool duplicate = false;
+ NormalizeDirSep(&(FST_Temp.children.at(j).physicalName));
+ for(u32 k = 0; k < Directories.size(); k++)
+ {
+ NormalizeDirSep(&Directories.at(k));
+ if(strcmp(Directories.at(k).c_str(), FST_Temp.children.at(j).physicalName.c_str()) == 0)
+ {
+ duplicate = true;
+ break;
+ }
+ }
+ if(!duplicate)
+ Directories.push_back(FST_Temp.children.at(j).physicalName.c_str());
+ }
+ }
+ }
+
+ CFileSearch::XStringVector Extensions;
+ Extensions.push_back("*.png");
+ Extensions.push_back("*.bmp");
+ Extensions.push_back("*.tga");
+ Extensions.push_back("*.dds");
+
+ CFileSearch FileSearch(Extensions, Directories);
+ const CFileSearch::XStringVector& rFilenames = FileSearch.GetFileNames();
+
+ if(rFilenames.size() > 0)
+ {
+ for(u32 i = 0; i < rFilenames.size(); i++)
+ {
+ std::string FileName;
+ SplitPath(rFilenames[i], NULL, &FileName, NULL);
+
+ if(FileName.substr(0, strlen(gameCode)).compare(gameCode) == 0 && textureMap.find(FileName) == textureMap.end())
+ textureMap.insert(std::map::value_type(FileName, rFilenames[i]));
+ }
+ }
+}
+
+void Shutdown()
+{
+ textureMap.clear();
+}
+
+PC_TexFormat GetHiresTex(const char *fileName, int *pWidth, int *pHeight, u8 *data)
+{
+ std::string key(fileName);
+
+ if(textureMap.find(key) == textureMap.end())
+ return PC_TEX_FMT_NONE;
+
+ int width;
+ int height;
+ int channels;
+ u8 *temp = SOIL_load_image(textureMap[key].c_str(), &width, &height, &channels, SOIL_LOAD_RGBA);
+
+ if (temp == NULL) {
+ ERROR_LOG(VIDEO, "Custom texture %s failed to load", textureMap[key].c_str(), width, height);
+ SOIL_free_image_data(temp);
+ return PC_TEX_FMT_NONE;
+ }
+
+ if (width > 1024 || height > 1024) {
+ ERROR_LOG(VIDEO, "Custom texture %s is too large (%ix%i); textures can only be 1024 pixels tall and wide", textureMap[key].c_str(), width, height);
+ SOIL_free_image_data(temp);
+ return PC_TEX_FMT_NONE;
+ }
+
+ memcpy(data, temp, width*height*4);
+ *pWidth = width;
+ *pHeight = height;
+ SOIL_free_image_data(temp);
+ return PC_TEX_FMT_RGBA32;
+}
+
+}
diff --git a/Source/Core/VideoCommon/Src/PixelShaderManager.cpp b/Source/Core/VideoCommon/Src/PixelShaderManager.cpp
index f2ead54b32..49200f401b 100644
--- a/Source/Core/VideoCommon/Src/PixelShaderManager.cpp
+++ b/Source/Core/VideoCommon/Src/PixelShaderManager.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2003-2008 Dolphin Project.
+// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -35,6 +35,7 @@ static bool s_bFogColorChanged;
static bool s_bFogParamChanged;
static float lastDepthRange[2] = {0}; // 0 = far z, 1 = far - near
static float lastRGBAfull[2][4][4];
+static float lastCustomTexScale[8][2];
static u8 s_nTexDimsChanged;
static u8 s_nIndTexScaleChanged;
static u32 lastAlpha = 0;
@@ -55,6 +56,8 @@ void PixelShaderManager::Init()
s_bAlphaChanged = s_bZBiasChanged = s_bZTextureTypeChanged = s_bDepthRangeChanged = true;
s_bFogColorChanged = s_bFogParamChanged = true;
memset(lastRGBAfull, 0, sizeof(lastRGBAfull));
+ for (int i = 0; i < 8; i++)
+ lastCustomTexScale[i][0] = lastCustomTexScale[i][1] = 1.0f;
}
void PixelShaderManager::Shutdown()
@@ -186,6 +189,8 @@ void PixelShaderManager::SetConstants()
SetPSConstant4f(C_FOG + 1, a, b, bpmem.fog.c_proj_fsel.GetC(), 0);
s_bFogParamChanged = false;
}
+ for (int i = 0; i < 8; i++)
+ lastCustomTexScale[i][0] = lastCustomTexScale[i][1] = 1.0f;
}
void PixelShaderManager::SetPSTextureDims(int texid)
@@ -198,15 +203,15 @@ void PixelShaderManager::SetPSTextureDims(int texid)
TCoordInfo& tc = bpmem.texcoords[texid];
fdims[0] = (float)(lastTexDims[texid]&0xffff);
fdims[1] = (float)((lastTexDims[texid]>>16)&0xfff);
- fdims[2] = (float)(tc.s.scale_minus_1+1);
- fdims[3] = (float)(tc.t.scale_minus_1+1);
+ fdims[2] = (float)(tc.s.scale_minus_1+1)*lastCustomTexScale[texid][0];
+ fdims[3] = (float)(tc.t.scale_minus_1+1)*lastCustomTexScale[texid][1];
}
else {
TCoordInfo& tc = bpmem.texcoords[texid];
fdims[0] = 1.0f/(float)(lastTexDims[texid]&0xffff);
fdims[1] = 1.0f/(float)((lastTexDims[texid]>>16)&0xfff);
- fdims[2] = (float)(tc.s.scale_minus_1+1);
- fdims[3] = (float)(tc.t.scale_minus_1+1);
+ fdims[2] = (float)(tc.s.scale_minus_1+1)*lastCustomTexScale[texid][0];
+ fdims[3] = (float)(tc.t.scale_minus_1+1)*lastCustomTexScale[texid][1];
}
PRIM_LOG("texdims%d: %f %f %f %f\n", texid, fdims[0], fdims[1], fdims[2], fdims[3]);
@@ -253,6 +258,12 @@ void PixelShaderManager::SetTexDims(int texmapid, u32 width, u32 height, u32 wra
}
}
+void PixelShaderManager::SetCustomTexScale(int texmapid, float x, float y)
+{
+ lastCustomTexScale[texmapid][0] = x;
+ lastCustomTexScale[texmapid][1] = y;
+}
+
void PixelShaderManager::SetZTextureBias(u32 bias)
{
if (lastZBias != bias) {
diff --git a/Source/Core/VideoCommon/Src/PixelShaderManager.h b/Source/Core/VideoCommon/Src/PixelShaderManager.h
index c9452afe6b..1b19d36f03 100644
--- a/Source/Core/VideoCommon/Src/PixelShaderManager.h
+++ b/Source/Core/VideoCommon/Src/PixelShaderManager.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2003-2008 Dolphin Project.
+// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -39,6 +39,8 @@ public:
static void SetAlpha(const AlphaFunc& alpha);
static void SetDestAlpha(const ConstantAlpha& alpha);
static void SetTexDims(int texmapid, u32 width, u32 height, u32 wraps, u32 wrapt);
+ static void SetCustomTexScale(int texmapid, float x, float y);
+ static void SetCustomTexScale(int texmapid, float x, float y);
static void SetZTextureBias(u32 bias);
static void SetViewport(float* viewport);
static void SetIndMatrixChanged(int matrixidx);
diff --git a/Source/Core/VideoCommon/Src/SConscript b/Source/Core/VideoCommon/Src/SConscript
index 9f0a42c47b..75deb37829 100644
--- a/Source/Core/VideoCommon/Src/SConscript
+++ b/Source/Core/VideoCommon/Src/SConscript
@@ -30,6 +30,11 @@ files = [
'Fifo.cpp',
'VideoState.cpp',
'Profiler.cpp',
+ 'HiresTextures.cpp',
+ 'SOIL/image_DXT.c',
+ 'SOIL/image_helper.c',
+ 'SOIL/SOIL.c',
+ 'SOIL/stb_image_aug.c'
]
env_common = env.Clone()
diff --git a/Source/Core/VideoCommon/Src/SOIL/SOIL.c b/Source/Core/VideoCommon/Src/SOIL/SOIL.c
new file mode 100644
index 0000000000..44d62dbc34
--- /dev/null
+++ b/Source/Core/VideoCommon/Src/SOIL/SOIL.c
@@ -0,0 +1,2024 @@
+/*
+ Jonathan Dummer
+ 2007-07-26-10.36
+
+ Simple OpenGL Image Library
+
+ Public Domain
+ using Sean Barret's stb_image as a base
+
+ Thanks to:
+ * Sean Barret - for the awesome stb_image
+ * Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts
+ * everybody at gamedev.net
+*/
+
+#define SOIL_CHECK_FOR_GL_ERRORS 0
+
+#ifdef WIN32
+ #define WIN32_LEAN_AND_MEAN
+ #include
+ #include
+ #include
+#elif defined(__APPLE__) || defined(__APPLE_CC__)
+ /* I can't test this Apple stuff! */
+ #include
+ #include
+ #define APIENTRY
+#else
+ #include
+ #include
+#endif
+
+#include "SOIL.h"
+#include "stb_image_aug.h"
+#include "image_helper.h"
+#include "image_DXT.h"
+
+#include
+#include
+
+/* error reporting */
+char *result_string_pointer = "SOIL initialized";
+
+/* for loading cube maps */
+enum{
+ SOIL_CAPABILITY_UNKNOWN = -1,
+ SOIL_CAPABILITY_NONE = 0,
+ SOIL_CAPABILITY_PRESENT = 1
+};
+static int has_cubemap_capability = SOIL_CAPABILITY_UNKNOWN;
+int query_cubemap_capability( void );
+#define SOIL_TEXTURE_WRAP_R 0x8072
+#define SOIL_CLAMP_TO_EDGE 0x812F
+#define SOIL_NORMAL_MAP 0x8511
+#define SOIL_REFLECTION_MAP 0x8512
+#define SOIL_TEXTURE_CUBE_MAP 0x8513
+#define SOIL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define SOIL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define SOIL_PROXY_TEXTURE_CUBE_MAP 0x851B
+#define SOIL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+/* for non-power-of-two texture */
+static int has_NPOT_capability = SOIL_CAPABILITY_UNKNOWN;
+int query_NPOT_capability( void );
+/* for texture rectangles */
+static int has_tex_rectangle_capability = SOIL_CAPABILITY_UNKNOWN;
+int query_tex_rectangle_capability( void );
+#define SOIL_TEXTURE_RECTANGLE_ARB 0x84F5
+#define SOIL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+/* for using DXT compression */
+static int has_DXT_capability = SOIL_CAPABILITY_UNKNOWN;
+int query_DXT_capability( void );
+#define SOIL_RGB_S3TC_DXT1 0x83F0
+#define SOIL_RGBA_S3TC_DXT1 0x83F1
+#define SOIL_RGBA_S3TC_DXT3 0x83F2
+#define SOIL_RGBA_S3TC_DXT5 0x83F3
+typedef void (APIENTRY * P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid * data);
+P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC soilGlCompressedTexImage2D = NULL;
+unsigned int SOIL_direct_load_DDS(
+ const char *filename,
+ unsigned int reuse_texture_ID,
+ int flags,
+ int loading_as_cubemap );
+unsigned int SOIL_direct_load_DDS_from_memory(
+ const unsigned char *const buffer,
+ int buffer_length,
+ unsigned int reuse_texture_ID,
+ int flags,
+ int loading_as_cubemap );
+/* other functions */
+unsigned int
+ SOIL_internal_create_OGL_texture
+ (
+ const unsigned char *const data,
+ int width, int height, int channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags,
+ unsigned int opengl_texture_type,
+ unsigned int opengl_texture_target,
+ unsigned int texture_check_size_enum
+ );
+
+/* and the code magic begins here [8^) */
+unsigned int
+ SOIL_load_OGL_texture
+ (
+ const char *filename,
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ )
+{
+ /* variables */
+ unsigned char* img;
+ int width, height, channels;
+ unsigned int tex_id;
+ /* does the user want direct uploading of the image as a DDS file? */
+ if( flags & SOIL_FLAG_DDS_LOAD_DIRECT )
+ {
+ /* 1st try direct loading of the image as a DDS file
+ note: direct uploading will only load what is in the
+ DDS file, no MIPmaps will be generated, the image will
+ not be flipped, etc. */
+ tex_id = SOIL_direct_load_DDS( filename, reuse_texture_ID, flags, 0 );
+ if( tex_id )
+ {
+ /* hey, it worked!! */
+ return tex_id;
+ }
+ }
+ /* try to load the image */
+ img = SOIL_load_image( filename, &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* OK, make it a texture! */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ reuse_texture_ID, flags,
+ GL_TEXTURE_2D, GL_TEXTURE_2D,
+ GL_MAX_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ /* and return the handle, such as it is */
+ return tex_id;
+}
+
+unsigned int
+ SOIL_load_OGL_HDR_texture
+ (
+ const char *filename,
+ int fake_HDR_format,
+ int rescale_to_max,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ )
+{
+ /* variables */
+ unsigned char* img;
+ int width, height, channels;
+ unsigned int tex_id;
+ /* no direct uploading of the image as a DDS file */
+ /* error check */
+ if( (fake_HDR_format != SOIL_HDR_RGBE) &&
+ (fake_HDR_format != SOIL_HDR_RGBdivA) &&
+ (fake_HDR_format != SOIL_HDR_RGBdivA2) )
+ {
+ result_string_pointer = "Invalid fake HDR format specified";
+ return 0;
+ }
+ /* try to load the image (only the HDR type) */
+ img = stbi_hdr_load_rgbe( filename, &width, &height, &channels, 4 );
+ /* channels holds the original number of channels, which may have been forced */
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* the load worked, do I need to convert it? */
+ if( fake_HDR_format == SOIL_HDR_RGBdivA )
+ {
+ RGBE_to_RGBdivA( img, width, height, rescale_to_max );
+ } else if( fake_HDR_format == SOIL_HDR_RGBdivA2 )
+ {
+ RGBE_to_RGBdivA2( img, width, height, rescale_to_max );
+ }
+ /* OK, make it a texture! */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ reuse_texture_ID, flags,
+ GL_TEXTURE_2D, GL_TEXTURE_2D,
+ GL_MAX_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ /* and return the handle, such as it is */
+ return tex_id;
+}
+
+unsigned int
+ SOIL_load_OGL_texture_from_memory
+ (
+ const unsigned char *const buffer,
+ int buffer_length,
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ )
+{
+ /* variables */
+ unsigned char* img;
+ int width, height, channels;
+ unsigned int tex_id;
+ /* does the user want direct uploading of the image as a DDS file? */
+ if( flags & SOIL_FLAG_DDS_LOAD_DIRECT )
+ {
+ /* 1st try direct loading of the image as a DDS file
+ note: direct uploading will only load what is in the
+ DDS file, no MIPmaps will be generated, the image will
+ not be flipped, etc. */
+ tex_id = SOIL_direct_load_DDS_from_memory(
+ buffer, buffer_length,
+ reuse_texture_ID, flags, 0 );
+ if( tex_id )
+ {
+ /* hey, it worked!! */
+ return tex_id;
+ }
+ }
+ /* try to load the image */
+ img = SOIL_load_image_from_memory(
+ buffer, buffer_length,
+ &width, &height, &channels,
+ force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* OK, make it a texture! */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ reuse_texture_ID, flags,
+ GL_TEXTURE_2D, GL_TEXTURE_2D,
+ GL_MAX_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ /* and return the handle, such as it is */
+ return tex_id;
+}
+
+unsigned int
+ SOIL_load_OGL_cubemap
+ (
+ const char *x_pos_file,
+ const char *x_neg_file,
+ const char *y_pos_file,
+ const char *y_neg_file,
+ const char *z_pos_file,
+ const char *z_neg_file,
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ )
+{
+ /* variables */
+ unsigned char* img;
+ int width, height, channels;
+ unsigned int tex_id;
+ /* error checking */
+ if( (x_pos_file == NULL) ||
+ (x_neg_file == NULL) ||
+ (y_pos_file == NULL) ||
+ (y_neg_file == NULL) ||
+ (z_pos_file == NULL) ||
+ (z_neg_file == NULL) )
+ {
+ result_string_pointer = "Invalid cube map files list";
+ return 0;
+ }
+ /* capability checking */
+ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
+ {
+ result_string_pointer = "No cube map capability present";
+ return 0;
+ }
+ /* 1st face: try to load the image */
+ img = SOIL_load_image( x_pos_file, &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, and create a texture ID if necessary */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ reuse_texture_ID, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ /* continue? */
+ if( tex_id != 0 )
+ {
+ /* 1st face: try to load the image */
+ img = SOIL_load_image( x_neg_file, &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, but reuse the assigned texture ID */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ tex_id, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ }
+ /* continue? */
+ if( tex_id != 0 )
+ {
+ /* 1st face: try to load the image */
+ img = SOIL_load_image( y_pos_file, &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, but reuse the assigned texture ID */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ tex_id, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ }
+ /* continue? */
+ if( tex_id != 0 )
+ {
+ /* 1st face: try to load the image */
+ img = SOIL_load_image( y_neg_file, &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, but reuse the assigned texture ID */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ tex_id, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ }
+ /* continue? */
+ if( tex_id != 0 )
+ {
+ /* 1st face: try to load the image */
+ img = SOIL_load_image( z_pos_file, &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, but reuse the assigned texture ID */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ tex_id, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ }
+ /* continue? */
+ if( tex_id != 0 )
+ {
+ /* 1st face: try to load the image */
+ img = SOIL_load_image( z_neg_file, &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, but reuse the assigned texture ID */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ tex_id, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ }
+ /* and return the handle, such as it is */
+ return tex_id;
+}
+
+unsigned int
+ SOIL_load_OGL_cubemap_from_memory
+ (
+ const unsigned char *const x_pos_buffer,
+ int x_pos_buffer_length,
+ const unsigned char *const x_neg_buffer,
+ int x_neg_buffer_length,
+ const unsigned char *const y_pos_buffer,
+ int y_pos_buffer_length,
+ const unsigned char *const y_neg_buffer,
+ int y_neg_buffer_length,
+ const unsigned char *const z_pos_buffer,
+ int z_pos_buffer_length,
+ const unsigned char *const z_neg_buffer,
+ int z_neg_buffer_length,
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ )
+{
+ /* variables */
+ unsigned char* img;
+ int width, height, channels;
+ unsigned int tex_id;
+ /* error checking */
+ if( (x_pos_buffer == NULL) ||
+ (x_neg_buffer == NULL) ||
+ (y_pos_buffer == NULL) ||
+ (y_neg_buffer == NULL) ||
+ (z_pos_buffer == NULL) ||
+ (z_neg_buffer == NULL) )
+ {
+ result_string_pointer = "Invalid cube map buffers list";
+ return 0;
+ }
+ /* capability checking */
+ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
+ {
+ result_string_pointer = "No cube map capability present";
+ return 0;
+ }
+ /* 1st face: try to load the image */
+ img = SOIL_load_image_from_memory(
+ x_pos_buffer, x_pos_buffer_length,
+ &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, and create a texture ID if necessary */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ reuse_texture_ID, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ /* continue? */
+ if( tex_id != 0 )
+ {
+ /* 1st face: try to load the image */
+ img = SOIL_load_image_from_memory(
+ x_neg_buffer, x_neg_buffer_length,
+ &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, but reuse the assigned texture ID */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ tex_id, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ }
+ /* continue? */
+ if( tex_id != 0 )
+ {
+ /* 1st face: try to load the image */
+ img = SOIL_load_image_from_memory(
+ y_pos_buffer, y_pos_buffer_length,
+ &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, but reuse the assigned texture ID */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ tex_id, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ }
+ /* continue? */
+ if( tex_id != 0 )
+ {
+ /* 1st face: try to load the image */
+ img = SOIL_load_image_from_memory(
+ y_neg_buffer, y_neg_buffer_length,
+ &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, but reuse the assigned texture ID */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ tex_id, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ }
+ /* continue? */
+ if( tex_id != 0 )
+ {
+ /* 1st face: try to load the image */
+ img = SOIL_load_image_from_memory(
+ z_pos_buffer, z_pos_buffer_length,
+ &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, but reuse the assigned texture ID */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ tex_id, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ }
+ /* continue? */
+ if( tex_id != 0 )
+ {
+ /* 1st face: try to load the image */
+ img = SOIL_load_image_from_memory(
+ z_neg_buffer, z_neg_buffer_length,
+ &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* upload the texture, but reuse the assigned texture ID */
+ tex_id = SOIL_internal_create_OGL_texture(
+ img, width, height, channels,
+ tex_id, flags,
+ SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ /* and nuke the image data */
+ SOIL_free_image_data( img );
+ }
+ /* and return the handle, such as it is */
+ return tex_id;
+}
+
+unsigned int
+ SOIL_load_OGL_single_cubemap
+ (
+ const char *filename,
+ const char face_order[6],
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ )
+{
+ /* variables */
+ unsigned char* img;
+ int width, height, channels, i;
+ unsigned int tex_id = 0;
+ /* error checking */
+ if( filename == NULL )
+ {
+ result_string_pointer = "Invalid single cube map file name";
+ return 0;
+ }
+ /* does the user want direct uploading of the image as a DDS file? */
+ if( flags & SOIL_FLAG_DDS_LOAD_DIRECT )
+ {
+ /* 1st try direct loading of the image as a DDS file
+ note: direct uploading will only load what is in the
+ DDS file, no MIPmaps will be generated, the image will
+ not be flipped, etc. */
+ tex_id = SOIL_direct_load_DDS( filename, reuse_texture_ID, flags, 1 );
+ if( tex_id )
+ {
+ /* hey, it worked!! */
+ return tex_id;
+ }
+ }
+ /* face order checking */
+ for( i = 0; i < 6; ++i )
+ {
+ if( (face_order[i] != 'N') &&
+ (face_order[i] != 'S') &&
+ (face_order[i] != 'W') &&
+ (face_order[i] != 'E') &&
+ (face_order[i] != 'U') &&
+ (face_order[i] != 'D') )
+ {
+ result_string_pointer = "Invalid single cube map face order";
+ return 0;
+ };
+ }
+ /* capability checking */
+ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
+ {
+ result_string_pointer = "No cube map capability present";
+ return 0;
+ }
+ /* 1st off, try to load the full image */
+ img = SOIL_load_image( filename, &width, &height, &channels, force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* now, does this image have the right dimensions? */
+ if( (width != 6*height) &&
+ (6*width != height) )
+ {
+ SOIL_free_image_data( img );
+ result_string_pointer = "Single cubemap image must have a 6:1 ratio";
+ return 0;
+ }
+ /* try the image split and create */
+ tex_id = SOIL_create_OGL_single_cubemap(
+ img, width, height, channels,
+ face_order, reuse_texture_ID, flags
+ );
+ /* nuke the temporary image data and return the texture handle */
+ SOIL_free_image_data( img );
+ return tex_id;
+}
+
+unsigned int
+ SOIL_load_OGL_single_cubemap_from_memory
+ (
+ const unsigned char *const buffer,
+ int buffer_length,
+ const char face_order[6],
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ )
+{
+ /* variables */
+ unsigned char* img;
+ int width, height, channels, i;
+ unsigned int tex_id = 0;
+ /* error checking */
+ if( buffer == NULL )
+ {
+ result_string_pointer = "Invalid single cube map buffer";
+ return 0;
+ }
+ /* does the user want direct uploading of the image as a DDS file? */
+ if( flags & SOIL_FLAG_DDS_LOAD_DIRECT )
+ {
+ /* 1st try direct loading of the image as a DDS file
+ note: direct uploading will only load what is in the
+ DDS file, no MIPmaps will be generated, the image will
+ not be flipped, etc. */
+ tex_id = SOIL_direct_load_DDS_from_memory(
+ buffer, buffer_length,
+ reuse_texture_ID, flags, 1 );
+ if( tex_id )
+ {
+ /* hey, it worked!! */
+ return tex_id;
+ }
+ }
+ /* face order checking */
+ for( i = 0; i < 6; ++i )
+ {
+ if( (face_order[i] != 'N') &&
+ (face_order[i] != 'S') &&
+ (face_order[i] != 'W') &&
+ (face_order[i] != 'E') &&
+ (face_order[i] != 'U') &&
+ (face_order[i] != 'D') )
+ {
+ result_string_pointer = "Invalid single cube map face order";
+ return 0;
+ };
+ }
+ /* capability checking */
+ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
+ {
+ result_string_pointer = "No cube map capability present";
+ return 0;
+ }
+ /* 1st off, try to load the full image */
+ img = SOIL_load_image_from_memory(
+ buffer, buffer_length,
+ &width, &height, &channels,
+ force_channels );
+ /* channels holds the original number of channels, which may have been forced */
+ if( (force_channels >= 1) && (force_channels <= 4) )
+ {
+ channels = force_channels;
+ }
+ if( NULL == img )
+ {
+ /* image loading failed */
+ result_string_pointer = stbi_failure_reason();
+ return 0;
+ }
+ /* now, does this image have the right dimensions? */
+ if( (width != 6*height) &&
+ (6*width != height) )
+ {
+ SOIL_free_image_data( img );
+ result_string_pointer = "Single cubemap image must have a 6:1 ratio";
+ return 0;
+ }
+ /* try the image split and create */
+ tex_id = SOIL_create_OGL_single_cubemap(
+ img, width, height, channels,
+ face_order, reuse_texture_ID, flags
+ );
+ /* nuke the temporary image data and return the texture handle */
+ SOIL_free_image_data( img );
+ return tex_id;
+}
+
+unsigned int
+ SOIL_create_OGL_single_cubemap
+ (
+ const unsigned char *const data,
+ int width, int height, int channels,
+ const char face_order[6],
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ )
+{
+ /* variables */
+ unsigned char* sub_img;
+ int dw, dh, sz, i;
+ unsigned int tex_id;
+ /* error checking */
+ if( data == NULL )
+ {
+ result_string_pointer = "Invalid single cube map image data";
+ return 0;
+ }
+ /* face order checking */
+ for( i = 0; i < 6; ++i )
+ {
+ if( (face_order[i] != 'N') &&
+ (face_order[i] != 'S') &&
+ (face_order[i] != 'W') &&
+ (face_order[i] != 'E') &&
+ (face_order[i] != 'U') &&
+ (face_order[i] != 'D') )
+ {
+ result_string_pointer = "Invalid single cube map face order";
+ return 0;
+ };
+ }
+ /* capability checking */
+ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
+ {
+ result_string_pointer = "No cube map capability present";
+ return 0;
+ }
+ /* now, does this image have the right dimensions? */
+ if( (width != 6*height) &&
+ (6*width != height) )
+ {
+ result_string_pointer = "Single cubemap image must have a 6:1 ratio";
+ return 0;
+ }
+ /* which way am I stepping? */
+ if( width > height )
+ {
+ dw = height;
+ dh = 0;
+ } else
+ {
+ dw = 0;
+ dh = width;
+ }
+ sz = dw+dh;
+ sub_img = (unsigned char *)malloc( sz*sz*channels );
+ /* do the splitting and uploading */
+ tex_id = reuse_texture_ID;
+ for( i = 0; i < 6; ++i )
+ {
+ int x, y, idx = 0;
+ unsigned int cubemap_target = 0;
+ /* copy in the sub-image */
+ for( y = i*dh; y < i*dh+sz; ++y )
+ {
+ for( x = i*dw*channels; x < (i*dw+sz)*channels; ++x )
+ {
+ sub_img[idx++] = data[y*width*channels+x];
+ }
+ }
+ /* what is my texture target?
+ remember, this coordinate system is
+ LHS if viewed from inside the cube! */
+ switch( face_order[i] )
+ {
+ case 'N':
+ cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z;
+ break;
+ case 'S':
+ cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
+ break;
+ case 'W':
+ cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X;
+ break;
+ case 'E':
+ cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X;
+ break;
+ case 'U':
+ cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y;
+ break;
+ case 'D':
+ cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
+ break;
+ }
+ /* upload it as a texture */
+ tex_id = SOIL_internal_create_OGL_texture(
+ sub_img, sz, sz, channels,
+ tex_id, flags,
+ SOIL_TEXTURE_CUBE_MAP,
+ cubemap_target,
+ SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
+ }
+ /* and nuke the image and sub-image data */
+ SOIL_free_image_data( sub_img );
+ /* and return the handle, such as it is */
+ return tex_id;
+}
+
+unsigned int
+ SOIL_create_OGL_texture
+ (
+ const unsigned char *const data,
+ int width, int height, int channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ )
+{
+ /* wrapper function for 2D textures */
+ return SOIL_internal_create_OGL_texture(
+ data, width, height, channels,
+ reuse_texture_ID, flags,
+ GL_TEXTURE_2D, GL_TEXTURE_2D,
+ GL_MAX_TEXTURE_SIZE );
+}
+
+#if SOIL_CHECK_FOR_GL_ERRORS
+void check_for_GL_errors( const char *calling_location )
+{
+ /* check for errors */
+ GLenum err_code = glGetError();
+ while( GL_NO_ERROR != err_code )
+ {
+ printf( "OpenGL Error @ %s: %i", calling_location, err_code );
+ err_code = glGetError();
+ }
+}
+#else
+void check_for_GL_errors( const char *calling_location )
+{
+ /* no check for errors */
+}
+#endif
+
+unsigned int
+ SOIL_internal_create_OGL_texture
+ (
+ const unsigned char *const data,
+ int width, int height, int channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags,
+ unsigned int opengl_texture_type,
+ unsigned int opengl_texture_target,
+ unsigned int texture_check_size_enum
+ )
+{
+ /* variables */
+ unsigned char* img;
+ unsigned int tex_id;
+ unsigned int internal_texture_format = 0, original_texture_format = 0;
+ int DXT_mode = SOIL_CAPABILITY_UNKNOWN;
+ int max_supported_size;
+ /* If the user wants to use the texture rectangle I kill a few flags */
+ if( flags & SOIL_FLAG_TEXTURE_RECTANGLE )
+ {
+ /* well, the user asked for it, can we do that? */
+ if( query_tex_rectangle_capability() == SOIL_CAPABILITY_PRESENT )
+ {
+ /* only allow this if the user in _NOT_ trying to do a cubemap! */
+ if( opengl_texture_type == GL_TEXTURE_2D )
+ {
+ /* clean out the flags that cannot be used with texture rectangles */
+ flags &= ~(
+ SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS |
+ SOIL_FLAG_TEXTURE_REPEATS
+ );
+ /* and change my target */
+ opengl_texture_target = SOIL_TEXTURE_RECTANGLE_ARB;
+ opengl_texture_type = SOIL_TEXTURE_RECTANGLE_ARB;
+ } else
+ {
+ /* not allowed for any other uses (yes, I'm looking at you, cubemaps!) */
+ flags &= ~SOIL_FLAG_TEXTURE_RECTANGLE;
+ }
+
+ } else
+ {
+ /* can't do it, and that is a breakable offense (uv coords use pixels instead of [0,1]!) */
+ result_string_pointer = "Texture Rectangle extension unsupported";
+ return 0;
+ }
+ }
+ /* create a copy the image data */
+ img = (unsigned char*)malloc( width*height*channels );
+ memcpy( img, data, width*height*channels );
+ /* does the user want me to invert the image? */
+ if( flags & SOIL_FLAG_INVERT_Y )
+ {
+ int i, j;
+ for( j = 0; j*2 < height; ++j )
+ {
+ int index1 = j * width * channels;
+ int index2 = (height - 1 - j) * width * channels;
+ for( i = width * channels; i > 0; --i )
+ {
+ unsigned char temp = img[index1];
+ img[index1] = img[index2];
+ img[index2] = temp;
+ ++index1;
+ ++index2;
+ }
+ }
+ }
+ /* does the user want me to scale the colors into the NTSC safe RGB range? */
+ if( flags & SOIL_FLAG_NTSC_SAFE_RGB )
+ {
+ scale_image_RGB_to_NTSC_safe( img, width, height, channels );
+ }
+ /* does the user want me to convert from straight to pre-multiplied alpha?
+ (and do we even _have_ alpha?) */
+ if( flags & SOIL_FLAG_MULTIPLY_ALPHA )
+ {
+ int i;
+ switch( channels )
+ {
+ case 2:
+ for( i = 0; i < 2*width*height; i += 2 )
+ {
+ img[i] = (img[i] * img[i+1] + 128) >> 8;
+ }
+ break;
+ case 4:
+ for( i = 0; i < 4*width*height; i += 4 )
+ {
+ img[i+0] = (img[i+0] * img[i+3] + 128) >> 8;
+ img[i+1] = (img[i+1] * img[i+3] + 128) >> 8;
+ img[i+2] = (img[i+2] * img[i+3] + 128) >> 8;
+ }
+ break;
+ default:
+ /* no other number of channels contains alpha data */
+ break;
+ }
+ }
+ /* if the user can't support NPOT textures, make sure we force the POT option */
+ if( (query_NPOT_capability() == SOIL_CAPABILITY_NONE) &&
+ !(flags & SOIL_FLAG_TEXTURE_RECTANGLE) )
+ {
+ /* add in the POT flag */
+ flags |= SOIL_FLAG_POWER_OF_TWO;
+ }
+ /* how large of a texture can this OpenGL implementation handle? */
+ /* texture_check_size_enum will be GL_MAX_TEXTURE_SIZE or SOIL_MAX_CUBE_MAP_TEXTURE_SIZE */
+ glGetIntegerv( texture_check_size_enum, &max_supported_size );
+ /* do I need to make it a power of 2? */
+ if(
+ (flags & SOIL_FLAG_POWER_OF_TWO) || /* user asked for it */
+ (flags & SOIL_FLAG_MIPMAPS) || /* need it for the MIP-maps */
+ (width > max_supported_size) || /* it's too big, (make sure it's */
+ (height > max_supported_size) ) /* 2^n for later down-sampling) */
+ {
+ int new_width = 1;
+ int new_height = 1;
+ while( new_width < width )
+ {
+ new_width *= 2;
+ }
+ while( new_height < height )
+ {
+ new_height *= 2;
+ }
+ /* still? */
+ if( (new_width != width) || (new_height != height) )
+ {
+ /* yep, resize */
+ unsigned char *resampled = (unsigned char*)malloc( channels*new_width*new_height );
+ up_scale_image(
+ img, width, height, channels,
+ resampled, new_width, new_height );
+ /* OJO this is for debug only! */
+ /*
+ SOIL_save_image( "\\showme.bmp", SOIL_SAVE_TYPE_BMP,
+ new_width, new_height, channels,
+ resampled );
+ */
+ /* nuke the old guy, then point it at the new guy */
+ SOIL_free_image_data( img );
+ img = resampled;
+ width = new_width;
+ height = new_height;
+ }
+ }
+ /* now, if it is too large... */
+ if( (width > max_supported_size) || (height > max_supported_size) )
+ {
+ /* I've already made it a power of two, so simply use the MIPmapping
+ code to reduce its size to the allowable maximum. */
+ unsigned char *resampled;
+ int reduce_block_x = 1, reduce_block_y = 1;
+ int new_width, new_height;
+ if( width > max_supported_size )
+ {
+ reduce_block_x = width / max_supported_size;
+ }
+ if( height > max_supported_size )
+ {
+ reduce_block_y = height / max_supported_size;
+ }
+ new_width = width / reduce_block_x;
+ new_height = height / reduce_block_y;
+ resampled = (unsigned char*)malloc( channels*new_width*new_height );
+ /* perform the actual reduction */
+ mipmap_image( img, width, height, channels,
+ resampled, reduce_block_x, reduce_block_y );
+ /* nuke the old guy, then point it at the new guy */
+ SOIL_free_image_data( img );
+ img = resampled;
+ width = new_width;
+ height = new_height;
+ }
+ /* does the user want us to use YCoCg color space? */
+ if( flags & SOIL_FLAG_CoCg_Y )
+ {
+ /* this will only work with RGB and RGBA images */
+ convert_RGB_to_YCoCg( img, width, height, channels );
+ /*
+ save_image_as_DDS( "CoCg_Y.dds", width, height, channels, img );
+ */
+ }
+ /* create the OpenGL texture ID handle
+ (note: allowing a forced texture ID lets me reload a texture) */
+ tex_id = reuse_texture_ID;
+ if( tex_id == 0 )
+ {
+ glGenTextures( 1, &tex_id );
+ }
+ check_for_GL_errors( "glGenTextures" );
+ /* Note: sometimes glGenTextures fails (usually no OpenGL context) */
+ if( tex_id )
+ {
+ /* and what type am I using as the internal texture format? */
+ switch( channels )
+ {
+ case 1:
+ original_texture_format = GL_LUMINANCE;
+ break;
+ case 2:
+ original_texture_format = GL_LUMINANCE_ALPHA;
+ break;
+ case 3:
+ original_texture_format = GL_RGB;
+ break;
+ case 4:
+ original_texture_format = GL_RGBA;
+ break;
+ }
+ internal_texture_format = original_texture_format;
+ /* does the user want me to, and can I, save as DXT? */
+ if( flags & SOIL_FLAG_COMPRESS_TO_DXT )
+ {
+ DXT_mode = query_DXT_capability();
+ if( DXT_mode == SOIL_CAPABILITY_PRESENT )
+ {
+ /* I can use DXT, whether I compress it or OpenGL does */
+ if( (channels & 1) == 1 )
+ {
+ /* 1 or 3 channels = DXT1 */
+ internal_texture_format = SOIL_RGB_S3TC_DXT1;
+ } else
+ {
+ /* 2 or 4 channels = DXT5 */
+ internal_texture_format = SOIL_RGBA_S3TC_DXT5;
+ }
+ }
+ }
+ /* bind an OpenGL texture ID */
+ glBindTexture( opengl_texture_type, tex_id );
+ check_for_GL_errors( "glBindTexture" );
+ /* upload the main image */
+ if( DXT_mode == SOIL_CAPABILITY_PRESENT )
+ {
+ /* user wants me to do the DXT conversion! */
+ int DDS_size;
+ unsigned char *DDS_data = NULL;
+ if( (channels & 1) == 1 )
+ {
+ /* RGB, use DXT1 */
+ DDS_data = convert_image_to_DXT1( img, width, height, channels, &DDS_size );
+ } else
+ {
+ /* RGBA, use DXT5 */
+ DDS_data = convert_image_to_DXT5( img, width, height, channels, &DDS_size );
+ }
+ if( DDS_data )
+ {
+ soilGlCompressedTexImage2D(
+ opengl_texture_target, 0,
+ internal_texture_format, width, height, 0,
+ DDS_size, DDS_data );
+ check_for_GL_errors( "glCompressedTexImage2D" );
+ SOIL_free_image_data( DDS_data );
+ /* printf( "Internal DXT compressor\n" ); */
+ } else
+ {
+ /* my compression failed, try the OpenGL driver's version */
+ glTexImage2D(
+ opengl_texture_target, 0,
+ internal_texture_format, width, height, 0,
+ original_texture_format, GL_UNSIGNED_BYTE, img );
+ check_for_GL_errors( "glTexImage2D" );
+ /* printf( "OpenGL DXT compressor\n" ); */
+ }
+ } else
+ {
+ /* user want OpenGL to do all the work! */
+ glTexImage2D(
+ opengl_texture_target, 0,
+ internal_texture_format, width, height, 0,
+ original_texture_format, GL_UNSIGNED_BYTE, img );
+ check_for_GL_errors( "glTexImage2D" );
+ /*printf( "OpenGL DXT compressor\n" ); */
+ }
+ /* are any MIPmaps desired? */
+ if( flags & SOIL_FLAG_MIPMAPS )
+ {
+ int MIPlevel = 1;
+ int MIPwidth = (width+1) / 2;
+ int MIPheight = (height+1) / 2;
+ unsigned char *resampled = (unsigned char*)malloc( channels*MIPwidth*MIPheight );
+ while( ((1< 0; --i )
+ {
+ unsigned char temp = pixel_data[index1];
+ pixel_data[index1] = pixel_data[index2];
+ pixel_data[index2] = temp;
+ ++index1;
+ ++index2;
+ }
+ }
+
+ /* save the image */
+ save_result = SOIL_save_image( filename, image_type, width, height, 3, pixel_data);
+
+ /* And free the memory */
+ SOIL_free_image_data( pixel_data );
+ return save_result;
+}
+
+unsigned char*
+ SOIL_load_image
+ (
+ const char *filename,
+ int *width, int *height, int *channels,
+ int force_channels
+ )
+{
+ unsigned char *result = stbi_load( filename,
+ width, height, channels, force_channels );
+ if( result == NULL )
+ {
+ result_string_pointer = stbi_failure_reason();
+ } else
+ {
+ result_string_pointer = "Image loaded";
+ }
+ return result;
+}
+
+unsigned char*
+ SOIL_load_image_from_memory
+ (
+ const unsigned char *const buffer,
+ int buffer_length,
+ int *width, int *height, int *channels,
+ int force_channels
+ )
+{
+ unsigned char *result = stbi_load_from_memory(
+ buffer, buffer_length,
+ width, height, channels,
+ force_channels );
+ if( result == NULL )
+ {
+ result_string_pointer = stbi_failure_reason();
+ } else
+ {
+ result_string_pointer = "Image loaded from memory";
+ }
+ return result;
+}
+
+int
+ SOIL_save_image
+ (
+ const char *filename,
+ int image_type,
+ int width, int height, int channels,
+ const unsigned char *const data
+ )
+{
+ int save_result;
+
+ /* error check */
+ if( (width < 1) || (height < 1) ||
+ (channels < 1) || (channels > 4) ||
+ (data == NULL) ||
+ (filename == NULL) )
+ {
+ return 0;
+ }
+ if( image_type == SOIL_SAVE_TYPE_BMP )
+ {
+ save_result = stbi_write_bmp( filename,
+ width, height, channels, (void*)data );
+ } else
+ if( image_type == SOIL_SAVE_TYPE_TGA )
+ {
+ save_result = stbi_write_tga( filename,
+ width, height, channels, (void*)data );
+ } else
+ if( image_type == SOIL_SAVE_TYPE_DDS )
+ {
+ save_result = save_image_as_DDS( filename,
+ width, height, channels, (const unsigned char *const)data );
+ } else
+ {
+ save_result = 0;
+ }
+ if( save_result == 0 )
+ {
+ result_string_pointer = "Saving the image failed";
+ } else
+ {
+ result_string_pointer = "Image saved";
+ }
+ return save_result;
+}
+
+void
+ SOIL_free_image_data
+ (
+ unsigned char *img_data
+ )
+{
+ free( (void*)img_data );
+}
+
+const char*
+ SOIL_last_result
+ (
+ void
+ )
+{
+ return result_string_pointer;
+}
+
+unsigned int SOIL_direct_load_DDS_from_memory(
+ const unsigned char *const buffer,
+ int buffer_length,
+ unsigned int reuse_texture_ID,
+ int flags,
+ int loading_as_cubemap )
+{
+ /* variables */
+ DDS_header header;
+ unsigned int buffer_index = 0;
+ unsigned int tex_ID = 0;
+ /* file reading variables */
+ unsigned int S3TC_type = 0;
+ unsigned char *DDS_data;
+ unsigned int DDS_main_size;
+ unsigned int DDS_full_size;
+ unsigned int width, height;
+ int mipmaps, cubemap, uncompressed, block_size = 16;
+ unsigned int flag;
+ unsigned int cf_target, ogl_target_start, ogl_target_end;
+ unsigned int opengl_texture_type;
+ int i;
+ /* 1st off, does the filename even exist? */
+ if( NULL == buffer )
+ {
+ /* we can't do it! */
+ result_string_pointer = "NULL buffer";
+ return 0;
+ }
+ if( buffer_length < sizeof( DDS_header ) )
+ {
+ /* we can't do it! */
+ result_string_pointer = "DDS file was too small to contain the DDS header";
+ return 0;
+ }
+ /* try reading in the header */
+ memcpy ( (void*)(&header), (const void *)buffer, sizeof( DDS_header ) );
+ buffer_index = sizeof( DDS_header );
+ /* guilty until proven innocent */
+ result_string_pointer = "Failed to read a known DDS header";
+ /* validate the header (warning, "goto"'s ahead, shield your eyes!!) */
+ flag = ('D'<<0)|('D'<<8)|('S'<<16)|(' '<<24);
+ if( header.dwMagic != flag ) {goto quick_exit;}
+ if( header.dwSize != 124 ) {goto quick_exit;}
+ /* I need all of these */
+ flag = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
+ if( (header.dwFlags & flag) != flag ) {goto quick_exit;}
+ /* According to the MSDN spec, the dwFlags should contain
+ DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if
+ uncompressed. Some DDS writers do not conform to the
+ spec, so I need to make my reader more tolerant */
+ /* I need one of these */
+ flag = DDPF_FOURCC | DDPF_RGB;
+ if( (header.sPixelFormat.dwFlags & flag) == 0 ) {goto quick_exit;}
+ if( header.sPixelFormat.dwSize != 32 ) {goto quick_exit;}
+ if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) {goto quick_exit;}
+ /* make sure it is a type we can upload */
+ if( (header.sPixelFormat.dwFlags & DDPF_FOURCC) &&
+ !(
+ (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24))) ||
+ (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('3'<<24))) ||
+ (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('5'<<24)))
+ ) )
+ {
+ goto quick_exit;
+ }
+ /* OK, validated the header, let's load the image data */
+ result_string_pointer = "DDS header loaded and validated";
+ width = header.dwWidth;
+ height = header.dwHeight;
+ uncompressed = 1 - (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC;
+ cubemap = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP;
+ if( uncompressed )
+ {
+ S3TC_type = GL_RGB;
+ block_size = 3;
+ if( header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS )
+ {
+ S3TC_type = GL_RGBA;
+ block_size = 4;
+ }
+ DDS_main_size = width * height * block_size;
+ } else
+ {
+ /* can we even handle direct uploading to OpenGL DXT compressed images? */
+ if( query_DXT_capability() != SOIL_CAPABILITY_PRESENT )
+ {
+ /* we can't do it! */
+ result_string_pointer = "Direct upload of S3TC images not supported by the OpenGL driver";
+ return 0;
+ }
+ /* well, we know it is DXT1/3/5, because we checked above */
+ switch( (header.sPixelFormat.dwFourCC >> 24) - '0' )
+ {
+ case 1:
+ S3TC_type = SOIL_RGBA_S3TC_DXT1;
+ block_size = 8;
+ break;
+ case 3:
+ S3TC_type = SOIL_RGBA_S3TC_DXT3;
+ block_size = 16;
+ break;
+ case 5:
+ S3TC_type = SOIL_RGBA_S3TC_DXT5;
+ block_size = 16;
+ break;
+ }
+ DDS_main_size = ((width+3)>>2)*((height+3)>>2)*block_size;
+ }
+ if( cubemap )
+ {
+ /* does the user want a cubemap? */
+ if( !loading_as_cubemap )
+ {
+ /* we can't do it! */
+ result_string_pointer = "DDS image was a cubemap";
+ return 0;
+ }
+ /* can we even handle cubemaps with the OpenGL driver? */
+ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
+ {
+ /* we can't do it! */
+ result_string_pointer = "Direct upload of cubemap images not supported by the OpenGL driver";
+ return 0;
+ }
+ ogl_target_start = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X;
+ ogl_target_end = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
+ opengl_texture_type = SOIL_TEXTURE_CUBE_MAP;
+ } else
+ {
+ /* does the user want a non-cubemap? */
+ if( loading_as_cubemap )
+ {
+ /* we can't do it! */
+ result_string_pointer = "DDS image was not a cubemap";
+ return 0;
+ }
+ ogl_target_start = GL_TEXTURE_2D;
+ ogl_target_end = GL_TEXTURE_2D;
+ opengl_texture_type = GL_TEXTURE_2D;
+ }
+ if( (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1) )
+ {
+ int shift_offset;
+ mipmaps = header.dwMipMapCount - 1;
+ DDS_full_size = DDS_main_size;
+ if( uncompressed )
+ {
+ /* uncompressed DDS, simple MIPmap size calculation */
+ shift_offset = 0;
+ } else
+ {
+ /* compressed DDS, MIPmap size calculation is block based */
+ shift_offset = 2;
+ }
+ for( i = 1; i <= mipmaps; ++ i )
+ {
+ int w, h;
+ w = width >> (shift_offset + i);
+ h = height >> (shift_offset + i);
+ if( w < 1 )
+ {
+ w = 1;
+ }
+ if( h < 1 )
+ {
+ h = 1;
+ }
+ DDS_full_size += w*h*block_size;
+ }
+ } else
+ {
+ mipmaps = 0;
+ DDS_full_size = DDS_main_size;
+ }
+ DDS_data = (unsigned char*)malloc( DDS_full_size );
+ /* got the image data RAM, create or use an existing OpenGL texture handle */
+ tex_ID = reuse_texture_ID;
+ if( tex_ID == 0 )
+ {
+ glGenTextures( 1, &tex_ID );
+ }
+ /* bind an OpenGL texture ID */
+ glBindTexture( opengl_texture_type, tex_ID );
+ /* do this for each face of the cubemap! */
+ for( cf_target = ogl_target_start; cf_target <= ogl_target_end; ++cf_target )
+ {
+ if( buffer_index + DDS_full_size <= buffer_length )
+ {
+ unsigned int byte_offset = DDS_main_size;
+ memcpy( (void*)DDS_data, (const void*)(&buffer[buffer_index]), DDS_full_size );
+ buffer_index += DDS_full_size;
+ /* upload the main chunk */
+ if( uncompressed )
+ {
+ /* and remember, DXT uncompressed uses BGR(A),
+ so swap to RGB(A) for ALL MIPmap levels */
+ for( i = 0; i < DDS_full_size; i += block_size )
+ {
+ unsigned char temp = DDS_data[i];
+ DDS_data[i] = DDS_data[i+2];
+ DDS_data[i+2] = temp;
+ }
+ glTexImage2D(
+ cf_target, 0,
+ S3TC_type, width, height, 0,
+ S3TC_type, GL_UNSIGNED_BYTE, DDS_data );
+ } else
+ {
+ soilGlCompressedTexImage2D(
+ cf_target, 0,
+ S3TC_type, width, height, 0,
+ DDS_main_size, DDS_data );
+ }
+ /* upload the mipmaps, if we have them */
+ for( i = 1; i <= mipmaps; ++i )
+ {
+ int w, h, mip_size;
+ w = width >> i;
+ h = height >> i;
+ if( w < 1 )
+ {
+ w = 1;
+ }
+ if( h < 1 )
+ {
+ h = 1;
+ }
+ /* upload this mipmap */
+ if( uncompressed )
+ {
+ mip_size = w*h*block_size;
+ glTexImage2D(
+ cf_target, i,
+ S3TC_type, w, h, 0,
+ S3TC_type, GL_UNSIGNED_BYTE, &DDS_data[byte_offset] );
+ } else
+ {
+ mip_size = ((w+3)/4)*((h+3)/4)*block_size;
+ soilGlCompressedTexImage2D(
+ cf_target, i,
+ S3TC_type, w, h, 0,
+ mip_size, &DDS_data[byte_offset] );
+ }
+ /* and move to the next mipmap */
+ byte_offset += mip_size;
+ }
+ /* it worked! */
+ result_string_pointer = "DDS file loaded";
+ } else
+ {
+ glDeleteTextures( 1, & tex_ID );
+ tex_ID = 0;
+ cf_target = ogl_target_end + 1;
+ result_string_pointer = "DDS file was too small for expected image data";
+ }
+ }/* end reading each face */
+ SOIL_free_image_data( DDS_data );
+ if( tex_ID )
+ {
+ /* did I have MIPmaps? */
+ if( mipmaps > 0 )
+ {
+ /* instruct OpenGL to use the MIPmaps */
+ glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+ } else
+ {
+ /* instruct OpenGL _NOT_ to use the MIPmaps */
+ glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ }
+ /* does the user want clamping, or wrapping? */
+ if( flags & SOIL_FLAG_TEXTURE_REPEATS )
+ {
+ glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT );
+ } else
+ {
+ /* unsigned int clamp_mode = SOIL_CLAMP_TO_EDGE; */
+ unsigned int clamp_mode = GL_CLAMP;
+ glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode );
+ glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode );
+ glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode );
+ }
+ }
+
+quick_exit:
+ /* report success or failure */
+ return tex_ID;
+}
+
+unsigned int SOIL_direct_load_DDS(
+ const char *filename,
+ unsigned int reuse_texture_ID,
+ int flags,
+ int loading_as_cubemap )
+{
+ FILE *f;
+ unsigned char *buffer;
+ size_t buffer_length, bytes_read;
+ unsigned int tex_ID = 0;
+ /* error checks */
+ if( NULL == filename )
+ {
+ result_string_pointer = "NULL filename";
+ return 0;
+ }
+ f = fopen( filename, "rb" );
+ if( NULL == f )
+ {
+ /* the file doesn't seem to exist (or be open-able) */
+ result_string_pointer = "Can not find DDS file";
+ return 0;
+ }
+ fseek( f, 0, SEEK_END );
+ buffer_length = ftell( f );
+ fseek( f, 0, SEEK_SET );
+ buffer = (unsigned char *) malloc( buffer_length );
+ if( NULL == buffer )
+ {
+ result_string_pointer = "malloc failed";
+ fclose( f );
+ return 0;
+ }
+ bytes_read = fread( (void*)buffer, 1, buffer_length, f );
+ fclose( f );
+ if( bytes_read < buffer_length )
+ {
+ /* huh? */
+ buffer_length = bytes_read;
+ }
+ /* now try to do the loading */
+ tex_ID = SOIL_direct_load_DDS_from_memory(
+ (const unsigned char *const)buffer, buffer_length,
+ reuse_texture_ID, flags, loading_as_cubemap );
+ SOIL_free_image_data( buffer );
+ return tex_ID;
+}
+
+int query_NPOT_capability( void )
+{
+ /* check for the capability */
+ if( has_NPOT_capability == SOIL_CAPABILITY_UNKNOWN )
+ {
+ /* we haven't yet checked for the capability, do so */
+ if(
+ (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
+ "GL_ARB_texture_non_power_of_two" ) )
+ )
+ {
+ /* not there, flag the failure */
+ has_NPOT_capability = SOIL_CAPABILITY_NONE;
+ } else
+ {
+ /* it's there! */
+ has_NPOT_capability = SOIL_CAPABILITY_PRESENT;
+ }
+ }
+ /* let the user know if we can do non-power-of-two textures or not */
+ return has_NPOT_capability;
+}
+
+int query_tex_rectangle_capability( void )
+{
+ /* check for the capability */
+ if( has_tex_rectangle_capability == SOIL_CAPABILITY_UNKNOWN )
+ {
+ /* we haven't yet checked for the capability, do so */
+ if(
+ (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
+ "GL_ARB_texture_rectangle" ) )
+ &&
+ (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
+ "GL_EXT_texture_rectangle" ) )
+ &&
+ (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
+ "GL_NV_texture_rectangle" ) )
+ )
+ {
+ /* not there, flag the failure */
+ has_tex_rectangle_capability = SOIL_CAPABILITY_NONE;
+ } else
+ {
+ /* it's there! */
+ has_tex_rectangle_capability = SOIL_CAPABILITY_PRESENT;
+ }
+ }
+ /* let the user know if we can do texture rectangles or not */
+ return has_tex_rectangle_capability;
+}
+
+int query_cubemap_capability( void )
+{
+ /* check for the capability */
+ if( has_cubemap_capability == SOIL_CAPABILITY_UNKNOWN )
+ {
+ /* we haven't yet checked for the capability, do so */
+ if(
+ (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
+ "GL_ARB_texture_cube_map" ) )
+ &&
+ (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
+ "GL_EXT_texture_cube_map" ) )
+ )
+ {
+ /* not there, flag the failure */
+ has_cubemap_capability = SOIL_CAPABILITY_NONE;
+ } else
+ {
+ /* it's there! */
+ has_cubemap_capability = SOIL_CAPABILITY_PRESENT;
+ }
+ }
+ /* let the user know if we can do cubemaps or not */
+ return has_cubemap_capability;
+}
+
+int query_DXT_capability( void )
+{
+ /* check for the capability */
+ if( has_DXT_capability == SOIL_CAPABILITY_UNKNOWN )
+ {
+ /* we haven't yet checked for the capability, do so */
+ if( NULL == strstr(
+ (char const*)glGetString( GL_EXTENSIONS ),
+ "GL_EXT_texture_compression_s3tc" ) )
+ {
+ /* not there, flag the failure */
+ has_DXT_capability = SOIL_CAPABILITY_NONE;
+ } else
+ {
+ /* and find the address of the extension function */
+ P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = NULL;
+ #ifdef WIN32
+ ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)
+ wglGetProcAddress
+ (
+ "glCompressedTexImage2DARB"
+ );
+ #elif defined(__APPLE__) || defined(__APPLE_CC__)
+ /* I can't test this Apple stuff! */
+ CFBundleRef bundle;
+ CFURLRef bundleURL =
+ CFURLCreateWithFileSystemPath(
+ kCFAllocatorDefault,
+ CFSTR("/System/Library/Frameworks/OpenGL.framework"),
+ kCFURLPOSIXPathStyle,
+ true );
+ CFStringRef extensionName =
+ CFStringCreateWithCString(
+ kCFAllocatorDefault,
+ "glCompressedTexImage2DARB",
+ kCFStringEncodingASCII );
+ bundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
+ assert( bundle != NULL );
+ ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)
+ CFBundleGetFunctionPointerForName
+ (
+ bundle, extensionName
+ );
+ CFRelease( bundleURL );
+ CFRelease( extensionName );
+ CFRelease( bundle );
+ #else
+ ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)
+ glXGetProcAddressARB
+ (
+ (const GLubyte *)"glCompressedTexImage2DARB"
+ );
+ #endif
+ /* Flag it so no checks needed later */
+ if( NULL == ext_addr )
+ {
+ /* hmm, not good!! This should not happen, but does on my
+ laptop's VIA chipset. The GL_EXT_texture_compression_s3tc
+ spec requires that ARB_texture_compression be present too.
+ this means I can upload and have the OpenGL drive do the
+ conversion, but I can't use my own routines or load DDS files
+ from disk and upload them directly [8^( */
+ has_DXT_capability = SOIL_CAPABILITY_NONE;
+ } else
+ {
+ /* all's well! */
+ soilGlCompressedTexImage2D = ext_addr;
+ has_DXT_capability = SOIL_CAPABILITY_PRESENT;
+ }
+ }
+ }
+ /* let the user know if we can do DXT or not */
+ return has_DXT_capability;
+}
diff --git a/Source/Core/VideoCommon/Src/SOIL/SOIL.h b/Source/Core/VideoCommon/Src/SOIL/SOIL.h
new file mode 100644
index 0000000000..57f375b734
--- /dev/null
+++ b/Source/Core/VideoCommon/Src/SOIL/SOIL.h
@@ -0,0 +1,433 @@
+/**
+ @mainpage SOIL
+
+ Jonathan Dummer
+ 2007-07-26-10.36
+
+ Simple OpenGL Image Library
+
+ A tiny c library for uploading images as
+ textures into OpenGL. Also saving and
+ loading of images is supported.
+
+ I'm using Sean's Tool Box image loader as a base:
+ http://www.nothings.org/
+
+ I'm upgrading it to load TGA and DDS files, and a direct
+ path for loading DDS files straight into OpenGL textures,
+ when applicable.
+
+ Image Formats:
+ - BMP load & save
+ - TGA load & save
+ - DDS load & save
+ - PNG load
+ - JPG load
+
+ OpenGL Texture Features:
+ - resample to power-of-two sizes
+ - MIPmap generation
+ - compressed texture S3TC formats (if supported)
+ - can pre-multiply alpha for you, for better compositing
+ - can flip image about the y-axis (except pre-compressed DDS files)
+
+ Thanks to:
+ * Sean Barret - for the awesome stb_image
+ * Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts
+ * everybody at gamedev.net
+**/
+
+#ifndef HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY
+#define HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ The format of images that may be loaded (force_channels).
+ SOIL_LOAD_AUTO leaves the image in whatever format it was found.
+ SOIL_LOAD_L forces the image to load as Luminous (greyscale)
+ SOIL_LOAD_LA forces the image to load as Luminous with Alpha
+ SOIL_LOAD_RGB forces the image to load as Red Green Blue
+ SOIL_LOAD_RGBA forces the image to load as Red Green Blue Alpha
+**/
+enum
+{
+ SOIL_LOAD_AUTO = 0,
+ SOIL_LOAD_L = 1,
+ SOIL_LOAD_LA = 2,
+ SOIL_LOAD_RGB = 3,
+ SOIL_LOAD_RGBA = 4
+};
+
+/**
+ Passed in as reuse_texture_ID, will cause SOIL to
+ register a new texture ID using glGenTextures().
+ If the value passed into reuse_texture_ID > 0 then
+ SOIL will just re-use that texture ID (great for
+ reloading image assets in-game!)
+**/
+enum
+{
+ SOIL_CREATE_NEW_ID = 0
+};
+
+/**
+ flags you can pass into SOIL_load_OGL_texture()
+ and SOIL_create_OGL_texture().
+ (note that if SOIL_FLAG_DDS_LOAD_DIRECT is used
+ the rest of the flags with the exception of
+ SOIL_FLAG_TEXTURE_REPEATS will be ignored while
+ loading already-compressed DDS files.)
+
+ SOIL_FLAG_POWER_OF_TWO: force the image to be POT
+ SOIL_FLAG_MIPMAPS: generate mipmaps for the texture
+ SOIL_FLAG_TEXTURE_REPEATS: otherwise will clamp
+ SOIL_FLAG_MULTIPLY_ALPHA: for using (GL_ONE,GL_ONE_MINUS_SRC_ALPHA) blending
+ SOIL_FLAG_INVERT_Y: flip the image vertically
+ SOIL_FLAG_COMPRESS_TO_DXT: if the card can display them, will convert RGB to DXT1, RGBA to DXT5
+ SOIL_FLAG_DDS_LOAD_DIRECT: will load DDS files directly without _ANY_ additional processing
+ SOIL_FLAG_NTSC_SAFE_RGB: clamps RGB components to the range [16,235]
+ SOIL_FLAG_CoCg_Y: Google YCoCg; RGB=>CoYCg, RGBA=>CoCgAY
+ SOIL_FLAG_TEXTURE_RECTANGE: uses ARB_texture_rectangle ; pixel indexed & no repeat or MIPmaps or cubemaps
+**/
+enum
+{
+ SOIL_FLAG_POWER_OF_TWO = 1,
+ SOIL_FLAG_MIPMAPS = 2,
+ SOIL_FLAG_TEXTURE_REPEATS = 4,
+ SOIL_FLAG_MULTIPLY_ALPHA = 8,
+ SOIL_FLAG_INVERT_Y = 16,
+ SOIL_FLAG_COMPRESS_TO_DXT = 32,
+ SOIL_FLAG_DDS_LOAD_DIRECT = 64,
+ SOIL_FLAG_NTSC_SAFE_RGB = 128,
+ SOIL_FLAG_CoCg_Y = 256,
+ SOIL_FLAG_TEXTURE_RECTANGLE = 512
+};
+
+/**
+ The types of images that may be saved.
+ (TGA supports uncompressed RGB / RGBA)
+ (BMP supports uncompressed RGB)
+ (DDS supports DXT1 and DXT5)
+**/
+enum
+{
+ SOIL_SAVE_TYPE_TGA = 0,
+ SOIL_SAVE_TYPE_BMP = 1,
+ SOIL_SAVE_TYPE_DDS = 2
+};
+
+/**
+ Defines the order of faces in a DDS cubemap.
+ I recommend that you use the same order in single
+ image cubemap files, so they will be interchangeable
+ with DDS cubemaps when using SOIL.
+**/
+#define SOIL_DDS_CUBEMAP_FACE_ORDER "EWUDNS"
+
+/**
+ The types of internal fake HDR representations
+
+ SOIL_HDR_RGBE: RGB * pow( 2.0, A - 128.0 )
+ SOIL_HDR_RGBdivA: RGB / A
+ SOIL_HDR_RGBdivA2: RGB / (A*A)
+**/
+enum
+{
+ SOIL_HDR_RGBE = 0,
+ SOIL_HDR_RGBdivA = 1,
+ SOIL_HDR_RGBdivA2 = 2
+};
+
+/**
+ Loads an image from disk into an OpenGL texture.
+ \param filename the name of the file to upload as a texture
+ \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA
+ \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)
+ \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT
+ \return 0-failed, otherwise returns the OpenGL texture handle
+**/
+unsigned int
+ SOIL_load_OGL_texture
+ (
+ const char *filename,
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ );
+
+/**
+ Loads 6 images from disk into an OpenGL cubemap texture.
+ \param x_pos_file the name of the file to upload as the +x cube face
+ \param x_neg_file the name of the file to upload as the -x cube face
+ \param y_pos_file the name of the file to upload as the +y cube face
+ \param y_neg_file the name of the file to upload as the -y cube face
+ \param z_pos_file the name of the file to upload as the +z cube face
+ \param z_neg_file the name of the file to upload as the -z cube face
+ \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA
+ \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)
+ \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT
+ \return 0-failed, otherwise returns the OpenGL texture handle
+**/
+unsigned int
+ SOIL_load_OGL_cubemap
+ (
+ const char *x_pos_file,
+ const char *x_neg_file,
+ const char *y_pos_file,
+ const char *y_neg_file,
+ const char *z_pos_file,
+ const char *z_neg_file,
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ );
+
+/**
+ Loads 1 image from disk and splits it into an OpenGL cubemap texture.
+ \param filename the name of the file to upload as a texture
+ \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc.
+ \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA
+ \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)
+ \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT
+ \return 0-failed, otherwise returns the OpenGL texture handle
+**/
+unsigned int
+ SOIL_load_OGL_single_cubemap
+ (
+ const char *filename,
+ const char face_order[6],
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ );
+
+/**
+ Loads an HDR image from disk into an OpenGL texture.
+ \param filename the name of the file to upload as a texture
+ \param fake_HDR_format SOIL_HDR_RGBE, SOIL_HDR_RGBdivA, SOIL_HDR_RGBdivA2
+ \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)
+ \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT
+ \return 0-failed, otherwise returns the OpenGL texture handle
+**/
+unsigned int
+ SOIL_load_OGL_HDR_texture
+ (
+ const char *filename,
+ int fake_HDR_format,
+ int rescale_to_max,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ );
+
+/**
+ Loads an image from RAM into an OpenGL texture.
+ \param buffer the image data in RAM just as if it were still in a file
+ \param buffer_length the size of the buffer in bytes
+ \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA
+ \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)
+ \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT
+ \return 0-failed, otherwise returns the OpenGL texture handle
+**/
+unsigned int
+ SOIL_load_OGL_texture_from_memory
+ (
+ const unsigned char *const buffer,
+ int buffer_length,
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ );
+
+/**
+ Loads 6 images from memory into an OpenGL cubemap texture.
+ \param x_pos_buffer the image data in RAM to upload as the +x cube face
+ \param x_pos_buffer_length the size of the above buffer
+ \param x_neg_buffer the image data in RAM to upload as the +x cube face
+ \param x_neg_buffer_length the size of the above buffer
+ \param y_pos_buffer the image data in RAM to upload as the +x cube face
+ \param y_pos_buffer_length the size of the above buffer
+ \param y_neg_buffer the image data in RAM to upload as the +x cube face
+ \param y_neg_buffer_length the size of the above buffer
+ \param z_pos_buffer the image data in RAM to upload as the +x cube face
+ \param z_pos_buffer_length the size of the above buffer
+ \param z_neg_buffer the image data in RAM to upload as the +x cube face
+ \param z_neg_buffer_length the size of the above buffer
+ \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA
+ \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)
+ \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT
+ \return 0-failed, otherwise returns the OpenGL texture handle
+**/
+unsigned int
+ SOIL_load_OGL_cubemap_from_memory
+ (
+ const unsigned char *const x_pos_buffer,
+ int x_pos_buffer_length,
+ const unsigned char *const x_neg_buffer,
+ int x_neg_buffer_length,
+ const unsigned char *const y_pos_buffer,
+ int y_pos_buffer_length,
+ const unsigned char *const y_neg_buffer,
+ int y_neg_buffer_length,
+ const unsigned char *const z_pos_buffer,
+ int z_pos_buffer_length,
+ const unsigned char *const z_neg_buffer,
+ int z_neg_buffer_length,
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ );
+
+/**
+ Loads 1 image from RAM and splits it into an OpenGL cubemap texture.
+ \param buffer the image data in RAM just as if it were still in a file
+ \param buffer_length the size of the buffer in bytes
+ \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc.
+ \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA
+ \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)
+ \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT
+ \return 0-failed, otherwise returns the OpenGL texture handle
+**/
+unsigned int
+ SOIL_load_OGL_single_cubemap_from_memory
+ (
+ const unsigned char *const buffer,
+ int buffer_length,
+ const char face_order[6],
+ int force_channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ );
+
+/**
+ Creates a 2D OpenGL texture from raw image data. Note that the raw data is
+ _NOT_ freed after the upload (so the user can load various versions).
+ \param data the raw data to be uploaded as an OpenGL texture
+ \param width the width of the image in pixels
+ \param height the height of the image in pixels
+ \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA
+ \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)
+ \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT
+ \return 0-failed, otherwise returns the OpenGL texture handle
+**/
+unsigned int
+ SOIL_create_OGL_texture
+ (
+ const unsigned char *const data,
+ int width, int height, int channels,
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ );
+
+/**
+ Creates an OpenGL cubemap texture by splitting up 1 image into 6 parts.
+ \param data the raw data to be uploaded as an OpenGL texture
+ \param width the width of the image in pixels
+ \param height the height of the image in pixels
+ \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA
+ \param face_order the order of the faces in the file, and combination of NSWEUD, for North, South, Up, etc.
+ \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)
+ \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT
+ \return 0-failed, otherwise returns the OpenGL texture handle
+**/
+unsigned int
+ SOIL_create_OGL_single_cubemap
+ (
+ const unsigned char *const data,
+ int width, int height, int channels,
+ const char face_order[6],
+ unsigned int reuse_texture_ID,
+ unsigned int flags
+ );
+
+/**
+ Captures the OpenGL window (RGB) and saves it to disk
+ \return 0 if it failed, otherwise returns 1
+**/
+int
+ SOIL_save_screenshot
+ (
+ const char *filename,
+ int image_type,
+ int x, int y,
+ int width, int height
+ );
+
+/**
+ Loads an image from disk into an array of unsigned chars.
+ Note that *channels return the original channel count of the
+ image. If force_channels was other than SOIL_LOAD_AUTO,
+ the resulting image has force_channels, but *channels may be
+ different (if the original image had a different channel
+ count).
+ \return 0 if failed, otherwise returns 1
+**/
+unsigned char*
+ SOIL_load_image
+ (
+ const char *filename,
+ int *width, int *height, int *channels,
+ int force_channels
+ );
+
+/**
+ Loads an image from memory into an array of unsigned chars.
+ Note that *channels return the original channel count of the
+ image. If force_channels was other than SOIL_LOAD_AUTO,
+ the resulting image has force_channels, but *channels may be
+ different (if the original image had a different channel
+ count).
+ \return 0 if failed, otherwise returns 1
+**/
+unsigned char*
+ SOIL_load_image_from_memory
+ (
+ const unsigned char *const buffer,
+ int buffer_length,
+ int *width, int *height, int *channels,
+ int force_channels
+ );
+
+/**
+ Saves an image from an array of unsigned chars (RGBA) to disk
+ \return 0 if failed, otherwise returns 1
+**/
+int
+ SOIL_save_image
+ (
+ const char *filename,
+ int image_type,
+ int width, int height, int channels,
+ const unsigned char *const data
+ );
+
+/**
+ Frees the image data (note, this is just C's "free()"...this function is
+ present mostly so C++ programmers don't forget to use "free()" and call
+ "delete []" instead [8^)
+**/
+void
+ SOIL_free_image_data
+ (
+ unsigned char *img_data
+ );
+
+/**
+ This function resturn a pointer to a string describing the last thing
+ that happened inside SOIL. It can be used to determine why an image
+ failed to load.
+**/
+const char*
+ SOIL_last_result
+ (
+ void
+ );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY */
diff --git a/Source/Core/VideoCommon/Src/SOIL/image_DXT.h b/Source/Core/VideoCommon/Src/SOIL/image_DXT.h
new file mode 100644
index 0000000000..ce7716425c
--- /dev/null
+++ b/Source/Core/VideoCommon/Src/SOIL/image_DXT.h
@@ -0,0 +1,123 @@
+/*
+ Jonathan Dummer
+ 2007-07-31-10.32
+
+ simple DXT compression / decompression code
+
+ public domain
+*/
+
+#ifndef HEADER_IMAGE_DXT
+#define HEADER_IMAGE_DXT
+
+/**
+ Converts an image from an array of unsigned chars (RGB or RGBA) to
+ DXT1 or DXT5, then saves the converted image to disk.
+ \return 0 if failed, otherwise returns 1
+**/
+int
+save_image_as_DDS
+(
+ const char *filename,
+ int width, int height, int channels,
+ const unsigned char *const data
+);
+
+/**
+ take an image and convert it to DXT1 (no alpha)
+**/
+unsigned char*
+convert_image_to_DXT1
+(
+ const unsigned char *const uncompressed,
+ int width, int height, int channels,
+ int *out_size
+);
+
+/**
+ take an image and convert it to DXT5 (with alpha)
+**/
+unsigned char*
+convert_image_to_DXT5
+(
+ const unsigned char *const uncompressed,
+ int width, int height, int channels,
+ int *out_size
+);
+
+/** A bunch of DirectDraw Surface structures and flags **/
+typedef struct
+{
+ unsigned int dwMagic;
+ unsigned int dwSize;
+ unsigned int dwFlags;
+ unsigned int dwHeight;
+ unsigned int dwWidth;
+ unsigned int dwPitchOrLinearSize;
+ unsigned int dwDepth;
+ unsigned int dwMipMapCount;
+ unsigned int dwReserved1[ 11 ];
+
+ /* DDPIXELFORMAT */
+ struct
+ {
+ unsigned int dwSize;
+ unsigned int dwFlags;
+ unsigned int dwFourCC;
+ unsigned int dwRGBBitCount;
+ unsigned int dwRBitMask;
+ unsigned int dwGBitMask;
+ unsigned int dwBBitMask;
+ unsigned int dwAlphaBitMask;
+ }
+ sPixelFormat;
+
+ /* DDCAPS2 */
+ struct
+ {
+ unsigned int dwCaps1;
+ unsigned int dwCaps2;
+ unsigned int dwDDSX;
+ unsigned int dwReserved;
+ }
+ sCaps;
+ unsigned int dwReserved2;
+}
+DDS_header ;
+
+/* the following constants were copied directly off the MSDN website */
+
+/* The dwFlags member of the original DDSURFACEDESC2 structure
+ can be set to one or more of the following values. */
+#define DDSD_CAPS 0x00000001
+#define DDSD_HEIGHT 0x00000002
+#define DDSD_WIDTH 0x00000004
+#define DDSD_PITCH 0x00000008
+#define DDSD_PIXELFORMAT 0x00001000
+#define DDSD_MIPMAPCOUNT 0x00020000
+#define DDSD_LINEARSIZE 0x00080000
+#define DDSD_DEPTH 0x00800000
+
+/* DirectDraw Pixel Format */
+#define DDPF_ALPHAPIXELS 0x00000001
+#define DDPF_FOURCC 0x00000004
+#define DDPF_RGB 0x00000040
+
+/* The dwCaps1 member of the DDSCAPS2 structure can be
+ set to one or more of the following values. */
+#define DDSCAPS_COMPLEX 0x00000008
+#define DDSCAPS_TEXTURE 0x00001000
+#define DDSCAPS_MIPMAP 0x00400000
+
+/* The dwCaps2 member of the DDSCAPS2 structure can be
+ set to one or more of the following values. */
+#define DDSCAPS2_CUBEMAP 0x00000200
+#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
+#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
+#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
+#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
+#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
+#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
+#define DDSCAPS2_VOLUME 0x00200000
+
+#endif /* HEADER_IMAGE_DXT */
diff --git a/Source/Core/VideoCommon/Src/SOIL/image_helper.h b/Source/Core/VideoCommon/Src/SOIL/image_helper.h
new file mode 100644
index 0000000000..abb257c342
--- /dev/null
+++ b/Source/Core/VideoCommon/Src/SOIL/image_helper.h
@@ -0,0 +1,115 @@
+/*
+ Jonathan Dummer
+
+ Image helper functions
+
+ MIT license
+*/
+
+#ifndef HEADER_IMAGE_HELPER
+#define HEADER_IMAGE_HELPER
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ This function upscales an image.
+ Not to be used to create MIPmaps,
+ but to make it square,
+ or to make it a power-of-two sized.
+**/
+int
+ up_scale_image
+ (
+ const unsigned char* const orig,
+ int width, int height, int channels,
+ unsigned char* resampled,
+ int resampled_width, int resampled_height
+ );
+
+/**
+ This function downscales an image.
+ Used for creating MIPmaps,
+ the incoming image should be a
+ power-of-two sized.
+**/
+int
+ mipmap_image
+ (
+ const unsigned char* const orig,
+ int width, int height, int channels,
+ unsigned char* resampled,
+ int block_size_x, int block_size_y
+ );
+
+/**
+ This function takes the RGB components of the image
+ and scales each channel from [0,255] to [16,235].
+ This makes the colors "Safe" for display on NTSC
+ displays. Note that this is _NOT_ a good idea for
+ loading images like normal- or height-maps!
+**/
+int
+ scale_image_RGB_to_NTSC_safe
+ (
+ unsigned char* orig,
+ int width, int height, int channels
+ );
+
+/**
+ This function takes the RGB components of the image
+ and converts them into YCoCg. 3 components will be
+ re-ordered to CoYCg (for optimum DXT1 compression),
+ while 4 components will be ordered CoCgAY (for DXT5
+ compression).
+**/
+int
+ convert_RGB_to_YCoCg
+ (
+ unsigned char* orig,
+ int width, int height, int channels
+ );
+
+/**
+ This function takes the YCoCg components of the image
+ and converts them into RGB. See above.
+**/
+int
+ convert_YCoCg_to_RGB
+ (
+ unsigned char* orig,
+ int width, int height, int channels
+ );
+
+/**
+ Converts an HDR image from an array
+ of unsigned chars (RGBE) to RGBdivA
+ \return 0 if failed, otherwise returns 1
+**/
+int
+ RGBE_to_RGBdivA
+ (
+ unsigned char *image,
+ int width, int height,
+ int rescale_to_max
+ );
+
+/**
+ Converts an HDR image from an array
+ of unsigned chars (RGBE) to RGBdivA2
+ \return 0 if failed, otherwise returns 1
+**/
+int
+ RGBE_to_RGBdivA2
+ (
+ unsigned char *image,
+ int width, int height,
+ int rescale_to_max
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HEADER_IMAGE_HELPER */
diff --git a/Source/Core/VideoCommon/Src/SOIL/stbi_DDS_aug.h b/Source/Core/VideoCommon/Src/SOIL/stbi_DDS_aug.h
new file mode 100644
index 0000000000..98f7b65341
--- /dev/null
+++ b/Source/Core/VideoCommon/Src/SOIL/stbi_DDS_aug.h
@@ -0,0 +1,21 @@
+/*
+ adding DDS loading support to stbi
+*/
+
+#ifndef HEADER_STB_IMAGE_DDS_AUGMENTATION
+#define HEADER_STB_IMAGE_DDS_AUGMENTATION
+
+// is it a DDS file?
+extern int stbi_dds_test_memory (stbi_uc const *buffer, int len);
+
+extern stbi_uc *stbi_dds_load (char *filename, int *x, int *y, int *comp, int req_comp);
+extern stbi_uc *stbi_dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
+#ifndef STBI_NO_STDIO
+extern int stbi_dds_test_file (FILE *f);
+extern stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
+#endif
+
+//
+//
+//// end header file /////////////////////////////////////////////////////
+#endif // HEADER_STB_IMAGE_DDS_AUGMENTATION
diff --git a/Source/Core/VideoCommon/Src/SOIL/stbi_DDS_aug_c.h b/Source/Core/VideoCommon/Src/SOIL/stbi_DDS_aug_c.h
new file mode 100644
index 0000000000..683d1cf0b7
--- /dev/null
+++ b/Source/Core/VideoCommon/Src/SOIL/stbi_DDS_aug_c.h
@@ -0,0 +1,511 @@
+
+/// DDS file support, does decoding, _not_ direct uploading
+/// (use SOIL for that ;-)
+
+/// A bunch of DirectDraw Surface structures and flags
+typedef struct {
+ unsigned int dwMagic;
+ unsigned int dwSize;
+ unsigned int dwFlags;
+ unsigned int dwHeight;
+ unsigned int dwWidth;
+ unsigned int dwPitchOrLinearSize;
+ unsigned int dwDepth;
+ unsigned int dwMipMapCount;
+ unsigned int dwReserved1[ 11 ];
+
+ // DDPIXELFORMAT
+ struct {
+ unsigned int dwSize;
+ unsigned int dwFlags;
+ unsigned int dwFourCC;
+ unsigned int dwRGBBitCount;
+ unsigned int dwRBitMask;
+ unsigned int dwGBitMask;
+ unsigned int dwBBitMask;
+ unsigned int dwAlphaBitMask;
+ } sPixelFormat;
+
+ // DDCAPS2
+ struct {
+ unsigned int dwCaps1;
+ unsigned int dwCaps2;
+ unsigned int dwDDSX;
+ unsigned int dwReserved;
+ } sCaps;
+ unsigned int dwReserved2;
+} DDS_header ;
+
+// the following constants were copied directly off the MSDN website
+
+// The dwFlags member of the original DDSURFACEDESC2 structure
+// can be set to one or more of the following values.
+#define DDSD_CAPS 0x00000001
+#define DDSD_HEIGHT 0x00000002
+#define DDSD_WIDTH 0x00000004
+#define DDSD_PITCH 0x00000008
+#define DDSD_PIXELFORMAT 0x00001000
+#define DDSD_MIPMAPCOUNT 0x00020000
+#define DDSD_LINEARSIZE 0x00080000
+#define DDSD_DEPTH 0x00800000
+
+// DirectDraw Pixel Format
+#define DDPF_ALPHAPIXELS 0x00000001
+#define DDPF_FOURCC 0x00000004
+#define DDPF_RGB 0x00000040
+
+// The dwCaps1 member of the DDSCAPS2 structure can be
+// set to one or more of the following values.
+#define DDSCAPS_COMPLEX 0x00000008
+#define DDSCAPS_TEXTURE 0x00001000
+#define DDSCAPS_MIPMAP 0x00400000
+
+// The dwCaps2 member of the DDSCAPS2 structure can be
+// set to one or more of the following values.
+#define DDSCAPS2_CUBEMAP 0x00000200
+#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
+#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
+#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
+#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
+#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
+#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
+#define DDSCAPS2_VOLUME 0x00200000
+
+static int dds_test(stbi *s)
+{
+ // check the magic number
+ if (get8(s) != 'D') return 0;
+ if (get8(s) != 'D') return 0;
+ if (get8(s) != 'S') return 0;
+ if (get8(s) != ' ') return 0;
+ // check header size
+ if (get32le(s) != 124) return 0;
+ return 1;
+}
+#ifndef STBI_NO_STDIO
+int stbi_dds_test_file (FILE *f)
+{
+ stbi s;
+ int r,n = ftell(f);
+ start_file(&s,f);
+ r = dds_test(&s);
+ fseek(f,n,SEEK_SET);
+ return r;
+}
+#endif
+
+int stbi_dds_test_memory (stbi_uc const *buffer, int len)
+{
+ stbi s;
+ start_mem(&s,buffer, len);
+ return dds_test(&s);
+}
+
+// helper functions
+int stbi_convert_bit_range( int c, int from_bits, int to_bits )
+{
+ int b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1);
+ return (b + (b >> from_bits)) >> from_bits;
+}
+void stbi_rgb_888_from_565( unsigned int c, int *r, int *g, int *b )
+{
+ *r = stbi_convert_bit_range( (c >> 11) & 31, 5, 8 );
+ *g = stbi_convert_bit_range( (c >> 05) & 63, 6, 8 );
+ *b = stbi_convert_bit_range( (c >> 00) & 31, 5, 8 );
+}
+void stbi_decode_DXT1_block(
+ unsigned char uncompressed[16*4],
+ unsigned char compressed[8] )
+{
+ int next_bit = 4*8;
+ int i, r, g, b;
+ int c0, c1;
+ unsigned char decode_colors[4*4];
+ // find the 2 primary colors
+ c0 = compressed[0] + (compressed[1] << 8);
+ c1 = compressed[2] + (compressed[3] << 8);
+ stbi_rgb_888_from_565( c0, &r, &g, &b );
+ decode_colors[0] = r;
+ decode_colors[1] = g;
+ decode_colors[2] = b;
+ decode_colors[3] = 255;
+ stbi_rgb_888_from_565( c1, &r, &g, &b );
+ decode_colors[4] = r;
+ decode_colors[5] = g;
+ decode_colors[6] = b;
+ decode_colors[7] = 255;
+ if( c0 > c1 )
+ {
+ // no alpha, 2 interpolated colors
+ decode_colors[8] = (2*decode_colors[0] + decode_colors[4]) / 3;
+ decode_colors[9] = (2*decode_colors[1] + decode_colors[5]) / 3;
+ decode_colors[10] = (2*decode_colors[2] + decode_colors[6]) / 3;
+ decode_colors[11] = 255;
+ decode_colors[12] = (decode_colors[0] + 2*decode_colors[4]) / 3;
+ decode_colors[13] = (decode_colors[1] + 2*decode_colors[5]) / 3;
+ decode_colors[14] = (decode_colors[2] + 2*decode_colors[6]) / 3;
+ decode_colors[15] = 255;
+ } else
+ {
+ // 1 interpolated color, alpha
+ decode_colors[8] = (decode_colors[0] + decode_colors[4]) / 2;
+ decode_colors[9] = (decode_colors[1] + decode_colors[5]) / 2;
+ decode_colors[10] = (decode_colors[2] + decode_colors[6]) / 2;
+ decode_colors[11] = 255;
+ decode_colors[12] = 0;
+ decode_colors[13] = 0;
+ decode_colors[14] = 0;
+ decode_colors[15] = 0;
+ }
+ // decode the block
+ for( i = 0; i < 16*4; i += 4 )
+ {
+ int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 4;
+ next_bit += 2;
+ uncompressed[i+0] = decode_colors[idx+0];
+ uncompressed[i+1] = decode_colors[idx+1];
+ uncompressed[i+2] = decode_colors[idx+2];
+ uncompressed[i+3] = decode_colors[idx+3];
+ }
+ // done
+}
+void stbi_decode_DXT23_alpha_block(
+ unsigned char uncompressed[16*4],
+ unsigned char compressed[8] )
+{
+ int i, next_bit = 0;
+ // each alpha value gets 4 bits
+ for( i = 3; i < 16*4; i += 4 )
+ {
+ uncompressed[i] = stbi_convert_bit_range(
+ (compressed[next_bit>>3] >> (next_bit&7)) & 15,
+ 4, 8 );
+ next_bit += 4;
+ }
+}
+void stbi_decode_DXT45_alpha_block(
+ unsigned char uncompressed[16*4],
+ unsigned char compressed[8] )
+{
+ int i, next_bit = 8*2;
+ unsigned char decode_alpha[8];
+ // each alpha value gets 3 bits, and the 1st 2 bytes are the range
+ decode_alpha[0] = compressed[0];
+ decode_alpha[1] = compressed[1];
+ if( decode_alpha[0] > decode_alpha[1] )
+ {
+ // 6 step intermediate
+ decode_alpha[2] = (6*decode_alpha[0] + 1*decode_alpha[1]) / 7;
+ decode_alpha[3] = (5*decode_alpha[0] + 2*decode_alpha[1]) / 7;
+ decode_alpha[4] = (4*decode_alpha[0] + 3*decode_alpha[1]) / 7;
+ decode_alpha[5] = (3*decode_alpha[0] + 4*decode_alpha[1]) / 7;
+ decode_alpha[6] = (2*decode_alpha[0] + 5*decode_alpha[1]) / 7;
+ decode_alpha[7] = (1*decode_alpha[0] + 6*decode_alpha[1]) / 7;
+ } else
+ {
+ // 4 step intermediate, pluss full and none
+ decode_alpha[2] = (4*decode_alpha[0] + 1*decode_alpha[1]) / 5;
+ decode_alpha[3] = (3*decode_alpha[0] + 2*decode_alpha[1]) / 5;
+ decode_alpha[4] = (2*decode_alpha[0] + 3*decode_alpha[1]) / 5;
+ decode_alpha[5] = (1*decode_alpha[0] + 4*decode_alpha[1]) / 5;
+ decode_alpha[6] = 0;
+ decode_alpha[7] = 255;
+ }
+ for( i = 3; i < 16*4; i += 4 )
+ {
+ int idx = 0, bit;
+ bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1;
+ idx += bit << 0;
+ ++next_bit;
+ bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1;
+ idx += bit << 1;
+ ++next_bit;
+ bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1;
+ idx += bit << 2;
+ ++next_bit;
+ uncompressed[i] = decode_alpha[idx & 7];
+ }
+ // done
+}
+void stbi_decode_DXT_color_block(
+ unsigned char uncompressed[16*4],
+ unsigned char compressed[8] )
+{
+ int next_bit = 4*8;
+ int i, r, g, b;
+ int c0, c1;
+ unsigned char decode_colors[4*3];
+ // find the 2 primary colors
+ c0 = compressed[0] + (compressed[1] << 8);
+ c1 = compressed[2] + (compressed[3] << 8);
+ stbi_rgb_888_from_565( c0, &r, &g, &b );
+ decode_colors[0] = r;
+ decode_colors[1] = g;
+ decode_colors[2] = b;
+ stbi_rgb_888_from_565( c1, &r, &g, &b );
+ decode_colors[3] = r;
+ decode_colors[4] = g;
+ decode_colors[5] = b;
+ // Like DXT1, but no choicees:
+ // no alpha, 2 interpolated colors
+ decode_colors[6] = (2*decode_colors[0] + decode_colors[3]) / 3;
+ decode_colors[7] = (2*decode_colors[1] + decode_colors[4]) / 3;
+ decode_colors[8] = (2*decode_colors[2] + decode_colors[5]) / 3;
+ decode_colors[9] = (decode_colors[0] + 2*decode_colors[3]) / 3;
+ decode_colors[10] = (decode_colors[1] + 2*decode_colors[4]) / 3;
+ decode_colors[11] = (decode_colors[2] + 2*decode_colors[5]) / 3;
+ // decode the block
+ for( i = 0; i < 16*4; i += 4 )
+ {
+ int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 3;
+ next_bit += 2;
+ uncompressed[i+0] = decode_colors[idx+0];
+ uncompressed[i+1] = decode_colors[idx+1];
+ uncompressed[i+2] = decode_colors[idx+2];
+ }
+ // done
+}
+static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+ // all variables go up front
+ stbi_uc *dds_data = NULL;
+ stbi_uc block[16*4];
+ stbi_uc compressed[8];
+ int flags, DXT_family;
+ int has_alpha, has_mipmap;
+ int is_compressed, cubemap_faces;
+ int block_pitch, num_blocks;
+ DDS_header header;
+ int i, sz, cf;
+ // load the header
+ if( sizeof( DDS_header ) != 128 )
+ {
+ return NULL;
+ }
+ getn( s, (stbi_uc*)(&header), 128 );
+ // and do some checking
+ if( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) return NULL;
+ if( header.dwSize != 124 ) return NULL;
+ flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
+ if( (header.dwFlags & flags) != flags ) return NULL;
+ /* According to the MSDN spec, the dwFlags should contain
+ DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if
+ uncompressed. Some DDS writers do not conform to the
+ spec, so I need to make my reader more tolerant */
+ if( header.sPixelFormat.dwSize != 32 ) return NULL;
+ flags = DDPF_FOURCC | DDPF_RGB;
+ if( (header.sPixelFormat.dwFlags & flags) == 0 ) return NULL;
+ if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) return NULL;
+ // get the image data
+ s->img_x = header.dwWidth;
+ s->img_y = header.dwHeight;
+ s->img_n = 4;
+ is_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC;
+ has_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS;
+ has_mipmap = (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1);
+ cubemap_faces = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP;
+ /* I need cubemaps to have square faces */
+ cubemap_faces &= (s->img_x == s->img_y);
+ cubemap_faces *= 5;
+ cubemap_faces += 1;
+ block_pitch = (s->img_x+3) >> 2;
+ num_blocks = block_pitch * ((s->img_y+3) >> 2);
+ /* let the user know what's going on */
+ *x = s->img_x;
+ *y = s->img_y;
+ *comp = s->img_n;
+ /* is this uncompressed? */
+ if( is_compressed )
+ {
+ /* compressed */
+ // note: header.sPixelFormat.dwFourCC is something like (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24))
+ DXT_family = 1 + (header.sPixelFormat.dwFourCC >> 24) - '1';
+ if( (DXT_family < 1) || (DXT_family > 5) ) return NULL;
+ /* check the expected size...oops, nevermind...
+ those non-compliant writers leave
+ dwPitchOrLinearSize == 0 */
+ // passed all the tests, get the RAM for decoding
+ sz = (s->img_x)*(s->img_y)*4*cubemap_faces;
+ dds_data = (unsigned char*)malloc( sz );
+ /* do this once for each face */
+ for( cf = 0; cf < cubemap_faces; ++ cf )
+ {
+ // now read and decode all the blocks
+ for( i = 0; i < num_blocks; ++i )
+ {
+ // where are we?
+ int bx, by, bw=4, bh=4;
+ int ref_x = 4 * (i % block_pitch);
+ int ref_y = 4 * (i / block_pitch);
+ // get the next block's worth of compressed data, and decompress it
+ if( DXT_family == 1 )
+ {
+ // DXT1
+ getn( s, compressed, 8 );
+ stbi_decode_DXT1_block( block, compressed );
+ } else if( DXT_family < 4 )
+ {
+ // DXT2/3
+ getn( s, compressed, 8 );
+ stbi_decode_DXT23_alpha_block ( block, compressed );
+ getn( s, compressed, 8 );
+ stbi_decode_DXT_color_block ( block, compressed );
+ } else
+ {
+ // DXT4/5
+ getn( s, compressed, 8 );
+ stbi_decode_DXT45_alpha_block ( block, compressed );
+ getn( s, compressed, 8 );
+ stbi_decode_DXT_color_block ( block, compressed );
+ }
+ // is this a partial block?
+ if( ref_x + 4 > s->img_x )
+ {
+ bw = s->img_x - ref_x;
+ }
+ if( ref_y + 4 > s->img_y )
+ {
+ bh = s->img_y - ref_y;
+ }
+ // now drop our decompressed data into the buffer
+ for( by = 0; by < bh; ++by )
+ {
+ int idx = 4*((ref_y+by+cf*s->img_x)*s->img_x + ref_x);
+ for( bx = 0; bx < bw*4; ++bx )
+ {
+
+ dds_data[idx+bx] = block[by*16+bx];
+ }
+ }
+ }
+ /* done reading and decoding the main image...
+ skip MIPmaps if present */
+ if( has_mipmap )
+ {
+ int block_size = 16;
+ if( DXT_family == 1 )
+ {
+ block_size = 8;
+ }
+ for( i = 1; i < header.dwMipMapCount; ++i )
+ {
+ int mx = s->img_x >> (i + 2);
+ int my = s->img_y >> (i + 2);
+ if( mx < 1 )
+ {
+ mx = 1;
+ }
+ if( my < 1 )
+ {
+ my = 1;
+ }
+ skip( s, mx*my*block_size );
+ }
+ }
+ }/* per cubemap face */
+ } else
+ {
+ /* uncompressed */
+ DXT_family = 0;
+ s->img_n = 3;
+ if( has_alpha )
+ {
+ s->img_n = 4;
+ }
+ *comp = s->img_n;
+ sz = s->img_x*s->img_y*s->img_n*cubemap_faces;
+ dds_data = (unsigned char*)malloc( sz );
+ /* do this once for each face */
+ for( cf = 0; cf < cubemap_faces; ++ cf )
+ {
+ /* read the main image for this face */
+ getn( s, &dds_data[cf*s->img_x*s->img_y*s->img_n], s->img_x*s->img_y*s->img_n );
+ /* done reading and decoding the main image...
+ skip MIPmaps if present */
+ if( has_mipmap )
+ {
+ for( i = 1; i < header.dwMipMapCount; ++i )
+ {
+ int mx = s->img_x >> i;
+ int my = s->img_y >> i;
+ if( mx < 1 )
+ {
+ mx = 1;
+ }
+ if( my < 1 )
+ {
+ my = 1;
+ }
+ skip( s, mx*my*s->img_n );
+ }
+ }
+ }
+ /* data was BGR, I need it RGB */
+ for( i = 0; i < sz; i += s->img_n )
+ {
+ unsigned char temp = dds_data[i];
+ dds_data[i] = dds_data[i+2];
+ dds_data[i+2] = temp;
+ }
+ }
+ /* finished decompressing into RGBA,
+ adjust the y size if we have a cubemap
+ note: sz is already up to date */
+ s->img_y *= cubemap_faces;
+ *y = s->img_y;
+ // did the user want something else, or
+ // see if all the alpha values are 255 (i.e. no transparency)
+ has_alpha = 0;
+ if( s->img_n == 4)
+ {
+ for( i = 3; (i < sz) && (has_alpha == 0); i += 4 )
+ {
+ has_alpha |= (dds_data[i] < 255);
+ }
+ }
+ if( (req_comp <= 4) && (req_comp >= 1) )
+ {
+ // user has some requirements, meet them
+ if( req_comp != s->img_n )
+ {
+ dds_data = convert_format( dds_data, s->img_n, req_comp, s->img_x, s->img_y );
+ *comp = s->img_n;
+ }
+ } else
+ {
+ // user had no requirements, only drop to RGB is no alpha
+ if( (has_alpha == 0) && (s->img_n == 4) )
+ {
+ dds_data = convert_format( dds_data, 4, 3, s->img_x, s->img_y );
+ *comp = 3;
+ }
+ }
+ // OK, done
+ return dds_data;
+}
+
+#ifndef STBI_NO_STDIO
+stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ stbi s;
+ start_file(&s,f);
+ return dds_load(&s,x,y,comp,req_comp);
+}
+
+stbi_uc *stbi_dds_load (char *filename, int *x, int *y, int *comp, int req_comp)
+{
+ stbi_uc *data;
+ FILE *f = fopen(filename, "rb");
+ if (!f) return NULL;
+ data = stbi_dds_load_from_file(f,x,y,comp,req_comp);
+ fclose(f);
+ return data;
+}
+#endif
+
+stbi_uc *stbi_dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+ stbi s;
+ start_mem(&s,buffer, len);
+ return dds_load(&s,x,y,comp,req_comp);
+}
diff --git a/Source/Core/VideoCommon/Src/TextureDecoder.h b/Source/Core/VideoCommon/Src/TextureDecoder.h
index 7995dbda0a..fe6cf169ce 100644
--- a/Source/Core/VideoCommon/Src/TextureDecoder.h
+++ b/Source/Core/VideoCommon/Src/TextureDecoder.h
@@ -73,6 +73,7 @@ enum PC_TexFormat
{
PC_TEX_FMT_NONE = 0,
PC_TEX_FMT_BGRA32,
+ PC_TEX_FMT_RGBA32,
PC_TEX_FMT_IA4,
PC_TEX_FMT_I8,
PC_TEX_FMT_IA8,
diff --git a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp
index 3e6db1acbf..5bb2c4d9a4 100644
--- a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp
+++ b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp
@@ -263,12 +263,7 @@ void VertexShaderManager::SetConstants(bool proj_hax_1,bool SMG_hack, bool freeL
g_fProjectionMatrix[9] = 0.0f;
g_fProjectionMatrix[10] = xfregs.rawProjection[4];
- if (SMG_hack) {
- g_fProjectionMatrix[11] = -(0.512505f + xfregs.rawProjection[5]) + (proj_hax_1 ? 0.1f : 0.0f);
- }
- else {
- g_fProjectionMatrix[11] = xfregs.rawProjection[5] + (proj_hax_1 ? 0.1f : 0.0f);
- }
+ g_fProjectionMatrix[11] = (SMG_hack ? -(0.512505f + xfregs.rawProjection[5]) : xfregs.rawProjection[5]) + (proj_hax_1 ? 0.1f : 0.0f);
g_fProjectionMatrix[12] = 0.0f;
g_fProjectionMatrix[13] = 0.0f;
diff --git a/Source/Core/VideoCommon/VideoCommon.vcproj b/Source/Core/VideoCommon/VideoCommon.vcproj
index a297dae3fc..c1d28c3172 100644
--- a/Source/Core/VideoCommon/VideoCommon.vcproj
+++ b/Source/Core/VideoCommon/VideoCommon.vcproj
@@ -609,6 +609,50 @@
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -633,6 +677,14 @@
RelativePath=".\Src\Fifo.h"
>
+
+
+
+
diff --git a/Source/Dolphin.sln b/Source/Dolphin.sln
index 7f53d39f89..880cac03ed 100644
--- a/Source/Dolphin.sln
+++ b/Source/Dolphin.sln
@@ -1,5 +1,5 @@
Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
+# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Core", "Core\Core\Core.vcproj", "{F0B874CB-4476-4199-9315-8343D05AE684}"
ProjectSection(ProjectDependencies) = postProject
{C7E5D50A-2916-464B-86A7-E10B3CC88ADA} = {C7E5D50A-2916-464B-86A7-E10B3CC88ADA}
diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp
index 7f038a3d58..ccd956d4b4 100644
--- a/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp
+++ b/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp
@@ -60,6 +60,7 @@ void Config::Load()
iniFile.Get("Settings", "ShowEFBCopyRegions", &bShowEFBCopyRegions, false);
iniFile.Get("Settings", "DLOptimize", &iCompileDLsLevel, 0);
iniFile.Get("Settings", "DumpTextures", &bDumpTextures, 0);
+ iniFile.Get("Settings", "HiresTextures", &bHiresTextures, 0);
iniFile.Get("Settings", "DumpEFBTarget", &bDumpEFBTarget, 0);
iniFile.Get("Settings", "DumpFrames", &bDumpFrames, 0);
iniFile.Get("Settings", "FreeLook", &bFreeLook, 0);
@@ -110,6 +111,9 @@ void Config::GameIniLoad() {
if (iniFile->Exists("Video", "SafeTextureCache"))
iniFile->Get("Video", "SafeTextureCache", &bSafeTextureCache, false);
+ if (iniFile->Exists("Video", "SMGhack"))
+ iniFile->Get("Video", "SMGhack", &bSMGhack, false);
+
if (iniFile->Exists("Video", "MSAA"))
iniFile->Get("Video", "MSAA", &iMultisampleMode, 0);
@@ -146,6 +150,7 @@ void Config::Save()
iniFile.Set("Settings", "DLOptimize", iCompileDLsLevel);
iniFile.Set("Settings", "Show", iCompileDLsLevel);
iniFile.Set("Settings", "DumpTextures", bDumpTextures);
+ iniFile.Set("Settings", "HiresTextures", bHiresTextures);
iniFile.Set("Settings", "DumpEFBTarget", bDumpEFBTarget);
iniFile.Set("Settings", "DumpFrames", bDumpFrames);
iniFile.Set("Settings", "FreeLook", bFreeLook);
@@ -167,6 +172,7 @@ void Config::Save()
iniFile.Set("Hacks", "EFBCopyDisableHotKey", bEFBCopyDisableHotKey);
iniFile.Set("Hacks", "ProjectionHax1", bProjectionHax1);
iniFile.Set("Hacks", "EFBToTextureEnable", bCopyEFBToRAM);
+ iniFile.Set("Hacks", "SMGhack", bSMGhack);
iniFile.Save(FULL_CONFIG_DIR "gfx_opengl.ini");
}
diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Config.h b/Source/Plugins/Plugin_VideoOGL/Src/Config.h
index 5910adf5a0..6bb8e35fcc 100644
--- a/Source/Plugins/Plugin_VideoOGL/Src/Config.h
+++ b/Source/Plugins/Plugin_VideoOGL/Src/Config.h
@@ -84,6 +84,8 @@ struct Config
// Utility
bool bDumpTextures;
+ bool bHiresTextures;
+ bool bHiresTextures;
bool bDumpEFBTarget;
bool bDumpFrames;
bool bFreeLook;
diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp
index a36ecb6309..3ae15705ae 100644
--- a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp
+++ b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp
@@ -54,6 +54,7 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog)
EVT_CHECKBOX(ID_TEXFMTOVERLAY, ConfigDialog::AdvancedSettingsChanged)
EVT_CHECKBOX(ID_TEXFMTCENTER, ConfigDialog::AdvancedSettingsChanged)
EVT_CHECKBOX(ID_DUMPTEXTURES, ConfigDialog::AdvancedSettingsChanged)
+ EVT_CHECKBOX(ID_HIRESTEXTURES, ConfigDialog::AdvancedSettingsChanged)
EVT_CHECKBOX(ID_DUMPEFBTARGET, ConfigDialog::AdvancedSettingsChanged)
EVT_CHECKBOX(ID_DUMPFRAMES, ConfigDialog::AdvancedSettingsChanged)
EVT_CHECKBOX(ID_FREELOOK, ConfigDialog::AdvancedSettingsChanged)
@@ -339,6 +340,8 @@ void ConfigDialog::CreateGUIControls()
sbUtilities = new wxStaticBoxSizer(wxVERTICAL, m_PageAdvanced, wxT("Utilities"));
m_DumpTextures = new wxCheckBox(m_PageAdvanced, ID_DUMPTEXTURES, wxT("Dump textures"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
m_DumpTextures->SetValue(g_Config.bDumpTextures);
+ m_HiresTextures = new wxCheckBox(m_PageAdvanced, ID_HIRESTEXTURES, wxT("Load Hires textures"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
+ m_HiresTextures->SetValue(g_Config.bHiresTextures);
m_DumpEFBTarget = new wxCheckBox(m_PageAdvanced, ID_DUMPEFBTARGET, wxT("Dump EFB Target"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
m_DumpEFBTarget->SetValue(g_Config.bDumpEFBTarget);
m_DumpFrames = new wxCheckBox(m_PageAdvanced, ID_DUMPFRAMES, wxT("Dump Rendered Frames"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
@@ -374,6 +377,7 @@ void ConfigDialog::CreateGUIControls()
m_DstAlphaPass->SetToolTip(wxT("This renders a second time to set alpha to a constant value,"
"\nDisabling it may speed up some games, but could also cause glitches."));
m_DisableFog->SetToolTip(wxT("This option should not require a restart."));
+ m_SMGh->SetToolTip(wxT("SMG hack for Super Mario Galaxy, Mario Kart Wii and other game probably it will be disable for other game and during SMG ending sequence or movies use the M key to turn this option on or off"));
// Sizers
sHacks = new wxGridBagSizer(0, 0);
@@ -418,7 +422,8 @@ void ConfigDialog::CreateGUIControls()
//sUtilities = new wxBoxSizer(wxHORIZONTAL);
sUtilities = new wxGridBagSizer(0, 0);
sUtilities->Add(m_DumpTextures, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5);
- sUtilities->Add(m_DumpEFBTarget, wxGBPosition(0, 1), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5);
+ sUtilities->Add(m_HiresTextures, wxGBPosition(0, 1), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5);
+ sUtilities->Add(m_DumpEFBTarget, wxGBPosition(0, 2), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5);
sUtilities->Add(m_DumpFrames, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5);
sUtilities->Add(m_FreeLook, wxGBPosition(1, 1), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5);
sbUtilities->Add(sUtilities, 1, wxEXPAND);
@@ -554,6 +559,9 @@ void ConfigDialog::AdvancedSettingsChanged(wxCommandEvent& event)
case ID_DUMPTEXTURES:
g_Config.bDumpTextures = m_DumpTextures->IsChecked();
break;
+ case ID_HIRESTEXTURES:
+ g_Config.bHiresTextures = m_HiresTextures->IsChecked();
+ break;
case ID_DUMPEFBTARGET:
g_Config.bDumpEFBTarget = m_DumpEFBTarget->IsChecked();
break;
diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h
index e6547d1391..267dc66d5a 100644
--- a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h
+++ b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h
@@ -106,6 +106,8 @@ class ConfigDialog : public wxDialog
wxCheckBox *m_DisableFog;
wxCheckBox *m_DstAlphaPass;
wxCheckBox *m_DumpTextures;
+ wxCheckBox *m_HiresTextures;
+ wxCheckBox *m_HiresTextures;
wxCheckBox *m_DumpEFBTarget;
wxCheckBox *m_DumpFrames;
wxCheckBox *m_FreeLook;
@@ -167,6 +169,8 @@ class ConfigDialog : public wxDialog
ID_SMGHACK,
ID_DUMPTEXTURES,
+ ID_HIRESTEXTURES,
+ ID_HIRESTEXTURES,
ID_DUMPEFBTARGET,
ID_DUMPFRAMES,
ID_FREELOOK,
diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp
index 63b1d21001..db03dd5594 100644
--- a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp
+++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp
@@ -20,7 +20,7 @@
#include "Globals.h"
#include "CommonPaths.h"
#include "StringUtil.h"
-
+#include
#ifdef _WIN32
#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
#define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset
@@ -34,6 +34,7 @@
#endif
#include "Config.h"
+#include "Hash.h"
#include "Statistics.h"
#include "Profiler.h"
#include "ImageWrite.h"
@@ -47,6 +48,10 @@
#include "PixelShaderCache.h"
#include "PixelShaderManager.h"
#include "VertexShaderManager.h"
+#include "FileUtil.h"
+#include "HiresTextures.h"
+
+#include "../../../Core/Core/Src/ConfigManager.h" // FIXME
u8 *TextureMngr::temp = NULL;
TextureMngr::TexCache TextureMngr::textures;
@@ -156,6 +161,7 @@ void TextureMngr::Init()
{
temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
TexDecoder_SetTexFmtOverlayOptions(g_Config.bTexFmtOverlayEnable, g_Config.bTexFmtOverlayCenter);
+ HiresTextures::Init(((struct SConfig *)globals->config)->m_LocalCoreStartupParameter.GetUniqueID().c_str());
}
void TextureMngr::Invalidate(bool shutdown)
@@ -163,6 +169,7 @@ void TextureMngr::Invalidate(bool shutdown)
for (TexCache::iterator iter = textures.begin(); iter != textures.end(); ++iter)
iter->second.Destroy(shutdown);
textures.clear();
+ HiresTextures::Shutdown();
}
void TextureMngr::Shutdown()
@@ -237,25 +244,25 @@ void TextureMngr::InvalidateRange(u32 start_address, u32 size) {
TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width, int height, int tex_format, int tlutaddr, int tlutfmt)
{
- /* notes (about "UNsafe texture cache"):
- * Have to be removed soon.
- * But we keep it until the "safe" way became rock solid
- * pros: it has an unique ID held by the texture data itself (@address) once cached.
- * cons: it writes this unique ID in the gc RAM <- very dangerous (break MP1) and ugly
- */
- /* notes (about "safe texture cache"):
- * Metroids text issue (character table):
- * Same addr, same GX_TF_C4 texture data but different TLUT (hence different outputs).
- * That's why we have to hash the TLUT too for TLUT tex_format dependent textures (ie. GX_TF_C4, GX_TF_C8, GX_TF_C14X2).
- * And since the address and tex data don't change, the key index in the cacheEntry map can't be the address but
- * have to be a real unique ID.
- * DONE but not satifiying yet -> may break copyEFBToTexture sometimes.
- *
- * Pokemon Colosseum text issue (plain text):
- * Use a GX_TF_I4 512x512 text-flush-texture at a const address.
- * The problem here was just the sparse hash on the texture. This texture is partly overwrited (what is needed only)
- * so lot's of remaning old text. Thin white chars on black bg too.
- */
+ // notes (about "UNsafe texture cache"):
+ // Have to be removed soon.
+ // But we keep it until the "safe" way became rock solid
+ // pros: it has an unique ID held by the texture data itself (@address) once cached.
+ // cons: it writes this unique ID in the gc RAM <- very dangerous (break MP1) and ugly
+
+ // notes (about "safe texture cache"):
+ // Metroids text issue (character table):
+ // Same addr, same GX_TF_C4 texture data but different TLUT (hence different outputs).
+ // That's why we have to hash the TLUT too for TLUT tex_format dependent textures (ie. GX_TF_C4, GX_TF_C8, GX_TF_C14X2).
+ // And since the address and tex data don't change, the key index in the cacheEntry map can't be the address but
+ // have to be a real unique ID.
+ // DONE but not satifiying yet -> may break copyEFBToTexture sometimes.
+
+ // Pokemon Colosseum text issue (plain text):
+ // Use a GX_TF_I4 512x512 text-flush-texture at a const address.
+ // The problem here was just the sparse hash on the texture. This texture is partly overwrited (what is needed only)
+ // so lot's of remaning old text. Thin white chars on black bg too.
+
// TODO: - clean this up when ready to kill old "unsafe texture cache"
// - fix the key index situation with CopyRenderTargetToTexture.
// Could happen only for GX_TF_C4, GX_TF_C8 and GX_TF_C14X2 fmt.
@@ -366,6 +373,26 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width
if (expandedWidth != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, expandedWidth);
+ u32 texHash = HashFNV(temp, entry.size_in_bytes);
+ if (g_Config.bHiresTextures)
+ {
+ //Load Custom textures
+ char texPathTemp[MAX_PATH];
+ int oldWidth = width;
+ int oldHeight = height;
+ sprintf(texPathTemp, "%s_%08x_%i", ((struct SConfig *)globals->config)->m_LocalCoreStartupParameter.GetUniqueID().c_str(), texHash, tex_format);
+ PC_TexFormat customTex = HiresTextures::GetHiresTex(texPathTemp, &width, &height, temp);
+
+ if (customTex != PC_TEX_FMT_NONE)
+ {
+ entry.size_in_bytes = sizeof(temp);
+ entry.scaleX = (float) width / oldWidth;
+ entry.scaleY = (float) height / oldHeight;
+ INFO_LOG(VIDEO, "loading custom texture from %s", texPathTemp);
+ dfmt = customTex;
+ }
+ }
+
if (dfmt != PC_TEX_FMT_DXT1)
{
int gl_format;
@@ -381,6 +408,11 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width
gl_iformat = 4;
gl_type = GL_UNSIGNED_BYTE;
break;
+ case PC_TEX_FMT_RGBA32:
+ gl_format = GL_RGBA;
+ gl_iformat = 4;
+ gl_type = GL_UNSIGNED_BYTE;
+ break;
case PC_TEX_FMT_I8:
gl_format = GL_LUMINANCE;
gl_iformat = GL_INTENSITY;
@@ -434,10 +466,13 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width
if (g_Config.bDumpTextures) // dump texture to file
{
- static int counter = 0;
char szTemp[MAX_PATH];
- sprintf(szTemp, "%s/txt_%04i_%i.tga", FULL_DUMP_TEXTURES_DIR, counter++, tex_format);
- SaveTexture(szTemp,target, entry.texture, width, height);
+
+ sprintf(szTemp, "%s/%s_%08x_%i.tga", FULL_DUMP_TEXTURES_DIR, ((struct SConfig *)globals->config)->m_LocalCoreStartupParameter.GetUniqueID().c_str(), texHash, tex_format);
+ if (!File::Exists(szTemp))
+ {
+ SaveTexture(szTemp, target, entry.texture, width, height);
+ }
}
INCSTAT(stats.numTexturesCreated);
diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h
index 976b77be88..e46ba59d95 100644
--- a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h
+++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h
@@ -29,7 +29,7 @@ class TextureMngr
public:
struct TCacheEntry
{
- TCacheEntry() : texture(0), addr(0), size_in_bytes(0), hash(0), w(0), h(0), isRenderTarget(false), isUpsideDown(false), isNonPow2(true), bHaveMipMaps(false) { mode.hex = 0xFCFCFCFC; }
+ TCacheEntry() : texture(0), addr(0), size_in_bytes(0), hash(0), w(0), h(0), scaleX(1.0f), scaleY(1.0f), isRenderTarget(false), isUpsideDown(false), isNonPow2(true), bHaveMipMaps(false) { mode.hex = 0xFCFCFCFC; }
GLuint texture;
u32 addr;
@@ -43,6 +43,8 @@ public:
int frameCount;
int w, h, fmt;
+ float scaleX, scaleY; // Hires texutres need this
+
bool isRenderTarget; // if render texture, then rendertex is filled with the direct copy of the render target
// later conversions would have to convert properly from rendertexfmt to texfmt
bool isUpsideDown;
diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp
index a5c920c64a..09931e6b93 100644
--- a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp
+++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp
@@ -236,6 +236,9 @@ void Flush()
// 0s are probably for no manual wrapping needed.
PixelShaderManager::SetTexDims(i, tentry->w, tentry->h, 0, 0);
}
+ // texture is hires - pass the scaling size
+ if (tentry->scaleX != 1.0f && tentry->scaleY != 1.0f)
+ PixelShaderManager::SetCustomTexScale(i, tentry->scaleX, tentry->scaleY);
if (g_Config.iLog & CONF_SAVETEXTURES)
{
// save the textures