/source/soil/SOIL.c
C | 2034 lines | 1653 code | 40 blank | 341 comment | 323 complexity | 516373e57a159fc8e40b880cfd6e3f32 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*
- 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
- #ifndef WIN32_LEAN_AND_MEAN
- #define WIN32_LEAN_AND_MEAN
- #endif //ifndef
-
- #include <windows.h>
- #include <wingdi.h>
- #include <GL/gl.h>
- #elif defined(__APPLE__) || defined(__APPLE_CC__)
- /* I can't test this Apple stuff! */
- #include <OpenGL/gl.h>
- #include <Carbon/Carbon.h>
- #define APIENTRY
- #else
- #include <GL/gl.h>
- #include <GL/glx.h>
- #endif
-
- #include "SOIL.h"
- #include "stb_image_aug.h"
- #include "image_helper.h"
- #include "image_DXT.h"
-
- #include <stdlib.h>
- #include <string.h>
-
- /* 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,
- int* w,
- int* h
- )
- {
- /* 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 );
-
- /* Set the width and height */
- (*w) = width;
- (*h) = height;
-
- /* 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<<MIPlevel) <= width) || ((1<<MIPlevel) <= height) )
- {
- /* do this MIPmap level */
- mipmap_image(
- img, width, height, channels,
- resampled,
- (1 << MIPlevel), (1 << MIPlevel) );
- /* upload the MIPmaps */
- 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(
- resampled, MIPwidth, MIPheight, channels, &DDS_size );
- } else
- {
- /* RGBA, use DXT5 */
- DDS_data = convert_image_to_DXT5(
- resampled, MIPwidth, MIPheight, channels, &DDS_size );
- }
- if( DDS_data )
- {
- soilGlCompressedTexImage2D(
- opengl_texture_target, MIPlevel,
- internal_texture_format, MIPwidth, MIPheight, 0,
- DDS_size, DDS_data );
- check_for_GL_errors( "glCompressedTexImage2D" );
- SOIL_free_image_data( DDS_data );
- } else
- {
- /* my compression failed, try the OpenGL driver's version */
- glTexImage2D(
- opengl_texture_target, MIPlevel,
- internal_texture_format, MIPwidth, MIPheight, 0,
- original_texture_format, GL_UNSIGNED_BYTE, resampled );
- check_for_GL_errors( "glTexImage2D" );
- }
- } else
- {
- /* user want OpenGL to do all the work! */
- glTexImage2D(
- opengl_texture_target, MIPlevel,
- internal_texture_format, MIPwidth, MIPheight, 0,
- original_texture_format, GL_UNSIGNED_BYTE, resampled );
- check_for_GL_errors( "glTexImage2D" );
- }
- /* prep for the next level */
- ++MIPlevel;
- MIPwidth = (MIPwidth + 1) / 2;
- MIPheight = (MIPheight + 1) / 2;
- }
- SOIL_free_image_data( resampled );
- /* 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 );
- check_for_GL_errors( "GL_TEXTURE_MIN/MAG_FILTER" );
- } 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 );
- check_for_GL_errors( "GL_TEXTURE_MIN/MAG_FILTER" );
- }
- /* 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 );
- if( opengl_texture_type == SOIL_TEXTURE_CUBE_MAP )
- {
- /* SOIL_TEXTURE_WRAP_R is invalid if cubemaps aren't supported */
- glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT );
- }
- check_for_GL_errors( "GL_TEXTURE_WRAP_*" );
- } 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 );
- if( opengl_texture_type == SOIL_TEXTURE_CUBE_MAP )
- {
- /* SOIL_TEXTURE_WRAP_R is invalid if cubemaps aren't supported */
- glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode );
- }
- check_for_GL_errors( "GL_TEXTURE_WRAP_*" );
- }
- /* done */
- result_string_pointer = "Image loaded as an OpenGL texture";
- } else
- {
- /* failed */
- result_string_pointer = "Failed to generate an OpenGL texture name; missing OpenGL context?";
- }
- SOIL_free_image_data( img );
- return tex_id;
- }
-
- int
- SOIL_save_screenshot
- (
- const char *filename,
- int image_type,
- int x, int y,
- int width, int height
- )
- {
- unsigned char *pixel_data;
- int i, j;
- int save_result;
-
- /* error checks */
- if( (width < 1) || (height < 1) )
- {
- result_string_pointer = "Invalid screenshot dimensions";
- return 0;
- }
- if( (x < 0) || (y < 0) )
- {
- result_string_pointer = "Invalid screenshot location";
- return 0;
- }
- if( filename == NULL )
- {
- result_string_pointer = "Invalid screenshot filename";
- return 0;
- }
-
- /* Get the data from OpenGL */
- pixel_data = (unsigned char*)malloc( 3*width*height );
- glReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixel_data);
-
- /* invert the image */
- for( j = 0; j*2 < height; ++j )
- {
- int index1 = j * width * 3;
- int index2 = (height - 1 - j) * width * 3;
- for( i = width * 3; i > 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; c…
Large files files are truncated, but you can click here to view the full file