upgrading soil to soil2

This commit is contained in:
Mischa Spiegelmock
2015-11-28 10:56:21 -08:00
parent 98fa7f8713
commit 8d041fcfd1
25 changed files with 11214 additions and 4454 deletions

View File

@ -1,10 +1,9 @@
project(Renderer)
SET(SOIL_SOURCES
SOIL/image_DXT.c
SOIL/image_helper.c
SOIL/SOIL.c
SOIL/stb_image_aug.c
SOIL2/image_DXT.c
SOIL2/image_helper.c
SOIL2/SOIL2.c
)
SET(Renderer_SOURCES

File diff suppressed because it is too large Load Diff

View File

@ -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 gamma);
extern void stbi_hdr_to_ldr_scale(float scale);
extern void stbi_ldr_to_hdr_gamma(float gamma);
extern void stbi_ldr_to_hdr_scale(float scale);
#endif // STBI_NO_HDR
// get a VERY brief reason for failure
// NOT THREADSAFE
extern 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

View File

@ -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

View File

@ -1,10 +1,12 @@
/**
@mainpage SOIL
@mainpage SOIL2
Jonathan Dummer
Fork by Martin Lucas Golini
Original author Jonathan Dummer
2007-07-26-10.36
Simple OpenGL Image Library
Simple OpenGL Image Library 2
A tiny c library for uploading images as
textures into OpenGL. Also saving and
@ -21,8 +23,11 @@
- BMP load & save
- TGA load & save
- DDS load & save
- PNG load
- PNG load & save
- JPG load
- PSD load
- HDR load
- PIC load
OpenGL Texture Features:
- resample to power-of-two sizes
@ -87,10 +92,11 @@ enum
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_DDS_LOAD_DIRECT: will load DDS files directly without _ANY_ additional processing ( if supported )
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
SOIL_FLAG_PVR_LOAD_DIRECT: will load PVR files directly without _ANY_ additional processing ( if supported )
**/
enum
{
@ -103,7 +109,10 @@ enum
SOIL_FLAG_DDS_LOAD_DIRECT = 64,
SOIL_FLAG_NTSC_SAFE_RGB = 128,
SOIL_FLAG_CoCg_Y = 256,
SOIL_FLAG_TEXTURE_RECTANGLE = 512
SOIL_FLAG_TEXTURE_RECTANGLE = 512,
SOIL_FLAG_PVR_LOAD_DIRECT = 1024,
SOIL_FLAG_ETC1_LOAD_DIRECT = 2048,
SOIL_FLAG_GL_MIPMAPS = 4096
};
/**
@ -111,12 +120,14 @@ enum
(TGA supports uncompressed RGB / RGBA)
(BMP supports uncompressed RGB)
(DDS supports DXT1 and DXT5)
(PNG supports RGB / RGBA)
**/
enum
{
SOIL_SAVE_TYPE_TGA = 0,
SOIL_SAVE_TYPE_BMP = 1,
SOIL_SAVE_TYPE_DDS = 2
SOIL_SAVE_TYPE_PNG = 2,
SOIL_SAVE_TYPE_DDS = 3
};
/**
@ -158,17 +169,6 @@ unsigned int
unsigned int flags
);
unsigned int
SOIL_load_OGL_texture_size
(
const char *filename,
int force_channels,
unsigned int reuse_texture_ID,
unsigned int flags,
int *width,
int *height
);
/**
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
@ -316,8 +316,8 @@ unsigned int
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 width the pointer of the width of the image in pixels ( if the texture size change, width will be overrided with the new width )
\param height the pointer of the height of the image in pixels ( if the texture size change, height will be overrided with the new height )
\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
@ -327,7 +327,7 @@ unsigned int
SOIL_create_OGL_texture
(
const unsigned char *const data,
int width, int height, int channels,
int *width, int *height, int channels,
unsigned int reuse_texture_ID,
unsigned int flags
);
@ -436,6 +436,60 @@ const char*
void
);
/** @return The address of the GL function proc, or NULL if the function is not found. */
void *
SOIL_GL_GetProcAddress
(
const char *proc
);
/** @return 1 if an OpenGL extension is supported for the current context, 0 otherwise. */
int
SOIL_GL_ExtensionSupported
(
const char *extension
);
/** Loads the DDS texture directly to the GPU memory ( if supported ) */
unsigned int SOIL_direct_load_DDS(
const char *filename,
unsigned int reuse_texture_ID,
int flags,
int loading_as_cubemap );
/** Loads the DDS texture directly to the GPU memory ( if supported ) */
unsigned int SOIL_direct_load_DDS_from_memory(
const unsigned char *const buffer,
int buffer_length,
unsigned int reuse_texture_ID,
int flags,
int loading_as_cubemap );
/** Loads the PVR texture directly to the GPU memory ( if supported ) */
unsigned int SOIL_direct_load_PVR(
const char *filename,
unsigned int reuse_texture_ID,
int flags,
int loading_as_cubemap );
/** Loads the PVR texture directly to the GPU memory ( if supported ) */
unsigned int SOIL_direct_load_PVR_from_memory(
const unsigned char *const buffer,
int buffer_length,
unsigned int reuse_texture_ID,
int flags,
int loading_as_cubemap );
/** Loads the PVR texture directly to the GPU memory ( if supported ) */
unsigned int SOIL_direct_load_ETC1(const char *filename,
unsigned int reuse_texture_ID,
int flags );
/** Loads the PVR texture directly to the GPU memory ( if supported ) */
unsigned int SOIL_direct_load_ETC1_from_memory(const unsigned char *const buffer,
int buffer_length,
unsigned int reuse_texture_ID,
int flags );
#ifdef __cplusplus
}

View File

@ -0,0 +1,680 @@
// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "etc1_utils.h"
#include <string.h>
/* From http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
The number of bits that represent a 4x4 texel block is 64 bits if
<internalformat> is given by ETC1_RGB8_OES.
The data for a block is a number of bytes,
{q0, q1, q2, q3, q4, q5, q6, q7}
where byte q0 is located at the lowest memory address and q7 at
the highest. The 64 bits specifying the block is then represented
by the following 64 bit integer:
int64bit = 256*(256*(256*(256*(256*(256*(256*q0+q1)+q2)+q3)+q4)+q5)+q6)+q7;
ETC1_RGB8_OES:
a) bit layout in bits 63 through 32 if diffbit = 0
63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48
-----------------------------------------------
| base col1 | base col2 | base col1 | base col2 |
| R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)|
-----------------------------------------------
47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
---------------------------------------------------
| base col1 | base col2 | table | table |diff|flip|
| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit |
---------------------------------------------------
b) bit layout in bits 63 through 32 if diffbit = 1
63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48
-----------------------------------------------
| base col1 | dcol 2 | base col1 | dcol 2 |
| R1' (5 bits) | dR2 | G1' (5 bits) | dG2 |
-----------------------------------------------
47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
---------------------------------------------------
| base col 1 | dcol 2 | table | table |diff|flip|
| B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit |
---------------------------------------------------
c) bit layout in bits 31 through 0 (in both cases)
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
-----------------------------------------------
| most significant pixel index bits |
| p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a|
-----------------------------------------------
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
--------------------------------------------------
| least significant pixel index bits |
| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a |
--------------------------------------------------
Add table 3.17.2: Intensity modifier sets for ETC1 compressed textures:
table codeword modifier table
------------------ ----------------------
0 -8 -2 2 8
1 -17 -5 5 17
2 -29 -9 9 29
3 -42 -13 13 42
4 -60 -18 18 60
5 -80 -24 24 80
6 -106 -33 33 106
7 -183 -47 47 183
Add table 3.17.3 Mapping from pixel index values to modifier values for
ETC1 compressed textures:
pixel index value
---------------
msb lsb resulting modifier value
----- ----- -------------------------
1 1 -b (large negative value)
1 0 -a (small negative value)
0 0 a (small positive value)
0 1 b (large positive value)
*/
static const int kModifierTable[] = {
/* 0 */2, 8, -2, -8,
/* 1 */5, 17, -5, -17,
/* 2 */9, 29, -9, -29,
/* 3 */13, 42, -13, -42,
/* 4 */18, 60, -18, -60,
/* 5 */24, 80, -24, -80,
/* 6 */33, 106, -33, -106,
/* 7 */47, 183, -47, -183 };
static const int kLookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 };
static inline etc1_byte clamp(int x) {
return (etc1_byte) (x >= 0 ? (x < 255 ? x : 255) : 0);
}
static
inline int convert4To8(int b) {
int c = b & 0xf;
return (c << 4) | c;
}
static
inline int convert5To8(int b) {
int c = b & 0x1f;
return (c << 3) | (c >> 2);
}
static
inline int convert6To8(int b) {
int c = b & 0x3f;
return (c << 2) | (c >> 4);
}
static
inline int divideBy255(int d) {
return (d + 128 + (d >> 8)) >> 8;
}
static
inline int convert8To4(int b) {
//int c = b & 0xff;
return divideBy255(b * 15);
}
static
inline int convert8To5(int b) {
//int c = b & 0xff;
return divideBy255(b * 31);
}
static
inline int convertDiff(int base, int diff) {
return convert5To8((0x1f & base) + kLookup[0x7 & diff]);
}
static
void decode_subblock(etc1_byte* pOut, int r, int g, int b, const int* table,
etc1_uint32 low, etc1_bool second, etc1_bool flipped) {
int baseX = 0;
int baseY = 0;
int i;
if (second) {
if (flipped) {
baseY = 2;
} else {
baseX = 2;
}
}
for (i = 0; i < 8; i++) {
int x, y;
if (flipped) {
x = baseX + (i >> 1);
y = baseY + (i & 1);
} else {
x = baseX + (i >> 2);
y = baseY + (i & 3);
}
int k = y + (x * 4);
int offset = ((low >> k) & 1) | ((low >> (k + 15)) & 2);
int delta = table[offset];
etc1_byte* q = pOut + 3 * (x + 4 * y);
*q++ = clamp(r + delta);
*q++ = clamp(g + delta);
*q++ = clamp(b + delta);
}
}
// Input is an ETC1 compressed version of the data.
// Output is a 4 x 4 square of 3-byte pixels in form R, G, B
void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut) {
etc1_uint32 high = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3];
etc1_uint32 low = (pIn[4] << 24) | (pIn[5] << 16) | (pIn[6] << 8) | pIn[7];
int r1, r2, g1, g2, b1, b2;
if (high & 2) {
// differential
int rBase = high >> 27;
int gBase = high >> 19;
int bBase = high >> 11;
r1 = convert5To8(rBase);
r2 = convertDiff(rBase, high >> 24);
g1 = convert5To8(gBase);
g2 = convertDiff(gBase, high >> 16);
b1 = convert5To8(bBase);
b2 = convertDiff(bBase, high >> 8);
} else {
// not differential
r1 = convert4To8(high >> 28);
r2 = convert4To8(high >> 24);
g1 = convert4To8(high >> 20);
g2 = convert4To8(high >> 16);
b1 = convert4To8(high >> 12);
b2 = convert4To8(high >> 8);
}
int tableIndexA = 7 & (high >> 5);
int tableIndexB = 7 & (high >> 2);
const int* tableA = kModifierTable + tableIndexA * 4;
const int* tableB = kModifierTable + tableIndexB * 4;
etc1_bool flipped = (high & 1) != 0;
decode_subblock(pOut, r1, g1, b1, tableA, low, 0, flipped);
decode_subblock(pOut, r2, g2, b2, tableB, low, 1, flipped);
}
typedef struct {
etc1_uint32 high;
etc1_uint32 low;
etc1_uint32 score; // Lower is more accurate
} etc_compressed;
static
inline void take_best(etc_compressed* a, const etc_compressed* b) {
if (a->score > b->score) {
*a = *b;
}
}
static
void etc_average_colors_subblock(const etc1_byte* pIn, etc1_uint32 inMask,
etc1_byte* pColors, etc1_bool flipped, etc1_bool second) {
int r = 0;
int g = 0;
int b = 0;
int y, x;
if (flipped) {
int by = 0;
if (second) {
by = 2;
}
for ( y = 0; y < 2; y++) {
int yy = by + y;
for ( x = 0; x < 4; x++) {
int i = x + 4 * yy;
if (inMask & (1 << i)) {
const etc1_byte* p = pIn + i * 3;
r += *(p++);
g += *(p++);
b += *(p++);
}
}
}
} else {
int bx = 0;
if (second) {
bx = 2;
}
for ( y = 0; y < 4; y++) {
for ( x = 0; x < 2; x++) {
int xx = bx + x;
int i = xx + 4 * y;
if (inMask & (1 << i)) {
const etc1_byte* p = pIn + i * 3;
r += *(p++);
g += *(p++);
b += *(p++);
}
}
}
}
pColors[0] = (etc1_byte)((r + 4) >> 3);
pColors[1] = (etc1_byte)((g + 4) >> 3);
pColors[2] = (etc1_byte)((b + 4) >> 3);
}
static
inline int square(int x) {
return x * x;
}
static etc1_uint32 chooseModifier(const etc1_byte* pBaseColors,
const etc1_byte* pIn, etc1_uint32 *pLow, int bitIndex,
const int* pModifierTable) {
etc1_uint32 bestScore = ~0;
int bestIndex = 0;
int pixelR = pIn[0];
int pixelG = pIn[1];
int pixelB = pIn[2];
int r = pBaseColors[0];
int g = pBaseColors[1];
int b = pBaseColors[2];
int i;
for ( i = 0; i < 4; i++) {
int modifier = pModifierTable[i];
int decodedG = clamp(g + modifier);
etc1_uint32 score = (etc1_uint32) (6 * square(decodedG - pixelG));
if (score >= bestScore) {
continue;
}
int decodedR = clamp(r + modifier);
score += (etc1_uint32) (3 * square(decodedR - pixelR));
if (score >= bestScore) {
continue;
}
int decodedB = clamp(b + modifier);
score += (etc1_uint32) square(decodedB - pixelB);
if (score < bestScore) {
bestScore = score;
bestIndex = i;
}
}
etc1_uint32 lowMask = (((bestIndex >> 1) << 16) | (bestIndex & 1))
<< bitIndex;
*pLow |= lowMask;
return bestScore;
}
static
void etc_encode_subblock_helper(const etc1_byte* pIn, etc1_uint32 inMask,
etc_compressed* pCompressed, etc1_bool flipped, etc1_bool second,
const etc1_byte* pBaseColors, const int* pModifierTable) {
int score = pCompressed->score;
int y, x;
if (flipped) {
int by = 0;
if (second) {
by = 2;
}
for ( y = 0; y < 2; y++) {
int yy = by + y;
for ( x = 0; x < 4; x++) {
int i = x + 4 * yy;
if (inMask & (1 << i)) {
score += chooseModifier(pBaseColors, pIn + i * 3,
&pCompressed->low, yy + x * 4, pModifierTable);
}
}
}
} else {
int bx = 0;
if (second) {
bx = 2;
}
for ( y = 0; y < 4; y++) {
for ( x = 0; x < 2; x++) {
int xx = bx + x;
int i = xx + 4 * y;
if (inMask & (1 << i)) {
score += chooseModifier(pBaseColors, pIn + i * 3,
&pCompressed->low, y + xx * 4, pModifierTable);
}
}
}
}
pCompressed->score = score;
}
static etc1_bool inRange4bitSigned(int color) {
return color >= -4 && color <= 3;
}
static void etc_encodeBaseColors(etc1_byte* pBaseColors,
const etc1_byte* pColors, etc_compressed* pCompressed) {
int r1, g1, b1, r2 = 0, g2 = 0, b2 = 0; // 8 bit base colors for sub-blocks
etc1_bool differential;
{
int r51 = convert8To5(pColors[0]);
int g51 = convert8To5(pColors[1]);
int b51 = convert8To5(pColors[2]);
int r52 = convert8To5(pColors[3]);
int g52 = convert8To5(pColors[4]);
int b52 = convert8To5(pColors[5]);
r1 = convert5To8(r51);
g1 = convert5To8(g51);
b1 = convert5To8(b51);
int dr = r52 - r51;
int dg = g52 - g51;
int db = b52 - b51;
differential = inRange4bitSigned(dr) && inRange4bitSigned(dg)
&& inRange4bitSigned(db);
if (differential) {
r2 = convert5To8(r51 + dr);
g2 = convert5To8(g51 + dg);
b2 = convert5To8(b51 + db);
pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19)
| ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2;
}
}
if (!differential) {
int r41 = convert8To4(pColors[0]);
int g41 = convert8To4(pColors[1]);
int b41 = convert8To4(pColors[2]);
int r42 = convert8To4(pColors[3]);
int g42 = convert8To4(pColors[4]);
int b42 = convert8To4(pColors[5]);
r1 = convert4To8(r41);
g1 = convert4To8(g41);
b1 = convert4To8(b41);
r2 = convert4To8(r42);
g2 = convert4To8(g42);
b2 = convert4To8(b42);
pCompressed->high |= (r41 << 28) | (r42 << 24) | (g41 << 20) | (g42
<< 16) | (b41 << 12) | (b42 << 8);
}
pBaseColors[0] = r1;
pBaseColors[1] = g1;
pBaseColors[2] = b1;
pBaseColors[3] = r2;
pBaseColors[4] = g2;
pBaseColors[5] = b2;
}
static
void etc_encode_block_helper(const etc1_byte* pIn, etc1_uint32 inMask,
const etc1_byte* pColors, etc_compressed* pCompressed, etc1_bool flipped) {
int i;
pCompressed->score = ~0;
pCompressed->high = (flipped ? 1 : 0);
pCompressed->low = 0;
etc1_byte pBaseColors[6];
etc_encodeBaseColors(pBaseColors, pColors, pCompressed);
int originalHigh = pCompressed->high;
const int* pModifierTable = kModifierTable;
for ( i = 0; i < 8; i++, pModifierTable += 4) {
etc_compressed temp;
temp.score = 0;
temp.high = originalHigh | (i << 5);
temp.low = 0;
etc_encode_subblock_helper(pIn, inMask, &temp, flipped, 0,
pBaseColors, pModifierTable);
take_best(pCompressed, &temp);
}
pModifierTable = kModifierTable;
etc_compressed firstHalf = *pCompressed;
for ( i = 0; i < 8; i++, pModifierTable += 4) {
etc_compressed temp;
temp.score = firstHalf.score;
temp.high = firstHalf.high | (i << 2);
temp.low = firstHalf.low;
etc_encode_subblock_helper(pIn, inMask, &temp, flipped, 1,
pBaseColors + 3, pModifierTable);
if (i == 0) {
*pCompressed = temp;
} else {
take_best(pCompressed, &temp);
}
}
}
static void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) {
pOut[0] = (etc1_byte)(d >> 24);
pOut[1] = (etc1_byte)(d >> 16);
pOut[2] = (etc1_byte)(d >> 8);
pOut[3] = (etc1_byte) d;
}
// Input is a 4 x 4 square of 3-byte pixels in form R, G, B
// inmask is a 16-bit mask where bit (1 << (x + y * 4)) tells whether the corresponding (x,y)
// pixel is valid or not. Invalid pixel color values are ignored when compressing.
// Output is an ETC1 compressed version of the data.
void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 inMask,
etc1_byte* pOut) {
etc1_byte colors[6];
etc1_byte flippedColors[6];
etc_average_colors_subblock(pIn, inMask, colors, 0, 0);
etc_average_colors_subblock(pIn, inMask, colors + 3, 0, 1);
etc_average_colors_subblock(pIn, inMask, flippedColors, 1, 0);
etc_average_colors_subblock(pIn, inMask, flippedColors + 3, 1, 1);
etc_compressed a, b;
etc_encode_block_helper(pIn, inMask, colors, &a, 0);
etc_encode_block_helper(pIn, inMask, flippedColors, &b, 1);
take_best(&a, &b);
writeBigEndian(pOut, a.high);
writeBigEndian(pOut + 4, a.low);
}
// Return the size of the encoded image data (does not include size of PKM header).
etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) {
return (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1;
}
// Encode an entire image.
// pIn - pointer to the image data. Formatted such that the Red component of
// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset;
// pOut - pointer to encoded data. Must be large enough to store entire encoded image.
int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height,
etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut) {
if (pixelSize < 2 || pixelSize > 3) {
return -1;
}
static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff };
static const unsigned short kXMask[] = { 0x0, 0x1111, 0x3333, 0x7777,
0xffff };
etc1_byte block[ETC1_DECODED_BLOCK_SIZE];
etc1_byte encoded[ETC1_ENCODED_BLOCK_SIZE];
etc1_uint32 y, x, cy, cx;
etc1_uint32 encodedWidth = (width + 3) & ~3;
etc1_uint32 encodedHeight = (height + 3) & ~3;
for ( y = 0; y < encodedHeight; y += 4) {
etc1_uint32 yEnd = height - y;
if (yEnd > 4) {
yEnd = 4;
}
int ymask = kYMask[yEnd];
for ( x = 0; x < encodedWidth; x += 4) {
etc1_uint32 xEnd = width - x;
if (xEnd > 4) {
xEnd = 4;
}
int mask = ymask & kXMask[xEnd];
for ( cy = 0; cy < yEnd; cy++) {
etc1_byte* q = block + (cy * 4) * 3;
const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy);
if (pixelSize == 3) {
memcpy(q, p, xEnd * 3);
} else {
for ( cx = 0; cx < xEnd; cx++) {
int pixel = (p[1] << 8) | p[0];
*q++ = convert5To8(pixel >> 11);
*q++ = convert6To8(pixel >> 5);
*q++ = convert5To8(pixel);
p += pixelSize;
}
}
}
etc1_encode_block(block, mask, encoded);
memcpy(pOut, encoded, sizeof(encoded));
pOut += sizeof(encoded);
}
}
return 0;
}
// Decode an entire image.
// pIn - pointer to encoded data.
// pOut - pointer to the image data. Will be written such that the Red component of
// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset. Must be
// large enough to store entire image.
int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut,
etc1_uint32 width, etc1_uint32 height,
etc1_uint32 pixelSize, etc1_uint32 stride) {
if (pixelSize < 2 || pixelSize > 3) {
return -1;
}
etc1_byte block[ETC1_DECODED_BLOCK_SIZE];
etc1_uint32 encodedWidth = (width + 3) & ~3;
etc1_uint32 encodedHeight = (height + 3) & ~3;
etc1_uint32 y, x, cy, cx;
for ( y = 0; y < encodedHeight; y += 4) {
etc1_uint32 yEnd = height - y;
if (yEnd > 4) {
yEnd = 4;
}
for ( x = 0; x < encodedWidth; x += 4) {
etc1_uint32 xEnd = width - x;
if (xEnd > 4) {
xEnd = 4;
}
etc1_decode_block(pIn, block);
pIn += ETC1_ENCODED_BLOCK_SIZE;
for ( cy = 0; cy < yEnd; cy++) {
const etc1_byte* q = block + (cy * 4) * 3;
etc1_byte* p = pOut + pixelSize * x + stride * (y + cy);
if (pixelSize == 3) {
memcpy(p, q, xEnd * 3);
} else {
for ( cx = 0; cx < xEnd; cx++) {
etc1_byte r = *q++;
etc1_byte g = *q++;
etc1_byte b = *q++;
etc1_uint32 pixel = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
*p++ = (etc1_byte) pixel;
*p++ = (etc1_byte) (pixel >> 8);
}
}
}
}
}
return 0;
}
static const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' };
static const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6;
static const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8;
static const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10;
static const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12;
static const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14;
static const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0;
static void writeBEUint16(etc1_byte* pOut, etc1_uint32 data) {
pOut[0] = (etc1_byte) (data >> 8);
pOut[1] = (etc1_byte) data;
}
static etc1_uint32 readBEUint16(const etc1_byte* pIn) {
return (pIn[0] << 8) | pIn[1];
}
// Format a PKM header
void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height) {
memcpy(pHeader, kMagic, sizeof(kMagic));
etc1_uint32 encodedWidth = (width + 3) & ~3;
etc1_uint32 encodedHeight = (height + 3) & ~3;
writeBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET, ETC1_RGB_NO_MIPMAPS);
writeBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET, encodedWidth);
writeBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET, encodedHeight);
writeBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET, width);
writeBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET, height);
}
// Check if a PKM header is correctly formatted.
etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader) {
if (memcmp(pHeader, kMagic, sizeof(kMagic))) {
return 0;
}
etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET);
etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET);
etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET);
etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET);
etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET);
return format == ETC1_RGB_NO_MIPMAPS &&
encodedWidth >= width && encodedWidth - width < 4 &&
encodedHeight >= height && encodedHeight - height < 4;
}
// Read the image width from a PKM header
etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader) {
return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET);
}
// Read the image height from a PKM header
etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader){
return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET);
}

View File

@ -0,0 +1,106 @@
// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __etc1_h__
#define __etc1_h__
#define ETC1_ENCODED_BLOCK_SIZE 8
#define ETC1_DECODED_BLOCK_SIZE 48
#ifndef ETC1_RGB8_OES
#define ETC1_RGB8_OES 0x8D64
#endif
typedef unsigned char etc1_byte;
typedef int etc1_bool;
typedef unsigned int etc1_uint32;
#ifdef __cplusplus
extern "C" {
#endif
// Encode a block of pixels.
//
// pIn is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a
// 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
// value of pixel (x, y).
//
// validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether
// the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing.
//
// pOut is an ETC1 compressed version of the data.
void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 validPixelMask, etc1_byte* pOut);
// Decode a block of pixels.
//
// pIn is an ETC1 compressed version of the data.
//
// pOut is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a
// 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
// value of pixel (x, y).
void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut);
// Return the size of the encoded image data (does not include size of PKM header).
etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height);
// Encode an entire image.
// pIn - pointer to the image data. Formatted such that
// pixel (x,y) is at pIn + pixelSize * x + stride * y;
// pOut - pointer to encoded data. Must be large enough to store entire encoded image.
// pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image.
// returns non-zero if there is an error.
int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height,
etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut);
// Decode an entire image.
// pIn - pointer to encoded data.
// pOut - pointer to the image data. Will be written such that
// pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be
// large enough to store entire image.
// pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image.
// returns non-zero if there is an error.
int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut,
etc1_uint32 width, etc1_uint32 height,
etc1_uint32 pixelSize, etc1_uint32 stride);
// Size of a PKM header, in bytes.
#define ETC_PKM_HEADER_SIZE 16
// Format a PKM header
void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height);
// Check if a PKM header is correctly formatted.
etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader);
// Read the image width from a PKM header
etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader);
// Read the image height from a PKM header
etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -322,7 +322,7 @@ find_max_RGBE
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 );
float scale = (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );
for( j = 0; j < 3; ++j )
{
if( img[j] * scale > max_val )
@ -363,14 +363,14 @@ RGBE_to_RGBdivA
/* 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 );
e = scale * (float)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 = (m != 0.0f) ? (int)(255.0f / m) : 1;
iv = (iv < 1) ? 1 : iv;
img[3] = (iv > 255) ? 255 : iv;
iv = (int)(img[3] * r + 0.5f);
@ -412,14 +412,14 @@ RGBE_to_RGBdivA2
/* 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 );
e = scale * (float)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 = (m != 0.0f) ? (int)sqrtf( 255.0f * 255.0f / m ) : 1;
iv = (iv < 1) ? 1 : iv;
img[3] = (iv > 255) ? 255 : iv;
iv = (int)(img[3] * img[3] * r / 255.0f + 0.5f);

View File

@ -0,0 +1,19 @@
#ifndef PKM_HELPER_H
#define PKM_HELPER_H
typedef struct {
char aName[6];
unsigned short iBlank;
unsigned char iPaddedWidthMSB;
unsigned char iPaddedWidthLSB;
unsigned char iPaddedHeightMSB;
unsigned char iPaddedHeightLSB;
unsigned char iWidthMSB;
unsigned char iWidthLSB;
unsigned char iHeightMSB;
unsigned char iHeightLSB;
} PKMHeader;
#define PKM_HEADER_SIZE 16
#endif

View File

@ -0,0 +1,264 @@
#ifndef PVR_HELPER_H
#define PVR_HELPER_H
// Taken from PowerVR SDK
/*!***************************************************************************
Describes the header of a PVR header-texture
*****************************************************************************/
typedef struct
{
unsigned int dwHeaderSize; /*!< size of the structure */
unsigned int dwHeight; /*!< height of surface to be created */
unsigned int dwWidth; /*!< width of input surface */
unsigned int dwMipMapCount; /*!< number of mip-map levels requested */
unsigned int dwpfFlags; /*!< pixel format flags */
unsigned int dwTextureDataSize; /*!< Total size in bytes */
unsigned int dwBitCount; /*!< number of bits per pixel */
unsigned int dwRBitMask; /*!< mask for red bit */
unsigned int dwGBitMask; /*!< mask for green bits */
unsigned int dwBBitMask; /*!< mask for blue bits */
unsigned int dwAlphaBitMask; /*!< mask for alpha channel */
unsigned int dwPVR; /*!< magic number identifying pvr file */
unsigned int dwNumSurfs; /*!< the number of surfaces present in the pvr */
} PVR_Texture_Header;
/*****************************************************************************
* ENUMS
*****************************************************************************/
enum PixelType
{
MGLPT_ARGB_4444 = 0x00,
MGLPT_ARGB_1555,
MGLPT_RGB_565,
MGLPT_RGB_555,
MGLPT_RGB_888,
MGLPT_ARGB_8888,
MGLPT_ARGB_8332,
MGLPT_I_8,
MGLPT_AI_88,
MGLPT_1_BPP,
MGLPT_VY1UY0,
MGLPT_Y1VY0U,
MGLPT_PVRTC2,
MGLPT_PVRTC4,
MGLPT_PVRTC2_2,
MGLPT_PVRTC2_4,
OGL_RGBA_4444= 0x10,
OGL_RGBA_5551,
OGL_RGBA_8888,
OGL_RGB_565,
OGL_RGB_555,
OGL_RGB_888,
OGL_I_8,
OGL_AI_88,
OGL_PVRTC2,
OGL_PVRTC4,
// OGL_BGRA_8888 extension
OGL_BGRA_8888,
D3D_DXT1 = 0x20,
D3D_DXT2,
D3D_DXT3,
D3D_DXT4,
D3D_DXT5,
D3D_RGB_332,
D3D_AI_44,
D3D_LVU_655,
D3D_XLVU_8888,
D3D_QWVU_8888,
//10 bits per channel
D3D_ABGR_2101010,
D3D_ARGB_2101010,
D3D_AWVU_2101010,
//16 bits per channel
D3D_GR_1616,
D3D_VU_1616,
D3D_ABGR_16161616,
//HDR formats
D3D_R16F,
D3D_GR_1616F,
D3D_ABGR_16161616F,
//32 bits per channel
D3D_R32F,
D3D_GR_3232F,
D3D_ABGR_32323232F,
// Ericsson
ETC_RGB_4BPP,
ETC_RGBA_EXPLICIT,
ETC_RGBA_INTERPOLATED,
// DX10
ePT_DX10_R32G32B32A32_FLOAT= 0x50,
ePT_DX10_R32G32B32A32_UINT ,
ePT_DX10_R32G32B32A32_SINT,
ePT_DX10_R32G32B32_FLOAT,
ePT_DX10_R32G32B32_UINT,
ePT_DX10_R32G32B32_SINT,
ePT_DX10_R16G16B16A16_FLOAT ,
ePT_DX10_R16G16B16A16_UNORM,
ePT_DX10_R16G16B16A16_UINT ,
ePT_DX10_R16G16B16A16_SNORM ,
ePT_DX10_R16G16B16A16_SINT ,
ePT_DX10_R32G32_FLOAT ,
ePT_DX10_R32G32_UINT ,
ePT_DX10_R32G32_SINT ,
ePT_DX10_R10G10B10A2_UNORM ,
ePT_DX10_R10G10B10A2_UINT ,
ePT_DX10_R11G11B10_FLOAT ,
ePT_DX10_R8G8B8A8_UNORM ,
ePT_DX10_R8G8B8A8_UNORM_SRGB ,
ePT_DX10_R8G8B8A8_UINT ,
ePT_DX10_R8G8B8A8_SNORM ,
ePT_DX10_R8G8B8A8_SINT ,
ePT_DX10_R16G16_FLOAT ,
ePT_DX10_R16G16_UNORM ,
ePT_DX10_R16G16_UINT ,
ePT_DX10_R16G16_SNORM ,
ePT_DX10_R16G16_SINT ,
ePT_DX10_R32_FLOAT ,
ePT_DX10_R32_UINT ,
ePT_DX10_R32_SINT ,
ePT_DX10_R8G8_UNORM ,
ePT_DX10_R8G8_UINT ,
ePT_DX10_R8G8_SNORM ,
ePT_DX10_R8G8_SINT ,
ePT_DX10_R16_FLOAT ,
ePT_DX10_R16_UNORM ,
ePT_DX10_R16_UINT ,
ePT_DX10_R16_SNORM ,
ePT_DX10_R16_SINT ,
ePT_DX10_R8_UNORM,
ePT_DX10_R8_UINT,
ePT_DX10_R8_SNORM,
ePT_DX10_R8_SINT,
ePT_DX10_A8_UNORM,
ePT_DX10_R1_UNORM,
ePT_DX10_R9G9B9E5_SHAREDEXP,
ePT_DX10_R8G8_B8G8_UNORM,
ePT_DX10_G8R8_G8B8_UNORM,
ePT_DX10_BC1_UNORM,
ePT_DX10_BC1_UNORM_SRGB,
ePT_DX10_BC2_UNORM,
ePT_DX10_BC2_UNORM_SRGB,
ePT_DX10_BC3_UNORM,
ePT_DX10_BC3_UNORM_SRGB,
ePT_DX10_BC4_UNORM,
ePT_DX10_BC4_SNORM,
ePT_DX10_BC5_UNORM,
ePT_DX10_BC5_SNORM,
//ePT_DX10_B5G6R5_UNORM, // defined but obsolete - won't actually load in DX10
//ePT_DX10_B5G5R5A1_UNORM,
//ePT_DX10_B8G8R8A8_UNORM,
//ePT_DX10_B8G8R8X8_UNORM,
// OpenVG
/* RGB{A,X} channel ordering */
ePT_VG_sRGBX_8888 = 0x90,
ePT_VG_sRGBA_8888,
ePT_VG_sRGBA_8888_PRE,
ePT_VG_sRGB_565,
ePT_VG_sRGBA_5551,
ePT_VG_sRGBA_4444,
ePT_VG_sL_8,
ePT_VG_lRGBX_8888,
ePT_VG_lRGBA_8888,
ePT_VG_lRGBA_8888_PRE,
ePT_VG_lL_8,
ePT_VG_A_8,
ePT_VG_BW_1,
/* {A,X}RGB channel ordering */
ePT_VG_sXRGB_8888,
ePT_VG_sARGB_8888,
ePT_VG_sARGB_8888_PRE,
ePT_VG_sARGB_1555,
ePT_VG_sARGB_4444,
ePT_VG_lXRGB_8888,
ePT_VG_lARGB_8888,
ePT_VG_lARGB_8888_PRE,
/* BGR{A,X} channel ordering */
ePT_VG_sBGRX_8888,
ePT_VG_sBGRA_8888,
ePT_VG_sBGRA_8888_PRE,
ePT_VG_sBGR_565,
ePT_VG_sBGRA_5551,
ePT_VG_sBGRA_4444,
ePT_VG_lBGRX_8888,
ePT_VG_lBGRA_8888,
ePT_VG_lBGRA_8888_PRE,
/* {A,X}BGR channel ordering */
ePT_VG_sXBGR_8888,
ePT_VG_sABGR_8888 ,
ePT_VG_sABGR_8888_PRE,
ePT_VG_sABGR_1555,
ePT_VG_sABGR_4444,
ePT_VG_lXBGR_8888,
ePT_VG_lABGR_8888,
ePT_VG_lABGR_8888_PRE,
// max cap for iterating
END_OF_PIXEL_TYPES,
MGLPT_NOTYPE = 0xff
};
/*****************************************************************************
* constants
*****************************************************************************/
#define PVRTEX_MIPMAP (1<<8) // has mip map levels
#define PVRTEX_TWIDDLE (1<<9) // is twiddled
#define PVRTEX_BUMPMAP (1<<10) // has normals encoded for a bump map
#define PVRTEX_TILING (1<<11) // is bordered for tiled pvr
#define PVRTEX_CUBEMAP (1<<12) // is a cubemap/skybox
#define PVRTEX_FALSEMIPCOL (1<<13) //
#define PVRTEX_VOLUME (1<<14)
#define PVRTEX_PIXELTYPE 0xff // pixel type is always in the last 16bits of the flags
#define PVRTEX_IDENTIFIER 0x21525650 // the pvr identifier is the characters 'P','V','R'
#define PVRTEX_V1_HEADER_SIZE 44 // old header size was 44 for identification purposes
#define PVRTC2_MIN_TEXWIDTH 16
#define PVRTC2_MIN_TEXHEIGHT 8
#define PVRTC4_MIN_TEXWIDTH 8
#define PVRTC4_MIN_TEXHEIGHT 8
#define ETC_MIN_TEXWIDTH 4
#define ETC_MIN_TEXHEIGHT 4
#define DXT_MIN_TEXWIDTH 4
#define DXT_MIN_TEXHEIGHT 4
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,730 @@
/* stb_image_write - v0.98 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
no warranty implied; use at your own risk
Before #including,
#define STB_IMAGE_WRITE_IMPLEMENTATION
in the file that you want to have the implementation.
Will probably not work correctly with strict-aliasing optimizations.
ABOUT:
This header file is a library for writing images to C stdio. It could be
adapted to write to memory or a general streaming interface; let me know.
The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed
for source code compactness and simplicitly, not optimal image file size
or run-time performance.
BUILDING:
You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
malloc,realloc,free.
You can define STBIW_MEMMOVE() to replace memmove()
USAGE:
There are four functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data);
Each function returns 0 on failure and non-0 on success.
The functions create an image file defined by the parameters. The image
is a rectangle of pixels stored from left-to-right, top-to-bottom.
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
The *data pointer points to the first byte of the top-left-most pixel.
For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
a row of pixels to the first byte of the next row of pixels.
PNG creates output files with the same number of components as the input.
The BMP format expands Y to RGB in the file format and does not
output alpha.
PNG supports writing rectangles of data even when the bytes storing rows of
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
by supplying the stride between the beginning of adjacent rows. The other
formats do not. (Thus you cannot write a native-format BMP through the BMP
writer, both because it is in BGR order and because it may have padding
at the end of the line.)
HDR expects linear float data. Since the format is always 32-bit rgb(e)
data, alpha (if provided) is discarded, and for monochrome data it is
replicated across all three channels.
CREDITS:
PNG/BMP/TGA
Sean Barrett
HDR
Baldur Karlsson
TGA monochrome:
Jean-Sebastien Guay
misc enhancements:
Tim Kelsey
bugfixes:
github:Chribba
*/
#ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H
#ifdef __cplusplus
extern "C" {
#endif
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
#ifdef __cplusplus
}
#endif
#endif//INCLUDE_STB_IMAGE_WRITE_H
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && defined(STBIW_REALLOC)
// ok
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC)
// ok
#else
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC."
#endif
#ifndef STBIW_MALLOC
#define STBIW_MALLOC(sz) malloc(sz)
#define STBIW_REALLOC(p,sz) realloc(p,sz)
#define STBIW_FREE(p) free(p)
#endif
#ifndef STBIW_MEMMOVE
#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
#endif
#ifndef STBIW_ASSERT
#include <assert.h>
#define STBIW_ASSERT(x) assert(x)
#endif
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
static void writefv(FILE *f, const char *fmt, va_list v)
{
while (*fmt) {
switch (*fmt++) {
case ' ': break;
case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
case '2': { int x = va_arg(v,int); unsigned char b[2];
b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
fwrite(b,2,1,f); break; }
case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
fwrite(b,4,1,f); break; }
default:
STBIW_ASSERT(0);
return;
}
}
}
static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
{
unsigned char arr[3];
arr[0] = a, arr[1] = b, arr[2] = c;
fwrite(arr, 3, 1, f);
}
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
{
unsigned char bg[3] = { 255, 0, 255}, px[3];
stbiw_uint32 zero = 0;
int i,j,k, j_end;
if (y <= 0)
return;
if (vdir < 0)
j_end = -1, j = y-1;
else
j_end = y, j = 0;
for (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
if (write_alpha < 0)
fwrite(&d[comp-1], 1, 1, f);
switch (comp) {
case 1: fwrite(d, 1, 1, f);
break;
case 2: if (expand_mono)
write3(f, d[0],d[0],d[0]); // monochrome bmp
else
fwrite(d, 1, 1, f); // monochrome TGA
break;
case 4:
if (!write_alpha) {
// composite against pink background
for (k=0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
break;
}
/* FALLTHROUGH */
case 3:
write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
break;
}
if (write_alpha > 0)
fwrite(&d[comp-1], 1, 1, f);
}
fwrite(&zero,scanline_pad,1,f);
}
}
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
{
FILE *f;
if (y < 0 || x < 0) return 0;
f = fopen(filename, "wb");
if (f) {
va_list v;
va_start(v, fmt);
writefv(f, fmt, v);
va_end(v);
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad,expand_mono);
fclose(f);
}
return f != NULL;
}
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{
int pad = (-x*3) & 3;
return outfile(filename,-1,-1,x,y,comp,1,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
}
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{
int has_alpha = (comp == 2 || comp == 4);
int colorbytes = has_alpha ? comp-1 : comp;
int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
return outfile(filename, -1,-1, x, y, comp, 0, (void *) data, has_alpha, 0,
"111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8);
}
// *************************************************************************************************
// Radiance RGBE HDR writer
// by Baldur Karlsson
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
{
int exponent;
float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
if (maxcomp < 1e-32) {
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
} else {
float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
rgbe[0] = (unsigned char)(linear[0] * normalize);
rgbe[1] = (unsigned char)(linear[1] * normalize);
rgbe[2] = (unsigned char)(linear[2] * normalize);
rgbe[3] = (unsigned char)(exponent + 128);
}
}
void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
{
unsigned char lengthbyte = (unsigned char) (length+128);
STBIW_ASSERT(length+128 <= 255);
fwrite(&lengthbyte, 1, 1, f);
fwrite(&databyte, 1, 1, f);
}
void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
{
unsigned char lengthbyte = (unsigned char )(length & 0xff);
STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
fwrite(&lengthbyte, 1, 1, f);
fwrite(data, length, 1, f);
}
void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scratch, const float *scanline)
{
unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
unsigned char rgbe[4];
float linear[3];
int x;
scanlineheader[2] = (width&0xff00)>>8;
scanlineheader[3] = (width&0x00ff);
/* skip RLE for images too small or large */
if (width < 8 || width >= 32768) {
for (x=0; x < width; x++) {
switch (comp) {
case 4: /* fallthrough */
case 3: linear[2] = scanline[x*comp + 2];
linear[1] = scanline[x*comp + 1];
linear[0] = scanline[x*comp + 0];
break;
case 2: /* fallthrough */
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
break;
}
stbiw__linear_to_rgbe(rgbe, linear);
fwrite(rgbe, 4, 1, f);
}
} else {
int c,r;
/* encode into scratch buffer */
for (x=0; x < width; x++) {
switch(comp) {
case 4: /* fallthrough */
case 3: linear[2] = scanline[x*comp + 2];
linear[1] = scanline[x*comp + 1];
linear[0] = scanline[x*comp + 0];
break;
case 2: /* fallthrough */
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
break;
}
stbiw__linear_to_rgbe(rgbe, linear);
scratch[x + width*0] = rgbe[0];
scratch[x + width*1] = rgbe[1];
scratch[x + width*2] = rgbe[2];
scratch[x + width*3] = rgbe[3];
}
fwrite(scanlineheader, 4, 1, f);
/* RLE each component separately */
for (c=0; c < 4; c++) {
unsigned char *comp = &scratch[width*c];
x = 0;
while (x < width) {
// find first run
r = x;
while (r+2 < width) {
if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
break;
++r;
}
if (r+2 >= width)
r = width;
// dump up to first run
while (x < r) {
int len = r-x;
if (len > 128) len = 128;
stbiw__write_dump_data(f, len, &comp[x]);
x += len;
}
// if there's a run, output it
if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
// find next byte after run
while (r < width && comp[r] == comp[x])
++r;
// output run up to r
while (x < r) {
int len = r-x;
if (len > 127) len = 127;
stbiw__write_run_data(f, len, comp[x]);
x += len;
}
}
}
}
}
}
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
{
int i;
FILE *f;
if (y <= 0 || x <= 0 || data == NULL) return 0;
f = fopen(filename, "wb");
if (f) {
/* Each component is stored separately. Allocate scratch space for full output scanline. */
unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
fprintf(f, "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n" );
fprintf(f, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n" , y, x);
for(i=0; i < y; i++)
stbiw__write_hdr_scanline(f, x, comp, scratch, data + comp*i*x);
STBIW_FREE(scratch);
fclose(f);
}
return f != NULL;
}
/////////////////////////////////////////////////////////
// PNG
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
#define stbiw__sbn(a) stbiw__sbraw(a)[1]
#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
{
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
void *p = STBIW_REALLOC(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
STBIW_ASSERT(p);
if (p) {
if (!*arr) ((int *) p)[1] = 0;
*arr = (void *) ((int *) p + 2);
stbiw__sbm(*arr) = m;
}
return *arr;
}
static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{
while (*bitcount >= 8) {
stbiw__sbpush(data, (unsigned char) *bitbuffer);
*bitbuffer >>= 8;
*bitcount -= 8;
}
return data;
}
static int stbiw__zlib_bitrev(int code, int codebits)
{
int res=0;
while (codebits--) {
res = (res << 1) | (code & 1);
code >>= 1;
}
return res;
}
static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
{
int i;
for (i=0; i < limit && i < 258; ++i)
if (a[i] != b[i]) break;
return i;
}
static unsigned int stbiw__zhash(unsigned char *data)
{
stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
#define stbiw__zlib_add(code,codebits) \
(bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
// default huffman tables
#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))
#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
#define stbiw__ZHASH 16384
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
unsigned int bitbuf=0;
int i,j, bitcount=0;
unsigned char *out = NULL;
unsigned char **hash_table[stbiw__ZHASH]; // 64KB on the stack!
if (quality < 5) quality = 5;
stbiw__sbpush(out, 0x78); // DEFLATE 32K window
stbiw__sbpush(out, 0x5e); // FLEVEL = 1
stbiw__zlib_add(1,1); // BFINAL = 1
stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
for (i=0; i < stbiw__ZHASH; ++i)
hash_table[i] = NULL;
i=0;
while (i < data_len-3) {
// hash next 3 bytes of data to be compressed
int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
unsigned char *bestloc = 0;
unsigned char **hlist = hash_table[h];
int n = stbiw__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32768) { // if entry lies within window
int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
if (d >= best) best=d,bestloc=hlist[j];
}
}
// when hash table entry is too long, delete half the entries
if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
stbiw__sbn(hash_table[h]) = quality;
}
stbiw__sbpush(hash_table[h],data+i);
if (bestloc) {
// "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
hlist = hash_table[h];
n = stbiw__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32767) {
int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
if (e > best) { // if next match is better, bail on current match
bestloc = NULL;
break;
}
}
}
}
if (bestloc) {
int d = (int) (data+i - bestloc); // distance back
STBIW_ASSERT(d <= 32767 && best <= 258);
for (j=0; best > lengthc[j+1]-1; ++j);
stbiw__zlib_huff(j+257);
if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
for (j=0; d > distc[j+1]-1; ++j);
stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
i += best;
} else {
stbiw__zlib_huffb(data[i]);
++i;
}
}
// write out final bytes
for (;i < data_len; ++i)
stbiw__zlib_huffb(data[i]);
stbiw__zlib_huff(256); // end of block
// pad with 0 bits to byte boundary
while (bitcount)
stbiw__zlib_add(0,1);
for (i=0; i < stbiw__ZHASH; ++i)
(void) stbiw__sbfree(hash_table[i]);
{
// compute adler32 on input
unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
int j=0;
while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
s1 %= 65521, s2 %= 65521;
j += blocklen;
blocklen = 5552;
}
stbiw__sbpush(out, (unsigned char) (s2 >> 8));
stbiw__sbpush(out, (unsigned char) s2);
stbiw__sbpush(out, (unsigned char) (s1 >> 8));
stbiw__sbpush(out, (unsigned char) s1);
}
*out_len = stbiw__sbn(out);
// make returned pointer freeable
STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
return (unsigned char *) stbiw__sbraw(out);
}
unsigned int stbiw__crc32(unsigned char *buffer, int len)
{
static unsigned int crc_table[256];
unsigned int crc = ~0u;
int i,j;
if (crc_table[1] == 0)
for(i=0; i < 256; i++)
for (crc_table[i]=i, j=0; j < 8; ++j)
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
for (i=0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc;
}
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
static void stbiw__wpcrc(unsigned char **data, int len)
{
unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
stbiw__wp32(*data, crc);
}
static unsigned char stbiw__paeth(int a, int b, int c)
{
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
if (pa <= pb && pa <= pc) return (unsigned char) a;
if (pb <= pc) return (unsigned char) b;
return (unsigned char) c;
}
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{
int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer;
int i,j,k,p,zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 };
int *mymap = j ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff;
for (p=0; p < 2; ++p) {
for (k= p?best:0; k < 5; ++k) {
int type = mymap[k],est=0;
unsigned char *z = pixels + stride_bytes*j;
for (i=0; i < n; ++i)
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
case 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break;
}
for (i=n; i < x*n; ++i) {
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i] - z[i-n]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
}
}
if (p) break;
for (i=0; i < x*n; ++i)
est += abs((signed char) line_buffer[i]);
if (est < bestval) { bestval = est; best = k; }
}
}
// when we get here, best contains the filter type, and line_buffer contains the data
filt[j*(x*n+1)] = (unsigned char) best;
STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
}
STBIW_FREE(line_buffer);
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
STBIW_FREE(filt);
if (!zlib) return 0;
// each tag requires 12 bytes of overhead
out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
if (!out) return 0;
*out_len = 8 + 12+13 + 12+zlen + 12;
o=out;
STBIW_MEMMOVE(o,sig,8); o+= 8;
stbiw__wp32(o, 13); // header length
stbiw__wptag(o, "IHDR");
stbiw__wp32(o, x);
stbiw__wp32(o, y);
*o++ = 8;
*o++ = (unsigned char) ctype[n];
*o++ = 0;
*o++ = 0;
*o++ = 0;
stbiw__wpcrc(&o,13);
stbiw__wp32(o, zlen);
stbiw__wptag(o, "IDAT");
STBIW_MEMMOVE(o, zlib, zlen);
o += zlen;
STBIW_FREE(zlib);
stbiw__wpcrc(&o, zlen);
stbiw__wp32(o,0);
stbiw__wptag(o, "IEND");
stbiw__wpcrc(&o,0);
STBIW_ASSERT(o == out + *out_len);
return out;
}
int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
{
FILE *f;
int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (!png) return 0;
f = fopen(filename, "wb");
if (!f) { STBIW_FREE(png); return 0; }
fwrite(png, 1, len, f);
fclose(f);
STBIW_FREE(png);
return 1;
}
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
0.98 (2015-04-08)
added STBIW_MALLOC, STBIW_ASSERT etc
0.97 (2015-01-18)
fixed HDR asserts, rewrote HDR rle logic
0.96 (2015-01-17)
add HDR output
fix monochrome BMP
0.95 (2014-08-17)
add monochrome TGA output
0.94 (2014-05-31)
rename private functions to avoid conflicts with stb_image.h
0.93 (2014-05-27)
warning fixes
0.92 (2010-08-01)
casts to unsigned char to fix warnings
0.91 (2010-07-17)
first public release
0.90 first internal release
*/

View File

@ -0,0 +1,34 @@
/*
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 int stbi__dds_test_callbacks (stbi_io_callbacks const *clbk, void *user);
extern stbi_uc *stbi__dds_load_from_path (const 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);
extern stbi_uc *stbi__dds_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
#ifndef STBI_NO_STDIO
extern int stbi__dds_test_filename (char const *filename);
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
extern int stbi__dds_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed);
extern int stbi__dds_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed);
#ifndef STBI_NO_STDIO
extern int stbi__dds_info_from_path (char const *filename, int *x, int *y, int *comp, int *iscompressed);
extern int stbi__dds_info_from_file (FILE *f, int *x, int *y, int *comp, int *iscompressed);
#endif
/*
//
//// end header file /////////////////////////////////////////////////////*/
#endif /* HEADER_STB_IMAGE_DDS_AUGMENTATION */

View File

@ -2,103 +2,77 @@
/// 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 ];
#include "image_DXT.h"
// 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)
static int stbi__dds_test(stbi__context *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;
if (stbi__get8(s) != 'D') {
stbi__rewind(s);
return 0;
}
if (stbi__get8(s) != 'D') {
stbi__rewind(s);
return 0;
}
if (stbi__get8(s) != 'S') {
stbi__rewind(s);
return 0;
}
if (stbi__get8(s) != ' ') {
stbi__rewind(s);
return 0;
}
// check header size
if (get32le(s) != 124) return 0;
if (stbi__get32le(s) != 124) {
stbi__rewind(s);
return 0;
}
// Also rewind because the loader needs to read the header
stbi__rewind(s);
return 1;
}
#ifndef STBI_NO_STDIO
int stbi_dds_test_file (FILE *f)
int stbi__dds_test_filename (char const *filename)
{
stbi s;
int r;
FILE *f = fopen(filename, "rb");
if (!f) return 0;
r = stbi__dds_test_file(f);
fclose(f);
return r;
}
int stbi__dds_test_file (FILE *f)
{
stbi__context s;
int r,n = ftell(f);
start_file(&s,f);
r = dds_test(&s);
stbi__start_file(&s,f);
r = stbi__dds_test(&s);
fseek(f,n,SEEK_SET);
return r;
}
#endif
int stbi_dds_test_memory (stbi_uc const *buffer, int len)
int stbi__dds_test_memory (stbi_uc const *buffer, int len)
{
stbi s;
start_mem(&s,buffer, len);
return dds_test(&s);
stbi__context s;
stbi__start_mem(&s,buffer, len);
return stbi__dds_test(&s);
}
int stbi__dds_test_callbacks (stbi_io_callbacks const *clbk, void *user)
{
stbi__context s;
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
return stbi__dds_test(&s);
}
// helper functions
@ -265,7 +239,104 @@ void stbi_decode_DXT_color_block(
}
// done
}
static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
static int stbi__dds_info( stbi__context *s, int *x, int *y, int *comp, int *iscompressed ) {
int flags,is_compressed,has_alpha;
DDS_header header={0};
if( sizeof( DDS_header ) != 128 )
{
return 0;
}
stbi__getn( s, (stbi_uc*)(&header), 128 );
if( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) {
stbi__rewind( s );
return 0;
}
if( header.dwSize != 124 ) {
stbi__rewind( s );
return 0;
}
flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
if( (header.dwFlags & flags) != flags ) {
stbi__rewind( s );
return 0;
}
if( header.sPixelFormat.dwSize != 32 ) {
stbi__rewind( s );
return 0;
}
flags = DDPF_FOURCC | DDPF_RGB;
if( (header.sPixelFormat.dwFlags & flags) == 0 ) {
stbi__rewind( s );
return 0;
}
if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) {
stbi__rewind( s );
return 0;
}
is_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC;
has_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS;
*x = header.dwWidth;
*y = header.dwHeight;
if ( !is_compressed ) {
*comp = 3;
if ( has_alpha )
*comp = 4;
}
else
*comp = 4;
if ( iscompressed )
*iscompressed = is_compressed;
return 1;
}
int stbi__dds_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed)
{
stbi__context s;
stbi__start_mem(&s,buffer, len);
return stbi__dds_info( &s, x, y, comp, iscompressed );
}
int stbi__dds_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed)
{
stbi__context s;
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
return stbi__dds_info( &s, x, y, comp, iscompressed );
}
#ifndef STBI_NO_STDIO
int stbi__dds_info_from_path(char const *filename, int *x, int *y, int *comp, int *iscompressed)
{
int res;
FILE *f = fopen(filename, "rb");
if (!f) return 0;
res = stbi__dds_info_from_file( f, x, y, comp, iscompressed );
fclose(f);
return res;
}
int stbi__dds_info_from_file(FILE *f, int *x, int *y, int *comp, int *iscompressed)
{
stbi__context s;
int res;
long n = ftell(f);
stbi__start_file(&s, f);
res = stbi__dds_info(&s, x, y, comp, iscompressed);
fseek(f, n, SEEK_SET);
return res;
}
#endif
static stbi_uc * stbi__dds_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{
// all variables go up front
stbi_uc *dds_data = NULL;
@ -275,14 +346,14 @@ static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
int has_alpha, has_mipmap;
int is_compressed, cubemap_faces;
int block_pitch, num_blocks;
DDS_header header;
DDS_header header={0};
int i, sz, cf;
// load the header
if( sizeof( DDS_header ) != 128 )
{
return NULL;
}
getn( s, (stbi_uc*)(&header), 128 );
stbi__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;
@ -341,29 +412,29 @@ static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
if( DXT_family == 1 )
{
// DXT1
getn( s, compressed, 8 );
stbi__getn( s, compressed, 8 );
stbi_decode_DXT1_block( block, compressed );
} else if( DXT_family < 4 )
{
// DXT2/3
getn( s, compressed, 8 );
stbi__getn( s, compressed, 8 );
stbi_decode_DXT23_alpha_block ( block, compressed );
getn( s, compressed, 8 );
stbi__getn( s, compressed, 8 );
stbi_decode_DXT_color_block ( block, compressed );
} else
{
// DXT4/5
getn( s, compressed, 8 );
stbi__getn( s, compressed, 8 );
stbi_decode_DXT45_alpha_block ( block, compressed );
getn( s, compressed, 8 );
stbi__getn( s, compressed, 8 );
stbi_decode_DXT_color_block ( block, compressed );
}
// is this a partial block?
if( ref_x + 4 > s->img_x )
if( ref_x + 4 > (int)s->img_x )
{
bw = s->img_x - ref_x;
}
if( ref_y + 4 > s->img_y )
if( ref_y + 4 > (int)s->img_y )
{
bh = s->img_y - ref_y;
}
@ -379,7 +450,7 @@ static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
}
}
/* done reading and decoding the main image...
skip MIPmaps if present */
stbi__skip MIPmaps if present */
if( has_mipmap )
{
int block_size = 16;
@ -387,7 +458,7 @@ static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
{
block_size = 8;
}
for( i = 1; i < header.dwMipMapCount; ++i )
for( i = 1; i < (int)header.dwMipMapCount; ++i )
{
int mx = s->img_x >> (i + 2);
int my = s->img_y >> (i + 2);
@ -399,7 +470,7 @@ static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
{
my = 1;
}
skip( s, mx*my*block_size );
stbi__skip( s, mx*my*block_size );
}
}
}/* per cubemap face */
@ -419,12 +490,12 @@ static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
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 );
stbi__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 */
stbi__skip MIPmaps if present */
if( has_mipmap )
{
for( i = 1; i < header.dwMipMapCount; ++i )
for( i = 1; i < (int)header.dwMipMapCount; ++i )
{
int mx = s->img_x >> i;
int my = s->img_y >> i;
@ -436,7 +507,7 @@ static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
{
my = 1;
}
skip( s, mx*my*s->img_n );
stbi__skip( s, mx*my*s->img_n );
}
}
}
@ -468,15 +539,15 @@ static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
// 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;
dds_data = stbi__convert_format( dds_data, s->img_n, req_comp, s->img_x, s->img_y );
*comp = req_comp;
}
} 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 );
dds_data = stbi__convert_format( dds_data, 4, 3, s->img_x, s->img_y );
*comp = 3;
}
}
@ -485,27 +556,34 @@ static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
}
#ifndef STBI_NO_STDIO
stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp)
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__context s;
stbi__start_file(&s,f);
return stbi__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 *stbi__dds_load_from_path (const 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);
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_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);
stbi__context s;
stbi__start_mem(&s,buffer, len);
return stbi__dds_load(&s,x,y,comp,req_comp);
}
stbi_uc *stbi__dds_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
{
stbi__context s;
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
return stbi__dds_load(&s,x,y,comp,req_comp);
}

View File

@ -0,0 +1,28 @@
#ifndef HEADER_STB_IMAGE_EXT
#define HEADER_STB_IMAGE_EXT
enum {
STBI_unknown= 0,
STBI_jpeg = 1,
STBI_png = 2,
STBI_bmp = 3,
STBI_gif = 4,
STBI_tga = 5,
STBI_psd = 6,
STBI_pic = 7,
STBI_pnm = 8,
STBI_dds = 9,
STBI_pvr = 10,
STBI_pkm = 11,
STBI_hdr = 12
};
extern int stbi_test_from_memory (stbi_uc const *buffer, int len);
extern int stbi_test_from_callbacks (stbi_io_callbacks const *clbk, void *user);
#ifndef STBI_NO_STDIO
extern int stbi_test (char const *filename);
extern int stbi_test_from_file (FILE *f);
#endif
#endif /* HEADER_STB_IMAGE_EXT */

View File

@ -0,0 +1,74 @@
static int stbi_test_main(stbi__context *s)
{
#ifndef STBI_NO_JPEG
if (stbi__jpeg_test(s)) return STBI_jpeg;
#endif
#ifndef STBI_NO_PNG
if (stbi__png_test(s)) return STBI_png;
#endif
#ifndef STBI_NO_BMP
if (stbi__bmp_test(s)) return STBI_bmp;
#endif
#ifndef STBI_NO_GIF
if (stbi__gif_test(s)) return STBI_gif;
#endif
#ifndef STBI_NO_PSD
if (stbi__psd_test(s)) return STBI_psd;
#endif
#ifndef STBI_NO_PIC
if (stbi__pic_test(s)) return STBI_pic;
#endif
#ifndef STBI_NO_PNM
if (stbi__pnm_test(s)) return STBI_pnm;
#endif
#ifndef STBI_NO_DDS
if (stbi__dds_test(s)) return STBI_dds;
#endif
#ifndef STBI_NO_PVR
if (stbi__pvr_test(s)) return STBI_pvr;
#endif
#ifndef STBI_NO_PKM
if (stbi__pkm_test(s)) return STBI_pkm;
#endif
#ifndef STBI_NO_HDR
if (stbi__hdr_test(s)) return STBI_hdr;
#endif
#ifndef STBI_NO_TGA
if (stbi__tga_test(s)) return STBI_tga;
#endif
return STBI_unknown;
}
#ifndef STBI_NO_STDIO
int stbi_test_from_file(FILE *f)
{
stbi__context s;
stbi__start_file(&s,f);
return stbi_test_main(&s);
}
int stbi_test(char const *filename)
{
FILE *f = fopen(filename, "rb");
int result;
if (!f) return STBI_unknown;
result = stbi_test_from_file(f);
fclose(f);
return result;
}
#endif //!STBI_NO_STDIO
int stbi_test_from_memory(stbi_uc const *buffer, int len)
{
stbi__context s;
stbi__start_mem(&s,buffer,len);
return stbi_test_main(&s);
}
int stbi_test_from_callbacks(stbi_io_callbacks const *clbk, void *user)
{
stbi__context s;
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
return stbi_test_main(&s);
}

View File

@ -0,0 +1,34 @@
/*
adding PKM loading support to stbi
*/
#ifndef HEADER_STB_IMAGE_PKM_AUGMENTATION
#define HEADER_STB_IMAGE_PKM_AUGMENTATION
/* is it a PKM file? */
extern int stbi__pkm_test_memory (stbi_uc const *buffer, int len);
extern int stbi__pkm_test_callbacks (stbi_io_callbacks const *clbk, void *user);
extern stbi_uc *stbi__pkm_load_from_path (char const *filename, int *x, int *y, int *comp, int req_comp);
extern stbi_uc *stbi__pkm_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
extern stbi_uc *stbi__pkm_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
#ifndef STBI_NO_STDIO
extern int stbi__pkm_test_filename (char const *filename);
extern int stbi__pkm_test_file (FILE *f);
extern stbi_uc *stbi__pkm_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
#endif
extern int stbi__pkm_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp);
extern int stbi__pkm_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
#ifndef STBI_NO_STDIO
extern int stbi__pkm_info_from_path (char const *filename, int *x, int *y, int *comp);
extern int stbi__pkm_info_from_file (FILE *f, int *x, int *y, int *comp);
#endif
/*
//
//// end header file /////////////////////////////////////////////////////*/
#endif /* HEADER_STB_IMAGE_PKM_AUGMENTATION */

View File

@ -0,0 +1,227 @@
#include "pkm_helper.h"
#include "etc1_utils.h"
static int stbi__pkm_test(stbi__context *s)
{
// check the magic number
if (stbi__get8(s) != 'P') {
stbi__rewind(s);
return 0;
}
if (stbi__get8(s) != 'K') {
stbi__rewind(s);
return 0;
}
if (stbi__get8(s) != 'M') {
stbi__rewind(s);
return 0;
}
if (stbi__get8(s) != ' ') {
stbi__rewind(s);
return 0;
}
if (stbi__get8(s) != '1') {
stbi__rewind(s);
return 0;
}
if (stbi__get8(s) != '0') {
stbi__rewind(s);
return 0;
}
stbi__rewind(s);
return 1;
}
#ifndef STBI_NO_STDIO
int stbi__pkm_test_filename (char const *filename)
{
int r;
FILE *f = fopen(filename, "rb");
if (!f) return 0;
r = stbi__pkm_test_file(f);
fclose(f);
return r;
}
int stbi__pkm_test_file (FILE *f)
{
stbi__context s;
int r,n = ftell(f);
stbi__start_file(&s,f);
r = stbi__pkm_test(&s);
fseek(f,n,SEEK_SET);
return r;
}
#endif
int stbi__pkm_test_memory (stbi_uc const *buffer, int len)
{
stbi__context s;
stbi__start_mem(&s,buffer, len);
return stbi__pkm_test(&s);
}
int stbi__pkm_test_callbacks (stbi_io_callbacks const *clbk, void *user)
{
stbi__context s;
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
return stbi__pkm_test(&s);
}
static int stbi__pkm_info(stbi__context *s, int *x, int *y, int *comp )
{
PKMHeader header;
unsigned int width, height;
stbi__getn( s, (stbi_uc*)(&header), sizeof(PKMHeader) );
if ( 0 != strcmp( header.aName, "PKM 10" ) ) {
stbi__rewind(s);
return 0;
}
width = (header.iWidthMSB << 8) | header.iWidthLSB;
height = (header.iHeightMSB << 8) | header.iHeightLSB;
*x = s->img_x = width;
*y = s->img_y = height;
*comp = s->img_n = 3;
stbi__rewind(s);
return 1;
}
int stbi__pkm_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp )
{
stbi__context s;
stbi__start_mem(&s,buffer, len);
return stbi__pkm_info( &s, x, y, comp );
}
int stbi__pkm_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp)
{
stbi__context s;
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
return stbi__pkm_info( &s, x, y, comp );
}
#ifndef STBI_NO_STDIO
int stbi__pkm_info_from_path(char const *filename, int *x, int *y, int *comp)
{
int res;
FILE *f = fopen(filename, "rb");
if (!f) return 0;
res = stbi__pkm_info_from_file( f, x, y, comp );
fclose(f);
return res;
}
int stbi__pkm_info_from_file(FILE *f, int *x, int *y, int *comp)
{
stbi__context s;
int res;
long n = ftell(f);
stbi__start_file(&s, f);
res = stbi__pkm_info(&s, x, y, comp);
fseek(f, n, SEEK_SET);
return res;
}
#endif
static stbi_uc * stbi__pkm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{
stbi_uc *pkm_data = NULL;
stbi_uc *pkm_res_data = NULL;
PKMHeader header;
unsigned int width;
unsigned int height;
unsigned int align = 0;
unsigned int bpr;
unsigned int size;
unsigned int compressedSize;
int res;
stbi__getn( s, (stbi_uc*)(&header), sizeof(PKMHeader) );
if ( 0 != strcmp( header.aName, "PKM 10" ) ) {
return NULL;
}
width = (header.iWidthMSB << 8) | header.iWidthLSB;
height = (header.iHeightMSB << 8) | header.iHeightLSB;
*x = s->img_x = width;
*y = s->img_y = height;
*comp = s->img_n = 3;
compressedSize = etc1_get_encoded_data_size(width, height);
pkm_data = (stbi_uc *)malloc(compressedSize);
stbi__getn( s, pkm_data, compressedSize );
bpr = ((width * 3) + align) & ~align;
size = bpr * height;
pkm_res_data = (stbi_uc *)malloc(size);
res = etc1_decode_image((const etc1_byte*)pkm_data, (etc1_byte*)pkm_res_data, width, height, 3, bpr);
free( pkm_data );
if ( 0 == res ) {
if( (req_comp <= 4) && (req_comp >= 1) ) {
// user has some requirements, meet them
if( req_comp != s->img_n ) {
pkm_res_data = stbi__convert_format( pkm_res_data, s->img_n, req_comp, s->img_x, s->img_y );
*comp = req_comp;
}
}
return (stbi_uc *)pkm_res_data;
} else {
free( pkm_res_data );
}
return NULL;
}
#ifndef STBI_NO_STDIO
stbi_uc *stbi__pkm_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp)
{
stbi__context s;
stbi__start_file(&s,f);
return stbi__pkm_load(&s,x,y,comp,req_comp);
}
stbi_uc *stbi__pkm_load_from_path (char const*filename, int *x, int *y, int *comp, int req_comp)
{
stbi_uc *data;
FILE *f = fopen(filename, "rb");
if (!f) return NULL;
data = stbi__pkm_load_from_file(f,x,y,comp,req_comp);
fclose(f);
return data;
}
#endif
stbi_uc *stbi__pkm_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
{
stbi__context s;
stbi__start_mem(&s,buffer, len);
return stbi__pkm_load(&s,x,y,comp,req_comp);
}
stbi_uc *stbi__pkm_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
{
stbi__context s;
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
return stbi__pkm_load(&s,x,y,comp,req_comp);
}

View File

@ -0,0 +1,34 @@
/*
adding PVR loading support to stbi
*/
#ifndef HEADER_STB_IMAGE_PVR_AUGMENTATION
#define HEADER_STB_IMAGE_PVR_AUGMENTATION
/* is it a PVR file? */
extern int stbi__pvr_test_memory (stbi_uc const *buffer, int len);
extern int stbi__pvr_test_callbacks (stbi_io_callbacks const *clbk, void *user);
extern stbi_uc *stbi__pvr_load_from_path (char const *filename, int *x, int *y, int *comp, int req_comp);
extern stbi_uc *stbi__pvr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
extern stbi_uc *stbi__pvr_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
#ifndef STBI_NO_STDIO
extern int stbi__pvr_test_filename (char const *filename);
extern int stbi__pvr_test_file (FILE *f);
extern stbi_uc *stbi__pvr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
#endif
extern int stbi__pvr_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed);
extern int stbi__pvr_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed);
#ifndef STBI_NO_STDIO
extern int stbi__pvr_info_from_path (char const *filename, int *x, int *y, int *comp, int *iscompressed);
extern int stbi__pvr_info_from_file (FILE *f, int *x, int *y, int *comp, int *iscompressed);
#endif
/*
//
//// end header file /////////////////////////////////////////////////////*/
#endif /* HEADER_STB_IMAGE_PVR_AUGMENTATION */

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@
#ifdef USE_DEVIL
#include <IL/ilut.h>
#else
#include "SOIL/SOIL.h"
#include "SOIL2/SOIL2.h"
#endif
#ifdef WIN32
@ -179,7 +179,7 @@ GLuint TextureManager::getTextureFullpath(const std::string filename, const std:
#else
int width, height;
unsigned int tex = SOIL_load_OGL_texture_size(
unsigned int tex = SOIL_load_OGL_texture(
imageURL.c_str(),
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
@ -189,7 +189,8 @@ GLuint TextureManager::getTextureFullpath(const std::string filename, const std:
SOIL_FLAG_MULTIPLY_ALPHA
//| SOIL_FLAG_COMPRESS_TO_DXT
//| SOIL_FLAG_DDS_LOAD_DIRECT
,&width,&height);
//,&width,&height);
);
#endif
textures[filename]=tex;