Merge pull request #6291 from JosJuice/remove-soil
Replace usage of SOIL with libpng
This commit is contained in:
commit
86c676ab04
|
@ -670,17 +670,6 @@ else()
|
||||||
include_directories(BEFORE Externals/curl/include)
|
include_directories(BEFORE Externals/curl/include)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT APPLE)
|
|
||||||
check_lib(SOIL "(no .pc for SOIL)" SOIL SOIL/SOIL.h QUIET)
|
|
||||||
endif()
|
|
||||||
if(SOIL_FOUND)
|
|
||||||
message(STATUS "Using shared SOIL")
|
|
||||||
else()
|
|
||||||
message(STATUS "Using static SOIL from Externals")
|
|
||||||
add_subdirectory(Externals/SOIL)
|
|
||||||
include_directories(Externals/SOIL)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT ANDROID)
|
if (NOT ANDROID)
|
||||||
find_library(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c)
|
find_library(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c)
|
||||||
find_path(ICONV_INCLUDE_DIR NAMES iconv.h)
|
find_path(ICONV_INCLUDE_DIR NAMES iconv.h)
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
set(SRCS image_DXT.c
|
|
||||||
image_helper.c
|
|
||||||
SOIL.c
|
|
||||||
stb_image_aug.c)
|
|
||||||
|
|
||||||
add_library(SOIL STATIC ${SRCS})
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,418 +0,0 @@
|
||||||
/**
|
|
||||||
@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 */
|
|
|
@ -1,58 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|x64">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
</ItemGroup>
|
|
||||||
<PropertyGroup Label="Globals">
|
|
||||||
<ProjectGuid>{B441CC62-877E-4B3F-93E0-0DE80544F705}</ProjectGuid>
|
|
||||||
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
|
||||||
<PropertyGroup Label="Configuration">
|
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
|
||||||
<PlatformToolset>v141</PlatformToolset>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
|
||||||
<ImportGroup Label="ExtensionSettings">
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="PropertySheets">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
<Import Project="..\..\Source\VSProps\Base.props" />
|
|
||||||
<Import Project="..\..\Source\VSProps\ClDisableAllWarnings.props" />
|
|
||||||
</ImportGroup>
|
|
||||||
<PropertyGroup Label="UserMacros" />
|
|
||||||
<ItemGroup>
|
|
||||||
<Text Include="CMakeLists.txt" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="image_DXT.c" />
|
|
||||||
<ClCompile Include="image_helper.c" />
|
|
||||||
<ClCompile Include="SOIL.c" />
|
|
||||||
<ClCompile Include="stb_image_aug.c" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="image_DXT.h" />
|
|
||||||
<ClInclude Include="image_helper.h" />
|
|
||||||
<ClInclude Include="SOIL.h" />
|
|
||||||
<ClInclude Include="stbi_DDS_aug.h" />
|
|
||||||
<ClInclude Include="stbi_DDS_aug_c.h" />
|
|
||||||
<ClInclude Include="stb_image_aug.h" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
|
||||||
<ImportGroup Label="ExtensionTargets">
|
|
||||||
</ImportGroup>
|
|
||||||
</Project>
|
|
|
@ -1 +0,0 @@
|
||||||
#include "../SOIL.h"
|
|
|
@ -1,632 +0,0 @@
|
||||||
/*
|
|
||||||
Jonathan Dummer
|
|
||||||
2007-07-31-10.32
|
|
||||||
|
|
||||||
simple DXT compression / decompression code
|
|
||||||
|
|
||||||
public domain
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "image_DXT.h"
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/* set this =1 if you want to use the covarince matrix method...
|
|
||||||
which is better than my method of using standard deviations
|
|
||||||
overall, except on the infintesimal chance that the power
|
|
||||||
method fails for finding the largest eigenvector */
|
|
||||||
#define USE_COV_MAT 1
|
|
||||||
|
|
||||||
/********* Function Prototypes *********/
|
|
||||||
/*
|
|
||||||
Takes a 4x4 block of pixels and compresses it into 8 bytes
|
|
||||||
in DXT1 format (color only, no alpha). Speed is valued
|
|
||||||
over prettyness, at least for now.
|
|
||||||
*/
|
|
||||||
void compress_DDS_color_block(
|
|
||||||
int channels,
|
|
||||||
const unsigned char *const uncompressed,
|
|
||||||
unsigned char compressed[8] );
|
|
||||||
/*
|
|
||||||
Takes a 4x4 block of pixels and compresses the alpha
|
|
||||||
component it into 8 bytes for use in DXT5 DDS files.
|
|
||||||
Speed is valued over prettyness, at least for now.
|
|
||||||
*/
|
|
||||||
void compress_DDS_alpha_block(
|
|
||||||
const unsigned char *const uncompressed,
|
|
||||||
unsigned char compressed[8] );
|
|
||||||
|
|
||||||
/********* Actual Exposed Functions *********/
|
|
||||||
int
|
|
||||||
save_image_as_DDS
|
|
||||||
(
|
|
||||||
const char *filename,
|
|
||||||
int width, int height, int channels,
|
|
||||||
const unsigned char *const data
|
|
||||||
)
|
|
||||||
{
|
|
||||||
/* variables */
|
|
||||||
FILE *fout;
|
|
||||||
unsigned char *DDS_data;
|
|
||||||
DDS_header header;
|
|
||||||
int DDS_size;
|
|
||||||
/* error check */
|
|
||||||
if( (NULL == filename) ||
|
|
||||||
(width < 1) || (height < 1) ||
|
|
||||||
(channels < 1) || (channels > 4) ||
|
|
||||||
(data == NULL ) )
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* Convert the image */
|
|
||||||
if( (channels & 1) == 1 )
|
|
||||||
{
|
|
||||||
/* no alpha, just use DXT1 */
|
|
||||||
DDS_data = convert_image_to_DXT1( data, width, height, channels, &DDS_size );
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
/* has alpha, so use DXT5 */
|
|
||||||
DDS_data = convert_image_to_DXT5( data, width, height, channels, &DDS_size );
|
|
||||||
}
|
|
||||||
/* save it */
|
|
||||||
memset( &header, 0, sizeof( DDS_header ) );
|
|
||||||
header.dwMagic = ('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24);
|
|
||||||
header.dwSize = 124;
|
|
||||||
header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_LINEARSIZE;
|
|
||||||
header.dwWidth = width;
|
|
||||||
header.dwHeight = height;
|
|
||||||
header.dwPitchOrLinearSize = DDS_size;
|
|
||||||
header.sPixelFormat.dwSize = 32;
|
|
||||||
header.sPixelFormat.dwFlags = DDPF_FOURCC;
|
|
||||||
if( (channels & 1) == 1 )
|
|
||||||
{
|
|
||||||
header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('1' << 24);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('5' << 24);
|
|
||||||
}
|
|
||||||
header.sCaps.dwCaps1 = DDSCAPS_TEXTURE;
|
|
||||||
/* write it out */
|
|
||||||
fout = fopen( filename, "wb");
|
|
||||||
fwrite( &header, sizeof( DDS_header ), 1, fout );
|
|
||||||
fwrite( DDS_data, 1, DDS_size, fout );
|
|
||||||
fclose( fout );
|
|
||||||
/* done */
|
|
||||||
free( DDS_data );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char* convert_image_to_DXT1(
|
|
||||||
const unsigned char *const uncompressed,
|
|
||||||
int width, int height, int channels,
|
|
||||||
int *out_size )
|
|
||||||
{
|
|
||||||
unsigned char *compressed;
|
|
||||||
int i, j, x, y;
|
|
||||||
unsigned char ublock[16*3];
|
|
||||||
unsigned char cblock[8];
|
|
||||||
int cindex = 0, chan_step = 1;
|
|
||||||
int block_count = 0;
|
|
||||||
/* error check */
|
|
||||||
*out_size = 0;
|
|
||||||
if( (width < 1) || (height < 1) ||
|
|
||||||
(NULL == uncompressed) ||
|
|
||||||
(channels < 1) || (channels > 4) )
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* for channels == 1 or 2, I do not step forward for R,G,B values */
|
|
||||||
if( channels < 3 )
|
|
||||||
{
|
|
||||||
chan_step = 0;
|
|
||||||
}
|
|
||||||
/* get the RAM for the compressed image
|
|
||||||
(8 bytes per 4x4 pixel block) */
|
|
||||||
*out_size = ((width+3) >> 2) * ((height+3) >> 2) * 8;
|
|
||||||
compressed = (unsigned char*)malloc( *out_size );
|
|
||||||
/* go through each block */
|
|
||||||
for( j = 0; j < height; j += 4 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < width; i += 4 )
|
|
||||||
{
|
|
||||||
/* copy this block into a new one */
|
|
||||||
int idx = 0;
|
|
||||||
int mx = 4, my = 4;
|
|
||||||
if( j+4 >= height )
|
|
||||||
{
|
|
||||||
my = height - j;
|
|
||||||
}
|
|
||||||
if( i+4 >= width )
|
|
||||||
{
|
|
||||||
mx = width - i;
|
|
||||||
}
|
|
||||||
for( y = 0; y < my; ++y )
|
|
||||||
{
|
|
||||||
for( x = 0; x < mx; ++x )
|
|
||||||
{
|
|
||||||
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels];
|
|
||||||
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step];
|
|
||||||
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step];
|
|
||||||
}
|
|
||||||
for( x = mx; x < 4; ++x )
|
|
||||||
{
|
|
||||||
ublock[idx++] = ublock[0];
|
|
||||||
ublock[idx++] = ublock[1];
|
|
||||||
ublock[idx++] = ublock[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for( y = my; y < 4; ++y )
|
|
||||||
{
|
|
||||||
for( x = 0; x < 4; ++x )
|
|
||||||
{
|
|
||||||
ublock[idx++] = ublock[0];
|
|
||||||
ublock[idx++] = ublock[1];
|
|
||||||
ublock[idx++] = ublock[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* compress the block */
|
|
||||||
++block_count;
|
|
||||||
compress_DDS_color_block( 3, ublock, cblock );
|
|
||||||
/* copy the data from the block into the main block */
|
|
||||||
for( x = 0; x < 8; ++x )
|
|
||||||
{
|
|
||||||
compressed[cindex++] = cblock[x];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return compressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char* convert_image_to_DXT5(
|
|
||||||
const unsigned char *const uncompressed,
|
|
||||||
int width, int height, int channels,
|
|
||||||
int *out_size )
|
|
||||||
{
|
|
||||||
unsigned char *compressed;
|
|
||||||
int i, j, x, y;
|
|
||||||
unsigned char ublock[16*4];
|
|
||||||
unsigned char cblock[8];
|
|
||||||
int cindex = 0, chan_step = 1;
|
|
||||||
int block_count = 0, has_alpha;
|
|
||||||
/* error check */
|
|
||||||
*out_size = 0;
|
|
||||||
if( (width < 1) || (height < 1) ||
|
|
||||||
(NULL == uncompressed) ||
|
|
||||||
(channels < 1) || ( channels > 4) )
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* for channels == 1 or 2, I do not step forward for R,G,B vales */
|
|
||||||
if( channels < 3 )
|
|
||||||
{
|
|
||||||
chan_step = 0;
|
|
||||||
}
|
|
||||||
/* # channels = 1 or 3 have no alpha, 2 & 4 do have alpha */
|
|
||||||
has_alpha = 1 - (channels & 1);
|
|
||||||
/* get the RAM for the compressed image
|
|
||||||
(16 bytes per 4x4 pixel block) */
|
|
||||||
*out_size = ((width+3) >> 2) * ((height+3) >> 2) * 16;
|
|
||||||
compressed = (unsigned char*)malloc( *out_size );
|
|
||||||
/* go through each block */
|
|
||||||
for( j = 0; j < height; j += 4 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < width; i += 4 )
|
|
||||||
{
|
|
||||||
/* local variables, and my block counter */
|
|
||||||
int idx = 0;
|
|
||||||
int mx = 4, my = 4;
|
|
||||||
if( j+4 >= height )
|
|
||||||
{
|
|
||||||
my = height - j;
|
|
||||||
}
|
|
||||||
if( i+4 >= width )
|
|
||||||
{
|
|
||||||
mx = width - i;
|
|
||||||
}
|
|
||||||
for( y = 0; y < my; ++y )
|
|
||||||
{
|
|
||||||
for( x = 0; x < mx; ++x )
|
|
||||||
{
|
|
||||||
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels];
|
|
||||||
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step];
|
|
||||||
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step];
|
|
||||||
ublock[idx++] =
|
|
||||||
has_alpha * uncompressed[(j+y)*width*channels+(i+x)*channels+channels-1]
|
|
||||||
+ (1-has_alpha)*255;
|
|
||||||
}
|
|
||||||
for( x = mx; x < 4; ++x )
|
|
||||||
{
|
|
||||||
ublock[idx++] = ublock[0];
|
|
||||||
ublock[idx++] = ublock[1];
|
|
||||||
ublock[idx++] = ublock[2];
|
|
||||||
ublock[idx++] = ublock[3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for( y = my; y < 4; ++y )
|
|
||||||
{
|
|
||||||
for( x = 0; x < 4; ++x )
|
|
||||||
{
|
|
||||||
ublock[idx++] = ublock[0];
|
|
||||||
ublock[idx++] = ublock[1];
|
|
||||||
ublock[idx++] = ublock[2];
|
|
||||||
ublock[idx++] = ublock[3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* now compress the alpha block */
|
|
||||||
compress_DDS_alpha_block( ublock, cblock );
|
|
||||||
/* copy the data from the compressed alpha block into the main buffer */
|
|
||||||
for( x = 0; x < 8; ++x )
|
|
||||||
{
|
|
||||||
compressed[cindex++] = cblock[x];
|
|
||||||
}
|
|
||||||
/* then compress the color block */
|
|
||||||
++block_count;
|
|
||||||
compress_DDS_color_block( 4, ublock, cblock );
|
|
||||||
/* copy the data from the compressed color block into the main buffer */
|
|
||||||
for( x = 0; x < 8; ++x )
|
|
||||||
{
|
|
||||||
compressed[cindex++] = cblock[x];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return compressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/********* Helper Functions *********/
|
|
||||||
int 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rgb_to_565( int r, int g, int b )
|
|
||||||
{
|
|
||||||
return
|
|
||||||
(convert_bit_range( r, 8, 5 ) << 11) |
|
|
||||||
(convert_bit_range( g, 8, 6 ) << 05) |
|
|
||||||
(convert_bit_range( b, 8, 5 ) << 00);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rgb_888_from_565( unsigned int c, int *r, int *g, int *b )
|
|
||||||
{
|
|
||||||
*r = convert_bit_range( (c >> 11) & 31, 5, 8 );
|
|
||||||
*g = convert_bit_range( (c >> 05) & 63, 6, 8 );
|
|
||||||
*b = convert_bit_range( (c >> 00) & 31, 5, 8 );
|
|
||||||
}
|
|
||||||
|
|
||||||
void compute_color_line_STDEV(
|
|
||||||
const unsigned char *const uncompressed,
|
|
||||||
int channels,
|
|
||||||
float point[3], float direction[3] )
|
|
||||||
{
|
|
||||||
const float inv_16 = 1.0f / 16.0f;
|
|
||||||
int i;
|
|
||||||
float sum_r = 0.0f, sum_g = 0.0f, sum_b = 0.0f;
|
|
||||||
float sum_rr = 0.0f, sum_gg = 0.0f, sum_bb = 0.0f;
|
|
||||||
float sum_rg = 0.0f, sum_rb = 0.0f, sum_gb = 0.0f;
|
|
||||||
/* calculate all data needed for the covariance matrix
|
|
||||||
( to compare with _rygdxt code) */
|
|
||||||
for( i = 0; i < 16*channels; i += channels )
|
|
||||||
{
|
|
||||||
sum_r += uncompressed[i+0];
|
|
||||||
sum_rr += uncompressed[i+0] * uncompressed[i+0];
|
|
||||||
sum_g += uncompressed[i+1];
|
|
||||||
sum_gg += uncompressed[i+1] * uncompressed[i+1];
|
|
||||||
sum_b += uncompressed[i+2];
|
|
||||||
sum_bb += uncompressed[i+2] * uncompressed[i+2];
|
|
||||||
sum_rg += uncompressed[i+0] * uncompressed[i+1];
|
|
||||||
sum_rb += uncompressed[i+0] * uncompressed[i+2];
|
|
||||||
sum_gb += uncompressed[i+1] * uncompressed[i+2];
|
|
||||||
}
|
|
||||||
/* convert the sums to averages */
|
|
||||||
sum_r *= inv_16;
|
|
||||||
sum_g *= inv_16;
|
|
||||||
sum_b *= inv_16;
|
|
||||||
/* and convert the squares to the squares of the value - avg_value */
|
|
||||||
sum_rr -= 16.0f * sum_r * sum_r;
|
|
||||||
sum_gg -= 16.0f * sum_g * sum_g;
|
|
||||||
sum_bb -= 16.0f * sum_b * sum_b;
|
|
||||||
sum_rg -= 16.0f * sum_r * sum_g;
|
|
||||||
sum_rb -= 16.0f * sum_r * sum_b;
|
|
||||||
sum_gb -= 16.0f * sum_g * sum_b;
|
|
||||||
/* the point on the color line is the average */
|
|
||||||
point[0] = sum_r;
|
|
||||||
point[1] = sum_g;
|
|
||||||
point[2] = sum_b;
|
|
||||||
#if USE_COV_MAT
|
|
||||||
/*
|
|
||||||
The following idea was from ryg.
|
|
||||||
(https://mollyrocket.com/forums/viewtopic.php?t=392)
|
|
||||||
The method worked great (less RMSE than mine) most of
|
|
||||||
the time, but had some issues handling some simple
|
|
||||||
boundary cases, like full green next to full red,
|
|
||||||
which would generate a covariance matrix like this:
|
|
||||||
|
|
||||||
| 1 -1 0 |
|
|
||||||
| -1 1 0 |
|
|
||||||
| 0 0 0 |
|
|
||||||
|
|
||||||
For a given starting vector, the power method can
|
|
||||||
generate all zeros! So no starting with {1,1,1}
|
|
||||||
as I was doing! This kind of error is still a
|
|
||||||
slight posibillity, but will be very rare.
|
|
||||||
*/
|
|
||||||
/* use the covariance matrix directly
|
|
||||||
(1st iteration, don't use all 1.0 values!) */
|
|
||||||
sum_r = 1.0f;
|
|
||||||
sum_g = 2.718281828f;
|
|
||||||
sum_b = 3.141592654f;
|
|
||||||
direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb;
|
|
||||||
direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb;
|
|
||||||
direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb;
|
|
||||||
/* 2nd iteration, use results from the 1st guy */
|
|
||||||
sum_r = direction[0];
|
|
||||||
sum_g = direction[1];
|
|
||||||
sum_b = direction[2];
|
|
||||||
direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb;
|
|
||||||
direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb;
|
|
||||||
direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb;
|
|
||||||
/* 3rd iteration, use results from the 2nd guy */
|
|
||||||
sum_r = direction[0];
|
|
||||||
sum_g = direction[1];
|
|
||||||
sum_b = direction[2];
|
|
||||||
direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb;
|
|
||||||
direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb;
|
|
||||||
direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb;
|
|
||||||
#else
|
|
||||||
/* use my standard deviation method
|
|
||||||
(very robust, a tiny bit slower and less accurate) */
|
|
||||||
direction[0] = sqrt( sum_rr );
|
|
||||||
direction[1] = sqrt( sum_gg );
|
|
||||||
direction[2] = sqrt( sum_bb );
|
|
||||||
/* which has a greater component */
|
|
||||||
if( sum_gg > sum_rr )
|
|
||||||
{
|
|
||||||
/* green has greater component, so base the other signs off of green */
|
|
||||||
if( sum_rg < 0.0f )
|
|
||||||
{
|
|
||||||
direction[0] = -direction[0];
|
|
||||||
}
|
|
||||||
if( sum_gb < 0.0f )
|
|
||||||
{
|
|
||||||
direction[2] = -direction[2];
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
/* red has a greater component */
|
|
||||||
if( sum_rg < 0.0f )
|
|
||||||
{
|
|
||||||
direction[1] = -direction[1];
|
|
||||||
}
|
|
||||||
if( sum_rb < 0.0f )
|
|
||||||
{
|
|
||||||
direction[2] = -direction[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void LSE_master_colors_max_min(
|
|
||||||
int *cmax, int *cmin,
|
|
||||||
int channels,
|
|
||||||
const unsigned char *const uncompressed )
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
/* the master colors */
|
|
||||||
int c0[3], c1[3];
|
|
||||||
/* used for fitting the line */
|
|
||||||
float sum_x[] = { 0.0f, 0.0f, 0.0f };
|
|
||||||
float sum_x2[] = { 0.0f, 0.0f, 0.0f };
|
|
||||||
float dot_max = 1.0f, dot_min = -1.0f;
|
|
||||||
float vec_len2 = 0.0f;
|
|
||||||
float dot;
|
|
||||||
/* error check */
|
|
||||||
if( (channels < 3) || (channels > 4) )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
compute_color_line_STDEV( uncompressed, channels, sum_x, sum_x2 );
|
|
||||||
vec_len2 = 1.0f / ( 0.00001f +
|
|
||||||
sum_x2[0]*sum_x2[0] + sum_x2[1]*sum_x2[1] + sum_x2[2]*sum_x2[2] );
|
|
||||||
/* finding the max and min vector values */
|
|
||||||
dot_max =
|
|
||||||
(
|
|
||||||
sum_x2[0] * uncompressed[0] +
|
|
||||||
sum_x2[1] * uncompressed[1] +
|
|
||||||
sum_x2[2] * uncompressed[2]
|
|
||||||
);
|
|
||||||
dot_min = dot_max;
|
|
||||||
for( i = 1; i < 16; ++i )
|
|
||||||
{
|
|
||||||
dot =
|
|
||||||
(
|
|
||||||
sum_x2[0] * uncompressed[i*channels+0] +
|
|
||||||
sum_x2[1] * uncompressed[i*channels+1] +
|
|
||||||
sum_x2[2] * uncompressed[i*channels+2]
|
|
||||||
);
|
|
||||||
if( dot < dot_min )
|
|
||||||
{
|
|
||||||
dot_min = dot;
|
|
||||||
} else if( dot > dot_max )
|
|
||||||
{
|
|
||||||
dot_max = dot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* and the offset (from the average location) */
|
|
||||||
dot = sum_x2[0]*sum_x[0] + sum_x2[1]*sum_x[1] + sum_x2[2]*sum_x[2];
|
|
||||||
dot_min -= dot;
|
|
||||||
dot_max -= dot;
|
|
||||||
/* post multiply by the scaling factor */
|
|
||||||
dot_min *= vec_len2;
|
|
||||||
dot_max *= vec_len2;
|
|
||||||
/* OK, build the master colors */
|
|
||||||
for( i = 0; i < 3; ++i )
|
|
||||||
{
|
|
||||||
/* color 0 */
|
|
||||||
c0[i] = (int)(0.5f + sum_x[i] + dot_max * sum_x2[i]);
|
|
||||||
if( c0[i] < 0 )
|
|
||||||
{
|
|
||||||
c0[i] = 0;
|
|
||||||
} else if( c0[i] > 255 )
|
|
||||||
{
|
|
||||||
c0[i] = 255;
|
|
||||||
}
|
|
||||||
/* color 1 */
|
|
||||||
c1[i] = (int)(0.5f + sum_x[i] + dot_min * sum_x2[i]);
|
|
||||||
if( c1[i] < 0 )
|
|
||||||
{
|
|
||||||
c1[i] = 0;
|
|
||||||
} else if( c1[i] > 255 )
|
|
||||||
{
|
|
||||||
c1[i] = 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* down_sample (with rounding?) */
|
|
||||||
i = rgb_to_565( c0[0], c0[1], c0[2] );
|
|
||||||
j = rgb_to_565( c1[0], c1[1], c1[2] );
|
|
||||||
if( i > j )
|
|
||||||
{
|
|
||||||
*cmax = i;
|
|
||||||
*cmin = j;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
*cmax = j;
|
|
||||||
*cmin = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
compress_DDS_color_block
|
|
||||||
(
|
|
||||||
int channels,
|
|
||||||
const unsigned char *const uncompressed,
|
|
||||||
unsigned char compressed[8]
|
|
||||||
)
|
|
||||||
{
|
|
||||||
/* variables */
|
|
||||||
int i;
|
|
||||||
int next_bit;
|
|
||||||
int enc_c0, enc_c1;
|
|
||||||
int c0[4], c1[4];
|
|
||||||
float color_line[] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
||||||
float vec_len2 = 0.0f, dot_offset = 0.0f;
|
|
||||||
/* stupid order */
|
|
||||||
int swizzle4[] = { 0, 2, 3, 1 };
|
|
||||||
/* get the master colors */
|
|
||||||
LSE_master_colors_max_min( &enc_c0, &enc_c1, channels, uncompressed );
|
|
||||||
/* store the 565 color 0 and color 1 */
|
|
||||||
compressed[0] = (enc_c0 >> 0) & 255;
|
|
||||||
compressed[1] = (enc_c0 >> 8) & 255;
|
|
||||||
compressed[2] = (enc_c1 >> 0) & 255;
|
|
||||||
compressed[3] = (enc_c1 >> 8) & 255;
|
|
||||||
/* zero out the compressed data */
|
|
||||||
compressed[4] = 0;
|
|
||||||
compressed[5] = 0;
|
|
||||||
compressed[6] = 0;
|
|
||||||
compressed[7] = 0;
|
|
||||||
/* reconstitute the master color vectors */
|
|
||||||
rgb_888_from_565( enc_c0, &c0[0], &c0[1], &c0[2] );
|
|
||||||
rgb_888_from_565( enc_c1, &c1[0], &c1[1], &c1[2] );
|
|
||||||
/* the new vector */
|
|
||||||
vec_len2 = 0.0f;
|
|
||||||
for( i = 0; i < 3; ++i )
|
|
||||||
{
|
|
||||||
color_line[i] = (float)(c1[i] - c0[i]);
|
|
||||||
vec_len2 += color_line[i] * color_line[i];
|
|
||||||
}
|
|
||||||
if( vec_len2 > 0.0f )
|
|
||||||
{
|
|
||||||
vec_len2 = 1.0f / vec_len2;
|
|
||||||
}
|
|
||||||
/* pre-proform the scaling */
|
|
||||||
color_line[0] *= vec_len2;
|
|
||||||
color_line[1] *= vec_len2;
|
|
||||||
color_line[2] *= vec_len2;
|
|
||||||
/* compute the offset (constant) portion of the dot product */
|
|
||||||
dot_offset = color_line[0]*c0[0] + color_line[1]*c0[1] + color_line[2]*c0[2];
|
|
||||||
/* store the rest of the bits */
|
|
||||||
next_bit = 8*4;
|
|
||||||
for( i = 0; i < 16; ++i )
|
|
||||||
{
|
|
||||||
/* find the dot product of this color, to place it on the line
|
|
||||||
(should be [-1,1]) */
|
|
||||||
int next_value = 0;
|
|
||||||
float dot_product =
|
|
||||||
color_line[0] * uncompressed[i*channels+0] +
|
|
||||||
color_line[1] * uncompressed[i*channels+1] +
|
|
||||||
color_line[2] * uncompressed[i*channels+2] -
|
|
||||||
dot_offset;
|
|
||||||
/* map to [0,3] */
|
|
||||||
next_value = (int)( dot_product * 3.0f + 0.5f );
|
|
||||||
if( next_value > 3 )
|
|
||||||
{
|
|
||||||
next_value = 3;
|
|
||||||
} else if( next_value < 0 )
|
|
||||||
{
|
|
||||||
next_value = 0;
|
|
||||||
}
|
|
||||||
/* OK, store this value */
|
|
||||||
compressed[next_bit >> 3] |= swizzle4[ next_value ] << (next_bit & 7);
|
|
||||||
next_bit += 2;
|
|
||||||
}
|
|
||||||
/* done compressing to DXT1 */
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
compress_DDS_alpha_block
|
|
||||||
(
|
|
||||||
const unsigned char *const uncompressed,
|
|
||||||
unsigned char compressed[8]
|
|
||||||
)
|
|
||||||
{
|
|
||||||
/* variables */
|
|
||||||
int i;
|
|
||||||
int next_bit;
|
|
||||||
int a0, a1;
|
|
||||||
float scale_me;
|
|
||||||
/* stupid order */
|
|
||||||
int swizzle8[] = { 1, 7, 6, 5, 4, 3, 2, 0 };
|
|
||||||
/* get the alpha limits (a0 > a1) */
|
|
||||||
a0 = a1 = uncompressed[3];
|
|
||||||
for( i = 4+3; i < 16*4; i += 4 )
|
|
||||||
{
|
|
||||||
if( uncompressed[i] > a0 )
|
|
||||||
{
|
|
||||||
a0 = uncompressed[i];
|
|
||||||
} else if( uncompressed[i] < a1 )
|
|
||||||
{
|
|
||||||
a1 = uncompressed[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* store those limits, and zero the rest of the compressed dataset */
|
|
||||||
compressed[0] = a0;
|
|
||||||
compressed[1] = a1;
|
|
||||||
/* zero out the compressed data */
|
|
||||||
compressed[2] = 0;
|
|
||||||
compressed[3] = 0;
|
|
||||||
compressed[4] = 0;
|
|
||||||
compressed[5] = 0;
|
|
||||||
compressed[6] = 0;
|
|
||||||
compressed[7] = 0;
|
|
||||||
/* store the all of the alpha values */
|
|
||||||
next_bit = 8*2;
|
|
||||||
scale_me = 7.9999f / (a0 - a1);
|
|
||||||
for( i = 3; i < 16*4; i += 4 )
|
|
||||||
{
|
|
||||||
/* convert this alpha value to a 3 bit number */
|
|
||||||
int svalue;
|
|
||||||
int value = (int)((uncompressed[i] - a1) * scale_me);
|
|
||||||
svalue = swizzle8[ value&7 ];
|
|
||||||
/* OK, store this value, start with the 1st byte */
|
|
||||||
compressed[next_bit >> 3] |= svalue << (next_bit & 7);
|
|
||||||
if( (next_bit & 7) > 5 )
|
|
||||||
{
|
|
||||||
/* spans 2 bytes, fill in the start of the 2nd byte */
|
|
||||||
compressed[1 + (next_bit >> 3)] |= svalue >> (8 - (next_bit & 7) );
|
|
||||||
}
|
|
||||||
next_bit += 3;
|
|
||||||
}
|
|
||||||
/* done compressing to DXT1 */
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
/*
|
|
||||||
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 */
|
|
|
@ -1,435 +0,0 @@
|
||||||
/*
|
|
||||||
Jonathan Dummer
|
|
||||||
|
|
||||||
image helper functions
|
|
||||||
|
|
||||||
MIT license
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "image_helper.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
/* Upscaling the image uses simple bilinear interpolation */
|
|
||||||
int
|
|
||||||
up_scale_image
|
|
||||||
(
|
|
||||||
const unsigned char* const orig,
|
|
||||||
int width, int height, int channels,
|
|
||||||
unsigned char* resampled,
|
|
||||||
int resampled_width, int resampled_height
|
|
||||||
)
|
|
||||||
{
|
|
||||||
float dx, dy;
|
|
||||||
int x, y, c;
|
|
||||||
|
|
||||||
/* error(s) check */
|
|
||||||
if ( (width < 1) || (height < 1) ||
|
|
||||||
(resampled_width < 2) || (resampled_height < 2) ||
|
|
||||||
(channels < 1) ||
|
|
||||||
(NULL == orig) || (NULL == resampled) )
|
|
||||||
{
|
|
||||||
/* signify badness */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
for each given pixel in the new map, find the exact location
|
|
||||||
from the original map which would contribute to this guy
|
|
||||||
*/
|
|
||||||
dx = (width - 1.0f) / (resampled_width - 1.0f);
|
|
||||||
dy = (height - 1.0f) / (resampled_height - 1.0f);
|
|
||||||
for ( y = 0; y < resampled_height; ++y )
|
|
||||||
{
|
|
||||||
/* find the base y index and fractional offset from that */
|
|
||||||
float sampley = y * dy;
|
|
||||||
int inty = (int)sampley;
|
|
||||||
/* if( inty < 0 ) { inty = 0; } else */
|
|
||||||
if( inty > height - 2 ) { inty = height - 2; }
|
|
||||||
sampley -= inty;
|
|
||||||
for ( x = 0; x < resampled_width; ++x )
|
|
||||||
{
|
|
||||||
float samplex = x * dx;
|
|
||||||
int intx = (int)samplex;
|
|
||||||
int base_index;
|
|
||||||
/* find the base x index and fractional offset from that */
|
|
||||||
/* if( intx < 0 ) { intx = 0; } else */
|
|
||||||
if( intx > width - 2 ) { intx = width - 2; }
|
|
||||||
samplex -= intx;
|
|
||||||
/* base index into the original image */
|
|
||||||
base_index = (inty * width + intx) * channels;
|
|
||||||
for ( c = 0; c < channels; ++c )
|
|
||||||
{
|
|
||||||
/* do the sampling */
|
|
||||||
float value = 0.5f;
|
|
||||||
value += orig[base_index]
|
|
||||||
*(1.0f-samplex)*(1.0f-sampley);
|
|
||||||
value += orig[base_index+channels]
|
|
||||||
*(samplex)*(1.0f-sampley);
|
|
||||||
value += orig[base_index+width*channels]
|
|
||||||
*(1.0f-samplex)*(sampley);
|
|
||||||
value += orig[base_index+width*channels+channels]
|
|
||||||
*(samplex)*(sampley);
|
|
||||||
/* move to the next channel */
|
|
||||||
++base_index;
|
|
||||||
/* save the new value */
|
|
||||||
resampled[y*resampled_width*channels+x*channels+c] =
|
|
||||||
(unsigned char)(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* done */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int mip_width, mip_height;
|
|
||||||
int i, j, c;
|
|
||||||
|
|
||||||
/* error check */
|
|
||||||
if( (width < 1) || (height < 1) ||
|
|
||||||
(channels < 1) || (orig == NULL) ||
|
|
||||||
(resampled == NULL) ||
|
|
||||||
(block_size_x < 1) || (block_size_y < 1) )
|
|
||||||
{
|
|
||||||
/* nothing to do */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
mip_width = width / block_size_x;
|
|
||||||
mip_height = height / block_size_y;
|
|
||||||
if( mip_width < 1 )
|
|
||||||
{
|
|
||||||
mip_width = 1;
|
|
||||||
}
|
|
||||||
if( mip_height < 1 )
|
|
||||||
{
|
|
||||||
mip_height = 1;
|
|
||||||
}
|
|
||||||
for( j = 0; j < mip_height; ++j )
|
|
||||||
{
|
|
||||||
for( i = 0; i < mip_width; ++i )
|
|
||||||
{
|
|
||||||
for( c = 0; c < channels; ++c )
|
|
||||||
{
|
|
||||||
const int index = (j*block_size_y)*width*channels + (i*block_size_x)*channels + c;
|
|
||||||
int sum_value;
|
|
||||||
int u,v;
|
|
||||||
int u_block = block_size_x;
|
|
||||||
int v_block = block_size_y;
|
|
||||||
int block_area;
|
|
||||||
/* do a bit of checking so we don't over-run the boundaries
|
|
||||||
(necessary for non-square textures!) */
|
|
||||||
if( block_size_x * (i+1) > width )
|
|
||||||
{
|
|
||||||
u_block = width - i*block_size_y;
|
|
||||||
}
|
|
||||||
if( block_size_y * (j+1) > height )
|
|
||||||
{
|
|
||||||
v_block = height - j*block_size_y;
|
|
||||||
}
|
|
||||||
block_area = u_block*v_block;
|
|
||||||
/* for this pixel, see what the average
|
|
||||||
of all the values in the block are.
|
|
||||||
note: start the sum at the rounding value, not at 0 */
|
|
||||||
sum_value = block_area >> 1;
|
|
||||||
for( v = 0; v < v_block; ++v )
|
|
||||||
for( u = 0; u < u_block; ++u )
|
|
||||||
{
|
|
||||||
sum_value += orig[index + v*width*channels + u*channels];
|
|
||||||
}
|
|
||||||
resampled[j*mip_width*channels + i*channels + c] = sum_value / block_area;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
scale_image_RGB_to_NTSC_safe
|
|
||||||
(
|
|
||||||
unsigned char* orig,
|
|
||||||
int width, int height, int channels
|
|
||||||
)
|
|
||||||
{
|
|
||||||
const float scale_lo = 16.0f - 0.499f;
|
|
||||||
const float scale_hi = 235.0f + 0.499f;
|
|
||||||
int i, j;
|
|
||||||
int nc = channels;
|
|
||||||
unsigned char scale_LUT[256];
|
|
||||||
/* error check */
|
|
||||||
if( (width < 1) || (height < 1) ||
|
|
||||||
(channels < 1) || (orig == NULL) )
|
|
||||||
{
|
|
||||||
/* nothing to do */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* set up the scaling Look Up Table */
|
|
||||||
for( i = 0; i < 256; ++i )
|
|
||||||
{
|
|
||||||
scale_LUT[i] = (unsigned char)((scale_hi - scale_lo) * i / 255.0f + scale_lo);
|
|
||||||
}
|
|
||||||
/* for channels = 2 or 4, ignore the alpha component */
|
|
||||||
nc -= 1 - (channels & 1);
|
|
||||||
/* OK, go through the image and scale any non-alpha components */
|
|
||||||
for( i = 0; i < width*height*channels; i += channels )
|
|
||||||
{
|
|
||||||
for( j = 0; j < nc; ++j )
|
|
||||||
{
|
|
||||||
orig[i+j] = scale_LUT[orig[i+j]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char clamp_byte( int x ) { return ( (x) < 0 ? (0) : ( (x) > 255 ? 255 : (x) ) ); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
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
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
/* error check */
|
|
||||||
if( (width < 1) || (height < 1) ||
|
|
||||||
(channels < 3) || (channels > 4) ||
|
|
||||||
(orig == NULL) )
|
|
||||||
{
|
|
||||||
/* nothing to do */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* do the conversion */
|
|
||||||
if( channels == 3 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < width*height*3; i += 3 )
|
|
||||||
{
|
|
||||||
int r = orig[i+0];
|
|
||||||
int g = (orig[i+1] + 1) >> 1;
|
|
||||||
int b = orig[i+2];
|
|
||||||
int tmp = (2 + r + b) >> 2;
|
|
||||||
/* Co */
|
|
||||||
orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) );
|
|
||||||
/* Y */
|
|
||||||
orig[i+1] = clamp_byte( g + tmp );
|
|
||||||
/* Cg */
|
|
||||||
orig[i+2] = clamp_byte( 128 + g - tmp );
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
for( i = 0; i < width*height*4; i += 4 )
|
|
||||||
{
|
|
||||||
int r = orig[i+0];
|
|
||||||
int g = (orig[i+1] + 1) >> 1;
|
|
||||||
int b = orig[i+2];
|
|
||||||
unsigned char a = orig[i+3];
|
|
||||||
int tmp = (2 + r + b) >> 2;
|
|
||||||
/* Co */
|
|
||||||
orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) );
|
|
||||||
/* Cg */
|
|
||||||
orig[i+1] = clamp_byte( 128 + g - tmp );
|
|
||||||
/* Alpha */
|
|
||||||
orig[i+2] = a;
|
|
||||||
/* Y */
|
|
||||||
orig[i+3] = clamp_byte( g + tmp );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* done */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
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
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
/* error check */
|
|
||||||
if( (width < 1) || (height < 1) ||
|
|
||||||
(channels < 3) || (channels > 4) ||
|
|
||||||
(orig == NULL) )
|
|
||||||
{
|
|
||||||
/* nothing to do */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* do the conversion */
|
|
||||||
if( channels == 3 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < width*height*3; i += 3 )
|
|
||||||
{
|
|
||||||
int co = orig[i+0] - 128;
|
|
||||||
int y = orig[i+1];
|
|
||||||
int cg = orig[i+2] - 128;
|
|
||||||
/* R */
|
|
||||||
orig[i+0] = clamp_byte( y + co - cg );
|
|
||||||
/* G */
|
|
||||||
orig[i+1] = clamp_byte( y + cg );
|
|
||||||
/* B */
|
|
||||||
orig[i+2] = clamp_byte( y - co - cg );
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
for( i = 0; i < width*height*4; i += 4 )
|
|
||||||
{
|
|
||||||
int co = orig[i+0] - 128;
|
|
||||||
int cg = orig[i+1] - 128;
|
|
||||||
unsigned char a = orig[i+2];
|
|
||||||
int y = orig[i+3];
|
|
||||||
/* R */
|
|
||||||
orig[i+0] = clamp_byte( y + co - cg );
|
|
||||||
/* G */
|
|
||||||
orig[i+1] = clamp_byte( y + cg );
|
|
||||||
/* B */
|
|
||||||
orig[i+2] = clamp_byte( y - co - cg );
|
|
||||||
/* A */
|
|
||||||
orig[i+3] = a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* done */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float
|
|
||||||
find_max_RGBE
|
|
||||||
(
|
|
||||||
unsigned char *image,
|
|
||||||
int width, int height
|
|
||||||
)
|
|
||||||
{
|
|
||||||
float max_val = 0.0f;
|
|
||||||
unsigned char *img = image;
|
|
||||||
int i, j;
|
|
||||||
for( i = width * height; i > 0; --i )
|
|
||||||
{
|
|
||||||
/* float scale = powf( 2.0f, img[3] - 128.0f ) / 255.0f; */
|
|
||||||
float scale = ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );
|
|
||||||
for( j = 0; j < 3; ++j )
|
|
||||||
{
|
|
||||||
if( img[j] * scale > max_val )
|
|
||||||
{
|
|
||||||
max_val = img[j] * scale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* next pixel */
|
|
||||||
img += 4;
|
|
||||||
}
|
|
||||||
return max_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
RGBE_to_RGBdivA
|
|
||||||
(
|
|
||||||
unsigned char *image,
|
|
||||||
int width, int height,
|
|
||||||
int rescale_to_max
|
|
||||||
)
|
|
||||||
{
|
|
||||||
/* local variables */
|
|
||||||
int i, iv;
|
|
||||||
unsigned char *img = image;
|
|
||||||
float scale = 1.0f;
|
|
||||||
/* error check */
|
|
||||||
if( (!image) || (width < 1) || (height < 1) )
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* convert (note: no negative numbers, but 0.0 is possible) */
|
|
||||||
if( rescale_to_max )
|
|
||||||
{
|
|
||||||
scale = 255.0f / find_max_RGBE( image, width, height );
|
|
||||||
}
|
|
||||||
for( i = width * height; i > 0; --i )
|
|
||||||
{
|
|
||||||
/* decode this pixel, and find the max */
|
|
||||||
float r,g,b,e, m;
|
|
||||||
/* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */
|
|
||||||
e = scale * ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );
|
|
||||||
r = e * img[0];
|
|
||||||
g = e * img[1];
|
|
||||||
b = e * img[2];
|
|
||||||
m = (r > g) ? r : g;
|
|
||||||
m = (b > m) ? b : m;
|
|
||||||
/* and encode it into RGBdivA */
|
|
||||||
iv = (m != 0.0f) ? (int)(255.0f / m) : 1.0f;
|
|
||||||
iv = (iv < 1) ? 1 : iv;
|
|
||||||
img[3] = (iv > 255) ? 255 : iv;
|
|
||||||
iv = (int)(img[3] * r + 0.5f);
|
|
||||||
img[0] = (iv > 255) ? 255 : iv;
|
|
||||||
iv = (int)(img[3] * g + 0.5f);
|
|
||||||
img[1] = (iv > 255) ? 255 : iv;
|
|
||||||
iv = (int)(img[3] * b + 0.5f);
|
|
||||||
img[2] = (iv > 255) ? 255 : iv;
|
|
||||||
/* and on to the next pixel */
|
|
||||||
img += 4;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
RGBE_to_RGBdivA2
|
|
||||||
(
|
|
||||||
unsigned char *image,
|
|
||||||
int width, int height,
|
|
||||||
int rescale_to_max
|
|
||||||
)
|
|
||||||
{
|
|
||||||
/* local variables */
|
|
||||||
int i, iv;
|
|
||||||
unsigned char *img = image;
|
|
||||||
float scale = 1.0f;
|
|
||||||
/* error check */
|
|
||||||
if( (!image) || (width < 1) || (height < 1) )
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* convert (note: no negative numbers, but 0.0 is possible) */
|
|
||||||
if( rescale_to_max )
|
|
||||||
{
|
|
||||||
scale = 255.0f * 255.0f / find_max_RGBE( image, width, height );
|
|
||||||
}
|
|
||||||
for( i = width * height; i > 0; --i )
|
|
||||||
{
|
|
||||||
/* decode this pixel, and find the max */
|
|
||||||
float r,g,b,e, m;
|
|
||||||
/* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */
|
|
||||||
e = scale * ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );
|
|
||||||
r = e * img[0];
|
|
||||||
g = e * img[1];
|
|
||||||
b = e * img[2];
|
|
||||||
m = (r > g) ? r : g;
|
|
||||||
m = (b > m) ? b : m;
|
|
||||||
/* and encode it into RGBdivA */
|
|
||||||
iv = (m != 0.0f) ? (int)sqrtf( 255.0f * 255.0f / m ) : 1.0f;
|
|
||||||
iv = (iv < 1) ? 1 : iv;
|
|
||||||
img[3] = (iv > 255) ? 255 : iv;
|
|
||||||
iv = (int)(img[3] * img[3] * r / 255.0f + 0.5f);
|
|
||||||
img[0] = (iv > 255) ? 255 : iv;
|
|
||||||
iv = (int)(img[3] * img[3] * g / 255.0f + 0.5f);
|
|
||||||
img[1] = (iv > 255) ? 255 : iv;
|
|
||||||
iv = (int)(img[3] * img[3] * b / 255.0f + 0.5f);
|
|
||||||
img[2] = (iv > 255) ? 255 : iv;
|
|
||||||
/* and on to the next pixel */
|
|
||||||
img += 4;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
/*
|
|
||||||
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 */
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,354 +0,0 @@
|
||||||
/* stbi-1.16 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c
|
|
||||||
when you control the images you're loading
|
|
||||||
|
|
||||||
QUICK NOTES:
|
|
||||||
Primarily of interest to game developers and other people who can
|
|
||||||
avoid problematic images and only need the trivial interface
|
|
||||||
|
|
||||||
JPEG baseline (no JPEG progressive, no oddball channel decimations)
|
|
||||||
PNG non-interlaced
|
|
||||||
BMP non-1bpp, non-RLE
|
|
||||||
TGA (not sure what subset, if a subset)
|
|
||||||
PSD (composited view only, no extra channels)
|
|
||||||
HDR (radiance rgbE format)
|
|
||||||
writes BMP,TGA (define STBI_NO_WRITE to remove code)
|
|
||||||
decoded from memory or through stdio FILE (define STBI_NO_STDIO to remove code)
|
|
||||||
supports installable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD)
|
|
||||||
|
|
||||||
TODO:
|
|
||||||
stbi_info_*
|
|
||||||
|
|
||||||
history:
|
|
||||||
1.16 major bugfix - convert_format converted one too many pixels
|
|
||||||
1.15 initialize some fields for thread safety
|
|
||||||
1.14 fix threadsafe conversion bug; header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
|
|
||||||
1.13 threadsafe
|
|
||||||
1.12 const qualifiers in the API
|
|
||||||
1.11 Support installable IDCT, colorspace conversion routines
|
|
||||||
1.10 Fixes for 64-bit (don't use "unsigned long")
|
|
||||||
optimized upsampling by Fabian "ryg" Giesen
|
|
||||||
1.09 Fix format-conversion for PSD code (bad global variables!)
|
|
||||||
1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz
|
|
||||||
1.07 attempt to fix C++ warning/errors again
|
|
||||||
1.06 attempt to fix C++ warning/errors again
|
|
||||||
1.05 fix TGA loading to return correct *comp and use good luminance calc
|
|
||||||
1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free
|
|
||||||
1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR
|
|
||||||
1.02 support for (subset of) HDR files, float interface for preferred access to them
|
|
||||||
1.01 fix bug: possible bug in handling right-side up bmps... not sure
|
|
||||||
fix bug: the stbi_bmp_load() and stbi_tga_load() functions didn't work at all
|
|
||||||
1.00 interface to zlib that skips zlib header
|
|
||||||
0.99 correct handling of alpha in palette
|
|
||||||
0.98 TGA loader by lonesock; dynamically add loaders (untested)
|
|
||||||
0.97 jpeg errors on too large a file; also catch another malloc failure
|
|
||||||
0.96 fix detection of invalid v value - particleman@mollyrocket forum
|
|
||||||
0.95 during header scan, seek to markers in case of padding
|
|
||||||
0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same
|
|
||||||
0.93 handle jpegtran output; verbose errors
|
|
||||||
0.92 read 4,8,16,24,32-bit BMP files of several formats
|
|
||||||
0.91 output 24-bit Windows 3.0 BMP files
|
|
||||||
0.90 fix a few more warnings; bump version number to approach 1.0
|
|
||||||
0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd
|
|
||||||
0.60 fix compiling as c++
|
|
||||||
0.59 fix warnings: merge Dave Moore's -Wall fixes
|
|
||||||
0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian
|
|
||||||
0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less
|
|
||||||
than 16 available
|
|
||||||
0.56 fix bug: zlib uncompressed mode len vs. nlen
|
|
||||||
0.55 fix bug: restart_interval not initialized to 0
|
|
||||||
0.54 allow NULL for 'int *comp'
|
|
||||||
0.53 fix bug in png 3->4; speedup png decoding
|
|
||||||
0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments
|
|
||||||
0.51 obey req_comp requests, 1-component jpegs return as 1-component,
|
|
||||||
on 'test' only check type, not whether we support this variant
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef HEADER_STB_IMAGE_AUGMENTED
|
|
||||||
#define HEADER_STB_IMAGE_AUGMENTED
|
|
||||||
|
|
||||||
//// begin header file ////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Limitations:
|
|
||||||
// - no progressive/interlaced support (jpeg, png)
|
|
||||||
// - 8-bit samples only (jpeg, png)
|
|
||||||
// - not threadsafe
|
|
||||||
// - channel subsampling of at most 2 in each dimension (jpeg)
|
|
||||||
// - no delayed line count (jpeg) -- IJG doesn't support either
|
|
||||||
//
|
|
||||||
// Basic usage (see HDR discussion below):
|
|
||||||
// int x,y,n;
|
|
||||||
// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
|
|
||||||
// // ... process data if not NULL ...
|
|
||||||
// // ... x = width, y = height, n = # 8-bit components per pixel ...
|
|
||||||
// // ... replace '0' with '1'..'4' to force that many components per pixel
|
|
||||||
// stbi_image_free(data)
|
|
||||||
//
|
|
||||||
// Standard parameters:
|
|
||||||
// int *x -- outputs image width in pixels
|
|
||||||
// int *y -- outputs image height in pixels
|
|
||||||
// int *comp -- outputs # of image components in image file
|
|
||||||
// int req_comp -- if non-zero, # of image components requested in result
|
|
||||||
//
|
|
||||||
// The return value from an image loader is an 'unsigned char *' which points
|
|
||||||
// to the pixel data. The pixel data consists of *y scanlines of *x pixels,
|
|
||||||
// with each pixel consisting of N interleaved 8-bit components; the first
|
|
||||||
// pixel pointed to is top-left-most in the image. There is no padding between
|
|
||||||
// image scanlines or between pixels, regardless of format. The number of
|
|
||||||
// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
|
|
||||||
// If req_comp is non-zero, *comp has the number of components that _would_
|
|
||||||
// have been output otherwise. E.g. if you set req_comp to 4, you will always
|
|
||||||
// get RGBA output, but you can check *comp to easily see if it's opaque.
|
|
||||||
//
|
|
||||||
// An output image with N components has the following components interleaved
|
|
||||||
// in this order in each pixel:
|
|
||||||
//
|
|
||||||
// N=#comp components
|
|
||||||
// 1 grey
|
|
||||||
// 2 grey, alpha
|
|
||||||
// 3 red, green, blue
|
|
||||||
// 4 red, green, blue, alpha
|
|
||||||
//
|
|
||||||
// If image loading fails for any reason, the return value will be NULL,
|
|
||||||
// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
|
|
||||||
// can be queried for an extremely brief, end-user unfriendly explanation
|
|
||||||
// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
|
|
||||||
// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
|
|
||||||
// more user-friendly ones.
|
|
||||||
//
|
|
||||||
// Paletted PNG and BMP images are automatically depalettized.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// ===========================================================================
|
|
||||||
//
|
|
||||||
// HDR image support (disable by defining STBI_NO_HDR)
|
|
||||||
//
|
|
||||||
// stb_image now supports loading HDR images in general, and currently
|
|
||||||
// the Radiance .HDR file format, although the support is provided
|
|
||||||
// generically. You can still load any file through the existing interface;
|
|
||||||
// if you attempt to load an HDR file, it will be automatically remapped to
|
|
||||||
// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
|
|
||||||
// both of these constants can be reconfigured through this interface:
|
|
||||||
//
|
|
||||||
// stbi_hdr_to_ldr_gamma(2.2f);
|
|
||||||
// stbi_hdr_to_ldr_scale(1.0f);
|
|
||||||
//
|
|
||||||
// (note, do not use _inverse_ constants; stbi_image will invert them
|
|
||||||
// appropriately).
|
|
||||||
//
|
|
||||||
// Additionally, there is a new, parallel interface for loading files as
|
|
||||||
// (linear) floats to preserve the full dynamic range:
|
|
||||||
//
|
|
||||||
// float *data = stbi_loadf(filename, &x, &y, &n, 0);
|
|
||||||
//
|
|
||||||
// If you load LDR images through this interface, those images will
|
|
||||||
// be promoted to floating point values, run through the inverse of
|
|
||||||
// constants corresponding to the above:
|
|
||||||
//
|
|
||||||
// stbi_ldr_to_hdr_scale(1.0f);
|
|
||||||
// stbi_ldr_to_hdr_gamma(2.2f);
|
|
||||||
//
|
|
||||||
// Finally, given a filename (or an open file or memory block--see header
|
|
||||||
// file for details) containing image data, you can query for the "most
|
|
||||||
// appropriate" interface to use (that is, whether the image is HDR or
|
|
||||||
// not), using:
|
|
||||||
//
|
|
||||||
// stbi_is_hdr(char *filename);
|
|
||||||
|
|
||||||
#ifndef STBI_NO_STDIO
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define STBI_VERSION 1
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
STBI_default = 0, // only used for req_comp
|
|
||||||
|
|
||||||
STBI_grey = 1,
|
|
||||||
STBI_grey_alpha = 2,
|
|
||||||
STBI_rgb = 3,
|
|
||||||
STBI_rgb_alpha = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef unsigned char stbi_uc;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// WRITING API
|
|
||||||
|
|
||||||
#if !defined(STBI_NO_WRITE) && !defined(STBI_NO_STDIO)
|
|
||||||
// write a BMP/TGA file given tightly packed 'comp' channels (no padding, nor bmp-stride-padding)
|
|
||||||
// (you must include the appropriate extension in the filename).
|
|
||||||
// returns TRUE on success, FALSE if couldn't open file, error writing file
|
|
||||||
extern int stbi_write_bmp (char const *filename, int x, int y, int comp, void *data);
|
|
||||||
extern int stbi_write_tga (char const *filename, int x, int y, int comp, void *data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// PRIMARY API - works on images of any type
|
|
||||||
|
|
||||||
// load image by filename, open file, or memory buffer
|
|
||||||
#ifndef STBI_NO_STDIO
|
|
||||||
extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
|
|
||||||
#endif
|
|
||||||
extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
|
|
||||||
// for stbi_load_from_file, file pointer is left pointing immediately after image
|
|
||||||
|
|
||||||
#ifndef STBI_NO_HDR
|
|
||||||
#ifndef STBI_NO_STDIO
|
|
||||||
extern float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
|
|
||||||
#endif
|
|
||||||
extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
|
|
||||||
|
|
||||||
extern void stbi_hdr_to_ldr_gamma(float gammafactor);
|
|
||||||
extern void stbi_hdr_to_ldr_scale(float scale);
|
|
||||||
|
|
||||||
extern void stbi_ldr_to_hdr_gamma(float gammafactor);
|
|
||||||
extern void stbi_ldr_to_hdr_scale(float scale);
|
|
||||||
|
|
||||||
#endif // STBI_NO_HDR
|
|
||||||
|
|
||||||
// get a VERY brief reason for failure
|
|
||||||
// NOT THREADSAFE
|
|
||||||
extern const char *stbi_failure_reason (void);
|
|
||||||
|
|
||||||
// free the loaded image -- this is just free()
|
|
||||||
extern void stbi_image_free (void *retval_from_stbi_load);
|
|
||||||
|
|
||||||
// get image dimensions & components without fully decoding
|
|
||||||
extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
|
|
||||||
extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
|
|
||||||
#ifndef STBI_NO_STDIO
|
|
||||||
extern int stbi_info (char const *filename, int *x, int *y, int *comp);
|
|
||||||
extern int stbi_is_hdr (char const *filename);
|
|
||||||
extern int stbi_is_hdr_from_file(FILE *f);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ZLIB client - used by PNG, available for other purposes
|
|
||||||
|
|
||||||
extern char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
|
|
||||||
extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
|
|
||||||
extern int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
|
|
||||||
|
|
||||||
extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
|
|
||||||
extern int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
|
|
||||||
|
|
||||||
// TYPE-SPECIFIC ACCESS
|
|
||||||
|
|
||||||
// is it a jpeg?
|
|
||||||
extern int stbi_jpeg_test_memory (stbi_uc const *buffer, int len);
|
|
||||||
extern stbi_uc *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
|
|
||||||
|
|
||||||
#ifndef STBI_NO_STDIO
|
|
||||||
extern stbi_uc *stbi_jpeg_load (char const *filename, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern int stbi_jpeg_test_file (FILE *f);
|
|
||||||
extern stbi_uc *stbi_jpeg_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
|
|
||||||
|
|
||||||
extern int stbi_jpeg_info (char const *filename, int *x, int *y, int *comp);
|
|
||||||
extern int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// is it a png?
|
|
||||||
extern int stbi_png_test_memory (stbi_uc const *buffer, int len);
|
|
||||||
extern stbi_uc *stbi_png_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp);
|
|
||||||
|
|
||||||
#ifndef STBI_NO_STDIO
|
|
||||||
extern stbi_uc *stbi_png_load (char const *filename, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern int stbi_png_info (char const *filename, int *x, int *y, int *comp);
|
|
||||||
extern int stbi_png_test_file (FILE *f);
|
|
||||||
extern stbi_uc *stbi_png_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// is it a bmp?
|
|
||||||
extern int stbi_bmp_test_memory (stbi_uc const *buffer, int len);
|
|
||||||
|
|
||||||
extern stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern stbi_uc *stbi_bmp_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_bmp_test_file (FILE *f);
|
|
||||||
extern stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// is it a tga?
|
|
||||||
extern int stbi_tga_test_memory (stbi_uc const *buffer, int len);
|
|
||||||
|
|
||||||
extern stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern stbi_uc *stbi_tga_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_tga_test_file (FILE *f);
|
|
||||||
extern stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// is it a psd?
|
|
||||||
extern int stbi_psd_test_memory (stbi_uc const *buffer, int len);
|
|
||||||
|
|
||||||
extern stbi_uc *stbi_psd_load (char const *filename, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern stbi_uc *stbi_psd_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_psd_test_file (FILE *f);
|
|
||||||
extern stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// is it an hdr?
|
|
||||||
extern int stbi_hdr_test_memory (stbi_uc const *buffer, int len);
|
|
||||||
|
|
||||||
extern float * stbi_hdr_load (char const *filename, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern stbi_uc *stbi_hdr_load_rgbe (char const *filename, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern float * stbi_hdr_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_hdr_test_file (FILE *f);
|
|
||||||
extern float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
|
|
||||||
extern stbi_uc *stbi_hdr_load_rgbe_file (FILE *f, int *x, int *y, int *comp, int req_comp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// define new loaders
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int (*test_memory)(stbi_uc const *buffer, int len);
|
|
||||||
stbi_uc * (*load_from_memory)(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
|
|
||||||
#ifndef STBI_NO_STDIO
|
|
||||||
int (*test_file)(FILE *f);
|
|
||||||
stbi_uc * (*load_from_file)(FILE *f, int *x, int *y, int *comp, int req_comp);
|
|
||||||
#endif
|
|
||||||
} stbi_loader;
|
|
||||||
|
|
||||||
// register a loader by filling out the above structure (you must defined ALL functions)
|
|
||||||
// returns 1 if added or already added, 0 if not added (too many loaders)
|
|
||||||
// NOT THREADSAFE
|
|
||||||
extern int stbi_register_loader(stbi_loader *loader);
|
|
||||||
|
|
||||||
// define faster low-level operations (typically SIMD support)
|
|
||||||
#if STBI_SIMD
|
|
||||||
typedef void (*stbi_idct_8x8)(uint8 *out, int out_stride, short data[64], unsigned short *dequantize);
|
|
||||||
// compute an integer IDCT on "input"
|
|
||||||
// input[x] = data[x] * dequantize[x]
|
|
||||||
// write results to 'out': 64 samples, each run of 8 spaced by 'out_stride'
|
|
||||||
// CLAMP results to 0..255
|
|
||||||
typedef void (*stbi_YCbCr_to_RGB_run)(uint8 *output, uint8 const *y, uint8 const *cb, uint8 const *cr, int count, int step);
|
|
||||||
// compute a conversion from YCbCr to RGB
|
|
||||||
// 'count' pixels
|
|
||||||
// write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B
|
|
||||||
// y: Y input channel
|
|
||||||
// cb: Cb input channel; scale/biased to be 0..255
|
|
||||||
// cr: Cr input channel; scale/biased to be 0..255
|
|
||||||
|
|
||||||
extern void stbi_install_idct(stbi_idct_8x8 func);
|
|
||||||
extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func);
|
|
||||||
#endif // STBI_SIMD
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//// end header file /////////////////////////////////////////////////////
|
|
||||||
#endif // STBI_INCLUDE_STB_IMAGE_H
|
|
|
@ -1,21 +0,0 @@
|
||||||
/*
|
|
||||||
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
|
|
|
@ -1,512 +0,0 @@
|
||||||
|
|
||||||
/// 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];
|
|
||||||
unsigned int flags;
|
|
||||||
int DXT_family;
|
|
||||||
int has_alpha, has_mipmap;
|
|
||||||
int is_compressed, cubemap_faces;
|
|
||||||
int block_pitch, cf;
|
|
||||||
DDS_header header;
|
|
||||||
unsigned int i, num_blocks, sz;
|
|
||||||
// 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;
|
|
||||||
unsigned int ref_x = 4 * (i % block_pitch);
|
|
||||||
unsigned 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);
|
|
||||||
}
|
|
|
@ -54,8 +54,6 @@ Dolphin includes or links code of the following third-party software projects:
|
||||||
[zlib license](http://hg.libsdl.org/SDL/file/tip/COPYING.txt)
|
[zlib license](http://hg.libsdl.org/SDL/file/tip/COPYING.txt)
|
||||||
- [SFML](http://www.sfml-dev.org/):
|
- [SFML](http://www.sfml-dev.org/):
|
||||||
[zlib license](http://www.sfml-dev.org/license.php)
|
[zlib license](http://www.sfml-dev.org/license.php)
|
||||||
- [SOIL](http://www.lonesock.net/soil.html):
|
|
||||||
[public domain](http://www.lonesock.net/soil.html)
|
|
||||||
- [SoundTouch](http://www.surina.net/soundtouch/):
|
- [SoundTouch](http://www.surina.net/soundtouch/):
|
||||||
[LGPLv2+](http://www.surina.net/soundtouch/license.html)
|
[LGPLv2+](http://www.surina.net/soundtouch/license.html)
|
||||||
- [TAP-Windows](https://openvpn.net/):
|
- [TAP-Windows](https://openvpn.net/):
|
||||||
|
|
|
@ -60,14 +60,12 @@ BuildRequires: openal-soft-devel
|
||||||
BuildRequires: mbedtls-devel
|
BuildRequires: mbedtls-devel
|
||||||
BuildRequires: SDL2-devel
|
BuildRequires: SDL2-devel
|
||||||
BuildRequires: SFML-devel
|
BuildRequires: SFML-devel
|
||||||
BuildRequires: SOIL-devel
|
|
||||||
BuildRequires: soundtouch-devel
|
BuildRequires: soundtouch-devel
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%if 0%{?suse_version}
|
%if 0%{?suse_version}
|
||||||
BuildRequires: libminiupnpc-devel
|
BuildRequires: libminiupnpc-devel
|
||||||
BuildRequires: libSDL2-devel
|
BuildRequires: libSDL2-devel
|
||||||
BuildRequires: libSOIL-devel
|
|
||||||
BuildRequires: lzo-devel
|
BuildRequires: lzo-devel
|
||||||
BuildRequires: openal-devel
|
BuildRequires: openal-devel
|
||||||
BuildRequires: sfml-devel
|
BuildRequires: sfml-devel
|
||||||
|
|
|
@ -18,6 +18,7 @@ add_library(common
|
||||||
GekkoDisassembler.cpp
|
GekkoDisassembler.cpp
|
||||||
Hash.cpp
|
Hash.cpp
|
||||||
HttpRequest.cpp
|
HttpRequest.cpp
|
||||||
|
Image.cpp
|
||||||
IniFile.cpp
|
IniFile.cpp
|
||||||
JitRegister.cpp
|
JitRegister.cpp
|
||||||
Logging/LogManager.cpp
|
Logging/LogManager.cpp
|
||||||
|
@ -54,6 +55,7 @@ PUBLIC
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${CURL_LIBRARIES}
|
${CURL_LIBRARIES}
|
||||||
${ICONV_LIBRARIES}
|
${ICONV_LIBRARIES}
|
||||||
|
png
|
||||||
${VTUNE_LIBRARIES}
|
${VTUNE_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,7 @@
|
||||||
<ClInclude Include="FloatUtils.h" />
|
<ClInclude Include="FloatUtils.h" />
|
||||||
<ClInclude Include="Hash.h" />
|
<ClInclude Include="Hash.h" />
|
||||||
<ClInclude Include="HttpRequest.h" />
|
<ClInclude Include="HttpRequest.h" />
|
||||||
|
<ClInclude Include="Image.h" />
|
||||||
<ClInclude Include="IniFile.h" />
|
<ClInclude Include="IniFile.h" />
|
||||||
<ClInclude Include="JitRegister.h" />
|
<ClInclude Include="JitRegister.h" />
|
||||||
<ClInclude Include="Lazy.h" />
|
<ClInclude Include="Lazy.h" />
|
||||||
|
@ -188,6 +189,7 @@
|
||||||
<ClCompile Include="GL\GLUtil.cpp" />
|
<ClCompile Include="GL\GLUtil.cpp" />
|
||||||
<ClCompile Include="Hash.cpp" />
|
<ClCompile Include="Hash.cpp" />
|
||||||
<ClCompile Include="HttpRequest.cpp" />
|
<ClCompile Include="HttpRequest.cpp" />
|
||||||
|
<ClCompile Include="Image.cpp" />
|
||||||
<ClCompile Include="IniFile.cpp" />
|
<ClCompile Include="IniFile.cpp" />
|
||||||
<ClCompile Include="JitRegister.cpp" />
|
<ClCompile Include="JitRegister.cpp" />
|
||||||
<ClCompile Include="LdrWatcher.cpp" />
|
<ClCompile Include="LdrWatcher.cpp" />
|
||||||
|
@ -230,6 +232,9 @@
|
||||||
<ProjectReference Include="$(ExternalsDir)mbedtls\mbedTLS.vcxproj">
|
<ProjectReference Include="$(ExternalsDir)mbedtls\mbedTLS.vcxproj">
|
||||||
<Project>{bdb6578b-0691-4e80-a46c-df21639fd3b8}</Project>
|
<Project>{bdb6578b-0691-4e80-a46c-df21639fd3b8}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="$(ExternalsDir)libpng\png\png.vcxproj">
|
||||||
|
<Project>{4c9f135b-a85e-430c-bad4-4c67ef5fc12c}</Project>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\..\..\Externals\curl\curl.vcxproj">
|
<ProjectReference Include="..\..\..\Externals\curl\curl.vcxproj">
|
||||||
<Project>{bb00605c-125f-4a21-b33b-7bf418322dcb}</Project>
|
<Project>{bb00605c-125f-4a21-b33b-7bf418322dcb}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
<ClInclude Include="FPURoundMode.h" />
|
<ClInclude Include="FPURoundMode.h" />
|
||||||
<ClInclude Include="Hash.h" />
|
<ClInclude Include="Hash.h" />
|
||||||
<ClInclude Include="HttpRequest.h" />
|
<ClInclude Include="HttpRequest.h" />
|
||||||
|
<ClInclude Include="Image.h" />
|
||||||
<ClInclude Include="IniFile.h" />
|
<ClInclude Include="IniFile.h" />
|
||||||
<ClInclude Include="LinearDiskCache.h" />
|
<ClInclude Include="LinearDiskCache.h" />
|
||||||
<ClInclude Include="MathUtil.h" />
|
<ClInclude Include="MathUtil.h" />
|
||||||
|
@ -281,6 +282,7 @@
|
||||||
<ClCompile Include="FloatUtils.cpp" />
|
<ClCompile Include="FloatUtils.cpp" />
|
||||||
<ClCompile Include="Hash.cpp" />
|
<ClCompile Include="Hash.cpp" />
|
||||||
<ClCompile Include="HttpRequest.cpp" />
|
<ClCompile Include="HttpRequest.cpp" />
|
||||||
|
<ClCompile Include="Image.cpp" />
|
||||||
<ClCompile Include="IniFile.cpp" />
|
<ClCompile Include="IniFile.cpp" />
|
||||||
<ClCompile Include="MathUtil.cpp" />
|
<ClCompile Include="MathUtil.cpp" />
|
||||||
<ClCompile Include="MemArena.cpp" />
|
<ClCompile Include="MemArena.cpp" />
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
// Copyright 2016 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Common/Image.h"
|
||||||
|
|
||||||
|
// Versions of libpng older than 1.5 want us to not include setjmp.h before png.h,
|
||||||
|
// so let's include png.h first of all headers
|
||||||
|
#include <png.h>
|
||||||
|
|
||||||
|
#include <csetjmp>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
|
static int MultiplyAlpha(int alpha, int color)
|
||||||
|
{
|
||||||
|
const int temp = (alpha * color) + 0x80;
|
||||||
|
return ((temp + (temp >> 8)) >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PremultiplyData(png_structp png, png_row_infop row_info, png_bytep data)
|
||||||
|
{
|
||||||
|
for (png_size_t i = 0; i < row_info->rowbytes; i += 4, data += 4)
|
||||||
|
{
|
||||||
|
const png_byte alpha = data[3];
|
||||||
|
u32 w;
|
||||||
|
|
||||||
|
if (alpha == 0)
|
||||||
|
{
|
||||||
|
w = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
png_byte red = data[0];
|
||||||
|
png_byte green = data[1];
|
||||||
|
png_byte blue = data[2];
|
||||||
|
|
||||||
|
if (alpha != 0xff)
|
||||||
|
{
|
||||||
|
red = MultiplyAlpha(alpha, red);
|
||||||
|
green = MultiplyAlpha(alpha, green);
|
||||||
|
blue = MultiplyAlpha(alpha, blue);
|
||||||
|
}
|
||||||
|
w = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(data, &w, sizeof(w));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ReadProgress
|
||||||
|
{
|
||||||
|
const u8* current;
|
||||||
|
const u8* end;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ReadCallback(png_structp png, png_bytep data, png_size_t size)
|
||||||
|
{
|
||||||
|
ReadProgress* progress = static_cast<ReadProgress*>(png_get_io_ptr(png));
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
if (progress->current >= progress->end)
|
||||||
|
png_error(png, "Read beyond end of file"); // This makes us longjmp back to LoadPNG
|
||||||
|
|
||||||
|
data[i] = *(progress->current);
|
||||||
|
++(progress->current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PNGErrorCallback(png_structp png, png_const_charp error_msg)
|
||||||
|
{
|
||||||
|
ERROR_LOG(COMMON, "PNG loading error: %s", error_msg);
|
||||||
|
longjmp(png_jmpbuf(png), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4611)
|
||||||
|
// VS shows the following warning even though no C++ objects are destroyed in LoadPNG:
|
||||||
|
// "warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool LoadPNG(const std::vector<u8>& input, std::vector<u8>* data_out, u32* width_out,
|
||||||
|
u32* height_out)
|
||||||
|
{
|
||||||
|
// The const_cast is only required for libpng versions older than 1.5
|
||||||
|
const bool is_png = !png_sig_cmp(const_cast<u8*>(input.data()), 0, input.size());
|
||||||
|
if (!is_png)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
png_struct* png =
|
||||||
|
png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, PNGErrorCallback, nullptr);
|
||||||
|
if (!png)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
png_info* info = png_create_info_struct(png);
|
||||||
|
if (!info)
|
||||||
|
{
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// It would've been nice to use std::vector for this, but using setjmp safely
|
||||||
|
// means that we have to use this manually managed volatile pointer garbage instead.
|
||||||
|
png_byte** volatile row_pointers_volatile = nullptr;
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png)))
|
||||||
|
{
|
||||||
|
free(row_pointers_volatile);
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadProgress read_progress{input.data(), input.data() + input.size()};
|
||||||
|
png_set_read_fn(png, &read_progress, ReadCallback);
|
||||||
|
png_read_info(png, info);
|
||||||
|
|
||||||
|
png_uint_32 width, height;
|
||||||
|
int depth, color_type, interlace;
|
||||||
|
png_get_IHDR(png, info, &width, &height, &depth, &color_type, &interlace, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
|
png_set_palette_to_rgb(png);
|
||||||
|
else if (color_type == PNG_COLOR_TYPE_GRAY)
|
||||||
|
png_set_expand_gray_1_2_4_to_8(png);
|
||||||
|
|
||||||
|
if (png_get_valid(png, info, PNG_INFO_tRNS))
|
||||||
|
png_set_tRNS_to_alpha(png);
|
||||||
|
|
||||||
|
if (depth == 16)
|
||||||
|
png_set_strip_16(png);
|
||||||
|
else if (depth < 8)
|
||||||
|
png_set_packing(png);
|
||||||
|
|
||||||
|
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||||
|
png_set_gray_to_rgb(png);
|
||||||
|
|
||||||
|
if (interlace != PNG_INTERLACE_NONE)
|
||||||
|
png_set_interlace_handling(png);
|
||||||
|
|
||||||
|
png_set_bgr(png);
|
||||||
|
png_set_filler(png, 0xff, PNG_FILLER_AFTER);
|
||||||
|
png_set_read_user_transform_fn(png, PremultiplyData);
|
||||||
|
png_read_update_info(png, info);
|
||||||
|
png_get_IHDR(png, info, &width, &height, &depth, &color_type, &interlace, nullptr, nullptr);
|
||||||
|
|
||||||
|
const size_t stride = width * 4;
|
||||||
|
data_out->resize(stride * height);
|
||||||
|
|
||||||
|
png_byte** row_pointers = static_cast<png_byte**>(malloc(height * sizeof(png_byte*)));
|
||||||
|
if (!row_pointers)
|
||||||
|
{
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (png_uint_32 i = 0; i < height; i++)
|
||||||
|
row_pointers[i] = &(*data_out)[i * stride];
|
||||||
|
|
||||||
|
row_pointers_volatile = row_pointers;
|
||||||
|
|
||||||
|
png_read_image(png, row_pointers);
|
||||||
|
png_read_end(png, info);
|
||||||
|
|
||||||
|
free(row_pointers);
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
|
||||||
|
*width_out = width;
|
||||||
|
*height_out = height;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Common
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2016 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
|
bool LoadPNG(const std::vector<u8>& input, std::vector<u8>* data_out, u32* width_out,
|
||||||
|
u32* height_out);
|
||||||
|
}
|
|
@ -46,7 +46,4 @@ target_link_libraries(videod3d
|
||||||
PUBLIC
|
PUBLIC
|
||||||
common
|
common
|
||||||
videocommon
|
videocommon
|
||||||
|
|
||||||
PRIVATE
|
|
||||||
SOIL
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,6 +24,5 @@ PUBLIC
|
||||||
videocommon
|
videocommon
|
||||||
|
|
||||||
PRIVATE
|
PRIVATE
|
||||||
SOIL
|
|
||||||
${X11_LIBRARIES}
|
${X11_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,6 +22,5 @@ PUBLIC
|
||||||
videocommon
|
videocommon
|
||||||
|
|
||||||
PRIVATE
|
PRIVATE
|
||||||
SOIL
|
|
||||||
${X11_LIBRARIES}
|
${X11_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#include "VideoCommon/HiresTextures.h"
|
#include "VideoCommon/HiresTextures.h"
|
||||||
|
|
||||||
#include <SOIL/SOIL.h>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -22,6 +21,7 @@
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/Flag.h"
|
#include "Common/Flag.h"
|
||||||
#include "Common/Hash.h"
|
#include "Common/Hash.h"
|
||||||
|
#include "Common/Image.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MemoryUtil.h"
|
#include "Common/MemoryUtil.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
@ -42,17 +42,12 @@ struct DiskTexture
|
||||||
static std::unordered_map<std::string, DiskTexture> s_textureMap;
|
static std::unordered_map<std::string, DiskTexture> s_textureMap;
|
||||||
static std::unordered_map<std::string, std::shared_ptr<HiresTexture>> s_textureCache;
|
static std::unordered_map<std::string, std::shared_ptr<HiresTexture>> s_textureCache;
|
||||||
static std::mutex s_textureCacheMutex;
|
static std::mutex s_textureCacheMutex;
|
||||||
static std::mutex s_textureCacheAquireMutex; // for high priority access
|
|
||||||
static Common::Flag s_textureCacheAbortLoading;
|
static Common::Flag s_textureCacheAbortLoading;
|
||||||
|
|
||||||
static std::thread s_prefetcher;
|
static std::thread s_prefetcher;
|
||||||
|
|
||||||
static const std::string s_format_prefix = "tex1_";
|
static const std::string s_format_prefix = "tex1_";
|
||||||
|
|
||||||
HiresTexture::Level::Level() : data(nullptr, SOIL_free_image_data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void HiresTexture::Init()
|
void HiresTexture::Init()
|
||||||
{
|
{
|
||||||
Update();
|
Update();
|
||||||
|
@ -92,10 +87,7 @@ void HiresTexture::Update()
|
||||||
|
|
||||||
const std::string& game_id = SConfig::GetInstance().GetGameID();
|
const std::string& game_id = SConfig::GetInstance().GetGameID();
|
||||||
const std::string texture_directory = GetTextureDirectory(game_id);
|
const std::string texture_directory = GetTextureDirectory(game_id);
|
||||||
std::vector<std::string> extensions{
|
const std::vector<std::string> extensions{".png", ".dds"};
|
||||||
".png", ".bmp", ".tga", ".dds",
|
|
||||||
".jpg" // Why not? Could be useful for large photo-like textures
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<std::string> texture_paths =
|
const std::vector<std::string> texture_paths =
|
||||||
Common::DoFileSearch({texture_directory}, extensions, /*recursive*/ true);
|
Common::DoFileSearch({texture_directory}, extensions, /*recursive*/ true);
|
||||||
|
@ -155,25 +147,16 @@ void HiresTexture::Prefetch()
|
||||||
|
|
||||||
if (base_filename.find("_mip") == std::string::npos)
|
if (base_filename.find("_mip") == std::string::npos)
|
||||||
{
|
{
|
||||||
{
|
|
||||||
// try to get this mutex first, so the video thread is allow to get the real mutex faster
|
|
||||||
std::unique_lock<std::mutex> lk(s_textureCacheAquireMutex);
|
|
||||||
}
|
|
||||||
std::unique_lock<std::mutex> lk(s_textureCacheMutex);
|
std::unique_lock<std::mutex> lk(s_textureCacheMutex);
|
||||||
|
|
||||||
auto iter = s_textureCache.find(base_filename);
|
auto iter = s_textureCache.find(base_filename);
|
||||||
if (iter == s_textureCache.end())
|
if (iter == s_textureCache.end())
|
||||||
{
|
{
|
||||||
// unlock while loading a texture. This may result in a race condition where we'll load a
|
// unlock while loading a texture. This may result in a race condition where
|
||||||
// texture twice,
|
// we'll load a texture twice, but it reduces the stuttering a lot.
|
||||||
// but it reduces the stuttering a lot. Notice: The loading library _must_ be thread safe
|
lk.unlock();
|
||||||
// now.
|
|
||||||
// But bad luck, SOIL isn't, so TODO: remove SOIL usage here and use libpng directly
|
|
||||||
// Also TODO: remove s_textureCacheAquireMutex afterwards. It won't be needed as the main
|
|
||||||
// mutex will be locked rarely
|
|
||||||
// lk.unlock();
|
|
||||||
std::unique_ptr<HiresTexture> texture = Load(base_filename, 0, 0);
|
std::unique_ptr<HiresTexture> texture = Load(base_filename, 0, 0);
|
||||||
// lk.lock();
|
lk.lock();
|
||||||
if (texture)
|
if (texture)
|
||||||
{
|
{
|
||||||
std::shared_ptr<HiresTexture> ptr(std::move(texture));
|
std::shared_ptr<HiresTexture> ptr(std::move(texture));
|
||||||
|
@ -183,9 +166,7 @@ void HiresTexture::Prefetch()
|
||||||
if (iter != s_textureCache.end())
|
if (iter != s_textureCache.end())
|
||||||
{
|
{
|
||||||
for (const Level& l : iter->second->m_levels)
|
for (const Level& l : iter->second->m_levels)
|
||||||
{
|
size_sum += l.data.size();
|
||||||
size_sum += l.data_size;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +287,6 @@ std::shared_ptr<HiresTexture> HiresTexture::Search(const u8* texture, size_t tex
|
||||||
std::string base_filename =
|
std::string base_filename =
|
||||||
GenBaseName(texture, texture_size, tlut, tlut_size, width, height, format, has_mipmaps);
|
GenBaseName(texture, texture_size, tlut, tlut_size, width, height, format, has_mipmaps);
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lk2(s_textureCacheAquireMutex);
|
|
||||||
std::lock_guard<std::mutex> lk(s_textureCacheMutex);
|
std::lock_guard<std::mutex> lk(s_textureCacheMutex);
|
||||||
|
|
||||||
auto iter = s_textureCache.find(base_filename);
|
auto iter = s_textureCache.find(base_filename);
|
||||||
|
@ -361,6 +341,7 @@ std::unique_ptr<HiresTexture> HiresTexture::Load(const std::string& base_filenam
|
||||||
file.Open(filename_iter->second.path, "rb");
|
file.Open(filename_iter->second.path, "rb");
|
||||||
std::vector<u8> buffer(file.GetSize());
|
std::vector<u8> buffer(file.GetSize());
|
||||||
file.ReadBytes(buffer.data(), file.GetSize());
|
file.ReadBytes(buffer.data(), file.GetSize());
|
||||||
|
|
||||||
if (!LoadTexture(level, buffer))
|
if (!LoadTexture(level, buffer))
|
||||||
{
|
{
|
||||||
ERROR_LOG(VIDEO, "Custom texture %s failed to load", filename.c_str());
|
ERROR_LOG(VIDEO, "Custom texture %s failed to load", filename.c_str());
|
||||||
|
@ -440,22 +421,15 @@ std::unique_ptr<HiresTexture> HiresTexture::Load(const std::string& base_filenam
|
||||||
|
|
||||||
bool HiresTexture::LoadTexture(Level& level, const std::vector<u8>& buffer)
|
bool HiresTexture::LoadTexture(Level& level, const std::vector<u8>& buffer)
|
||||||
{
|
{
|
||||||
int channels;
|
if (!Common::LoadPNG(buffer, &level.data, &level.width, &level.height))
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
|
|
||||||
u8* data = SOIL_load_image_from_memory(buffer.data(), static_cast<int>(buffer.size()), &width,
|
|
||||||
&height, &channels, SOIL_LOAD_RGBA);
|
|
||||||
if (!data)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Images loaded by SOIL are converted to RGBA.
|
if (level.data.empty())
|
||||||
level.width = static_cast<u32>(width);
|
return false;
|
||||||
level.height = static_cast<u32>(height);
|
|
||||||
|
// Loaded PNG images are converted to RGBA.
|
||||||
level.format = AbstractTextureFormat::RGBA8;
|
level.format = AbstractTextureFormat::RGBA8;
|
||||||
level.data = ImageDataPointer(data, SOIL_free_image_data);
|
|
||||||
level.row_length = level.width;
|
level.row_length = level.width;
|
||||||
level.data_size = static_cast<size_t>(level.row_length) * 4 * level.height;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,6 @@ enum class TextureFormat;
|
||||||
class HiresTexture
|
class HiresTexture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using ImageDataPointer = std::unique_ptr<u8, void (*)(unsigned char*)>;
|
|
||||||
|
|
||||||
static void Init();
|
static void Init();
|
||||||
static void Update();
|
static void Update();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
@ -39,14 +37,11 @@ public:
|
||||||
|
|
||||||
struct Level
|
struct Level
|
||||||
{
|
{
|
||||||
Level();
|
std::vector<u8> data;
|
||||||
|
|
||||||
ImageDataPointer data;
|
|
||||||
AbstractTextureFormat format = AbstractTextureFormat::RGBA8;
|
AbstractTextureFormat format = AbstractTextureFormat::RGBA8;
|
||||||
u32 width = 0;
|
u32 width = 0;
|
||||||
u32 height = 0;
|
u32 height = 0;
|
||||||
u32 row_length = 0;
|
u32 row_length = 0;
|
||||||
size_t data_size = 0;
|
|
||||||
};
|
};
|
||||||
std::vector<Level> m_levels;
|
std::vector<Level> m_levels;
|
||||||
|
|
||||||
|
|
|
@ -155,14 +155,9 @@ u32 GetBlockCount(u32 extent, u32 block_size)
|
||||||
return std::max(Common::AlignUp(extent, block_size) / block_size, 1u);
|
return std::max(Common::AlignUp(extent, block_size) / block_size, 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
HiresTexture::ImageDataPointer AllocateLevelData(size_t size)
|
|
||||||
{
|
|
||||||
return HiresTexture::ImageDataPointer(new u8[size], [](u8* data) { delete[] data; });
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConvertTexture_X8B8G8R8(HiresTexture::Level* level)
|
void ConvertTexture_X8B8G8R8(HiresTexture::Level* level)
|
||||||
{
|
{
|
||||||
u8* data_ptr = level->data.get();
|
u8* data_ptr = level->data.data();
|
||||||
for (u32 row = 0; row < level->height; row++)
|
for (u32 row = 0; row < level->height; row++)
|
||||||
{
|
{
|
||||||
for (u32 x = 0; x < level->row_length; x++)
|
for (u32 x = 0; x < level->row_length; x++)
|
||||||
|
@ -176,7 +171,7 @@ void ConvertTexture_X8B8G8R8(HiresTexture::Level* level)
|
||||||
|
|
||||||
void ConvertTexture_A8R8G8B8(HiresTexture::Level* level)
|
void ConvertTexture_A8R8G8B8(HiresTexture::Level* level)
|
||||||
{
|
{
|
||||||
u8* data_ptr = level->data.get();
|
u8* data_ptr = level->data.data();
|
||||||
for (u32 row = 0; row < level->height; row++)
|
for (u32 row = 0; row < level->height; row++)
|
||||||
{
|
{
|
||||||
for (u32 x = 0; x < level->row_length; x++)
|
for (u32 x = 0; x < level->row_length; x++)
|
||||||
|
@ -193,7 +188,7 @@ void ConvertTexture_A8R8G8B8(HiresTexture::Level* level)
|
||||||
|
|
||||||
void ConvertTexture_X8R8G8B8(HiresTexture::Level* level)
|
void ConvertTexture_X8R8G8B8(HiresTexture::Level* level)
|
||||||
{
|
{
|
||||||
u8* data_ptr = level->data.get();
|
u8* data_ptr = level->data.data();
|
||||||
for (u32 row = 0; row < level->height; row++)
|
for (u32 row = 0; row < level->height; row++)
|
||||||
{
|
{
|
||||||
for (u32 x = 0; x < level->row_length; x++)
|
for (u32 x = 0; x < level->row_length; x++)
|
||||||
|
@ -210,14 +205,10 @@ void ConvertTexture_X8R8G8B8(HiresTexture::Level* level)
|
||||||
|
|
||||||
void ConvertTexture_R8G8B8(HiresTexture::Level* level)
|
void ConvertTexture_R8G8B8(HiresTexture::Level* level)
|
||||||
{
|
{
|
||||||
// Have to reallocate the buffer for this one, since the data in the file
|
std::vector<u8> new_data(level->row_length * level->height * sizeof(u32));
|
||||||
// does not have an alpha byte.
|
|
||||||
level->data_size = level->row_length * level->height * sizeof(u32);
|
|
||||||
HiresTexture::ImageDataPointer rgb_data = AllocateLevelData(level->data_size);
|
|
||||||
std::swap(level->data, rgb_data);
|
|
||||||
|
|
||||||
const u8* rgb_data_ptr = rgb_data.get();
|
const u8* rgb_data_ptr = level->data.data();
|
||||||
u8* data_ptr = level->data.get();
|
u8* data_ptr = new_data.data();
|
||||||
|
|
||||||
for (u32 row = 0; row < level->height; row++)
|
for (u32 row = 0; row < level->height; row++)
|
||||||
{
|
{
|
||||||
|
@ -232,6 +223,8 @@ void ConvertTexture_R8G8B8(HiresTexture::Level* level)
|
||||||
rgb_data_ptr += 3;
|
rgb_data_ptr += 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
level->data = std::move(new_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
|
bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
|
||||||
|
@ -410,19 +403,14 @@ bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
|
||||||
bool ReadMipLevel(HiresTexture::Level* level, File::IOFile& file, const DDSLoadInfo& info,
|
bool ReadMipLevel(HiresTexture::Level* level, File::IOFile& file, const DDSLoadInfo& info,
|
||||||
u32 width, u32 height, u32 row_length, size_t size)
|
u32 width, u32 height, u32 row_length, size_t size)
|
||||||
{
|
{
|
||||||
// Copy to the final storage location. The deallocator here is simple, nothing extra is
|
// Copy to the final storage location.
|
||||||
// needed, compared to the SOIL-based loader.
|
|
||||||
level->width = width;
|
level->width = width;
|
||||||
level->height = height;
|
level->height = height;
|
||||||
level->format = info.format;
|
level->format = info.format;
|
||||||
level->row_length = row_length;
|
level->row_length = row_length;
|
||||||
level->data_size = size;
|
level->data.resize(size);
|
||||||
level->data = AllocateLevelData(level->data_size);
|
if (!file.ReadBytes(level->data.data(), level->data.size()))
|
||||||
if (!file.ReadBytes(level->data.get(), level->data_size))
|
|
||||||
{
|
|
||||||
level->data.reset();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Apply conversion function for uncompressed textures.
|
// Apply conversion function for uncompressed textures.
|
||||||
if (info.conversion_function)
|
if (info.conversion_function)
|
||||||
|
|
|
@ -957,8 +957,8 @@ TextureCacheBase::GetTexture(u32 address, u32 width, u32 height, const TextureFo
|
||||||
if (hires_tex)
|
if (hires_tex)
|
||||||
{
|
{
|
||||||
const auto& level = hires_tex->m_levels[0];
|
const auto& level = hires_tex->m_levels[0];
|
||||||
entry->texture->Load(0, level.width, level.height, level.row_length, level.data.get(),
|
entry->texture->Load(0, level.width, level.height, level.row_length, level.data.data(),
|
||||||
level.data_size);
|
level.data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialized to null because only software loading uses this buffer
|
// Initialized to null because only software loading uses this buffer
|
||||||
|
@ -1042,7 +1042,7 @@ TextureCacheBase::GetTexture(u32 address, u32 width, u32 height, const TextureFo
|
||||||
{
|
{
|
||||||
const auto& level = hires_tex->m_levels[level_index];
|
const auto& level = hires_tex->m_levels[level_index];
|
||||||
entry->texture->Load(level_index, level.width, level.height, level.row_length,
|
entry->texture->Load(level_index, level.width, level.height, level.row_length,
|
||||||
level.data.get(), level.data_size);
|
level.data.data(), level.data.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -174,9 +174,6 @@
|
||||||
<ProjectReference Include="$(ExternalsDir)libpng\png\png.vcxproj">
|
<ProjectReference Include="$(ExternalsDir)libpng\png\png.vcxproj">
|
||||||
<Project>{4c9f135b-a85e-430c-bad4-4c67ef5fc12c}</Project>
|
<Project>{4c9f135b-a85e-430c-bad4-4c67ef5fc12c}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="$(ExternalsDir)SOIL\SOIL.vcxproj">
|
|
||||||
<Project>{b441cc62-877e-4b3f-93e0-0de80544f705}</Project>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="$(ExternalsDir)xxhash\xxhash.vcxproj">
|
<ProjectReference Include="$(ExternalsDir)xxhash\xxhash.vcxproj">
|
||||||
<Project>{677EA016-1182-440C-9345-DC88D1E98C0C}</Project>
|
<Project>{677EA016-1182-440C-9345-DC88D1E98C0C}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
@ -190,4 +187,4 @@
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -49,7 +49,6 @@
|
||||||
<AdditionalIncludeDirectories>$(ExternalsDir)mbedtls\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ExternalsDir)mbedtls\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(ExternalsDir)pugixml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ExternalsDir)pugixml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(ExternalsDir)SFML\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ExternalsDir)SFML\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(ExternalsDir)SOIL;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
|
||||||
<AdditionalIncludeDirectories>$(ExternalsDir)Vulkan\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ExternalsDir)Vulkan\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(ExternalsDir)wxWidgets3;$(ExternalsDir)wxWidgets3\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ExternalsDir)wxWidgets3;$(ExternalsDir)wxWidgets3\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(ExternalsDir)xxhash;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ExternalsDir)xxhash;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
in order to prevent the trailing slash from escaping the doublequote after value replacement.
|
in order to prevent the trailing slash from escaping the doublequote after value replacement.
|
||||||
-->
|
-->
|
||||||
<MocIncludes>"-I$(QtIncludeDir)QtWidgets" "-I$(QtIncludeDir)QtGui" "-I$(QtIncludeDir)QtCore" "-I$(QtIncludeDir) " "-I$(QtToolOutDir) " -I.</MocIncludes>
|
<MocIncludes>"-I$(QtIncludeDir)QtWidgets" "-I$(QtIncludeDir)QtGui" "-I$(QtIncludeDir)QtCore" "-I$(QtIncludeDir) " "-I$(QtToolOutDir) " -I.</MocIncludes>
|
||||||
<MocIncludes>"-I$(ExternalsDir)xxhash" "-I$(ExternalsDir)zlib" "-I$(ExternalsDir)SOIL" "-I$(ExternalsDir)SFML\include" "-I$(ExternalsDir)mbedtls\include" "-I$(ExternalsDir)miniupnpc\src" "-I$(ExternalsDir)LZO" "-I$(ExternalsDir)libusbx\libusb" "-I$(ExternalsDir)libpng" "-I$(ExternalsDir)GL" "-I$(ExternalsDir)Bochs_disasm" "-I$(ExternalsDir) " "-I$(CoreDir) " $(MocIncludes)</MocIncludes>
|
<MocIncludes>"-I$(ExternalsDir)xxhash" "-I$(ExternalsDir)zlib" "-I$(ExternalsDir)SFML\include" "-I$(ExternalsDir)mbedtls\include" "-I$(ExternalsDir)miniupnpc\src" "-I$(ExternalsDir)LZO" "-I$(ExternalsDir)libusbx\libusb" "-I$(ExternalsDir)libpng" "-I$(ExternalsDir)GL" "-I$(ExternalsDir)Bochs_disasm" "-I$(ExternalsDir) " "-I$(CoreDir) " $(MocIncludes)</MocIncludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Target Name="QtMoc"
|
<Target Name="QtMoc"
|
||||||
BeforeTargets="ClCompile"
|
BeforeTargets="ClCompile"
|
||||||
|
|
|
@ -33,8 +33,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc", "..\Externals\m
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "png", "..\Externals\libpng\png\png.vcxproj", "{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "png", "..\Externals\libpng\png\png.vcxproj", "{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SOIL", "..\Externals\SOIL\SOIL.vcxproj", "{B441CC62-877E-4B3F-93E0-0DE80544F705}"
|
|
||||||
EndProject
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxhash", "..\Externals\xxhash\xxhash.vcxproj", "{677EA016-1182-440C-9345-DC88D1E98C0C}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxhash", "..\Externals\xxhash\xxhash.vcxproj", "{677EA016-1182-440C-9345-DC88D1E98C0C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\Externals\zlib\zlib.vcxproj", "{FF213B23-2C26-4214-9F88-85271E557E87}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\Externals\zlib\zlib.vcxproj", "{FF213B23-2C26-4214-9F88-85271E557E87}"
|
||||||
|
@ -147,10 +145,6 @@ Global
|
||||||
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}.Debug|x64.Build.0 = Debug|x64
|
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}.Debug|x64.Build.0 = Debug|x64
|
||||||
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}.Release|x64.ActiveCfg = Release|x64
|
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}.Release|x64.ActiveCfg = Release|x64
|
||||||
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}.Release|x64.Build.0 = Release|x64
|
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}.Release|x64.Build.0 = Release|x64
|
||||||
{B441CC62-877E-4B3F-93E0-0DE80544F705}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{B441CC62-877E-4B3F-93E0-0DE80544F705}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{B441CC62-877E-4B3F-93E0-0DE80544F705}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{B441CC62-877E-4B3F-93E0-0DE80544F705}.Release|x64.Build.0 = Release|x64
|
|
||||||
{677EA016-1182-440C-9345-DC88D1E98C0C}.Debug|x64.ActiveCfg = Debug|x64
|
{677EA016-1182-440C-9345-DC88D1E98C0C}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{677EA016-1182-440C-9345-DC88D1E98C0C}.Debug|x64.Build.0 = Debug|x64
|
{677EA016-1182-440C-9345-DC88D1E98C0C}.Debug|x64.Build.0 = Debug|x64
|
||||||
{677EA016-1182-440C-9345-DC88D1E98C0C}.Release|x64.ActiveCfg = Release|x64
|
{677EA016-1182-440C-9345-DC88D1E98C0C}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
@ -271,7 +265,6 @@ Global
|
||||||
{AB993F38-C31D-4897-B139-A620C42BC565} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
{AB993F38-C31D-4897-B139-A620C42BC565} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||||
{31643FDB-1BB8-4965-9DE7-000FC88D35AE} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
{31643FDB-1BB8-4965-9DE7-000FC88D35AE} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||||
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||||
{B441CC62-877E-4B3F-93E0-0DE80544F705} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
|
||||||
{677EA016-1182-440C-9345-DC88D1E98C0C} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
{677EA016-1182-440C-9345-DC88D1E98C0C} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||||
{FF213B23-2C26-4214-9F88-85271E557E87} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
{FF213B23-2C26-4214-9F88-85271E557E87} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||||
{EC082900-B4D8-42E9-9663-77F02F6936AE} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
{EC082900-B4D8-42E9-9663-77F02F6936AE} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||||
|
|
Loading…
Reference in New Issue