mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-28 00:35:34 +00:00
Forgot to upload some files crucial to SOIL
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3169 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
58058311f4
commit
14f9d84e60
632
Source/Core/VideoCommon/Src/SOIL/image_DXT.c
Normal file
632
Source/Core/VideoCommon/Src/SOIL/image_DXT.c
Normal file
@ -0,0 +1,632 @@
|
|||||||
|
/*
|
||||||
|
Jonathan Dummer
|
||||||
|
2007-07-31-10.32
|
||||||
|
|
||||||
|
simple DXT compression / decompression code
|
||||||
|
|
||||||
|
public domain
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "image_DXT.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* set this =1 if you want to use the covarince matrix method...
|
||||||
|
which is better than my method of using standard deviations
|
||||||
|
overall, except on the infintesimal chance that the power
|
||||||
|
method fails for finding the largest eigenvector */
|
||||||
|
#define USE_COV_MAT 1
|
||||||
|
|
||||||
|
/********* Function Prototypes *********/
|
||||||
|
/*
|
||||||
|
Takes a 4x4 block of pixels and compresses it into 8 bytes
|
||||||
|
in DXT1 format (color only, no alpha). Speed is valued
|
||||||
|
over prettyness, at least for now.
|
||||||
|
*/
|
||||||
|
void compress_DDS_color_block(
|
||||||
|
int channels,
|
||||||
|
const unsigned char *const uncompressed,
|
||||||
|
unsigned char compressed[8] );
|
||||||
|
/*
|
||||||
|
Takes a 4x4 block of pixels and compresses the alpha
|
||||||
|
component it into 8 bytes for use in DXT5 DDS files.
|
||||||
|
Speed is valued over prettyness, at least for now.
|
||||||
|
*/
|
||||||
|
void compress_DDS_alpha_block(
|
||||||
|
const unsigned char *const uncompressed,
|
||||||
|
unsigned char compressed[8] );
|
||||||
|
|
||||||
|
/********* Actual Exposed Functions *********/
|
||||||
|
int
|
||||||
|
save_image_as_DDS
|
||||||
|
(
|
||||||
|
const char *filename,
|
||||||
|
int width, int height, int channels,
|
||||||
|
const unsigned char *const data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* variables */
|
||||||
|
FILE *fout;
|
||||||
|
unsigned char *DDS_data;
|
||||||
|
DDS_header header;
|
||||||
|
int DDS_size;
|
||||||
|
/* error check */
|
||||||
|
if( (NULL == filename) ||
|
||||||
|
(width < 1) || (height < 1) ||
|
||||||
|
(channels < 1) || (channels > 4) ||
|
||||||
|
(data == NULL ) )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Convert the image */
|
||||||
|
if( (channels & 1) == 1 )
|
||||||
|
{
|
||||||
|
/* no alpha, just use DXT1 */
|
||||||
|
DDS_data = convert_image_to_DXT1( data, width, height, channels, &DDS_size );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
/* has alpha, so use DXT5 */
|
||||||
|
DDS_data = convert_image_to_DXT5( data, width, height, channels, &DDS_size );
|
||||||
|
}
|
||||||
|
/* save it */
|
||||||
|
memset( &header, 0, sizeof( DDS_header ) );
|
||||||
|
header.dwMagic = ('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24);
|
||||||
|
header.dwSize = 124;
|
||||||
|
header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_LINEARSIZE;
|
||||||
|
header.dwWidth = width;
|
||||||
|
header.dwHeight = height;
|
||||||
|
header.dwPitchOrLinearSize = DDS_size;
|
||||||
|
header.sPixelFormat.dwSize = 32;
|
||||||
|
header.sPixelFormat.dwFlags = DDPF_FOURCC;
|
||||||
|
if( (channels & 1) == 1 )
|
||||||
|
{
|
||||||
|
header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('1' << 24);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('5' << 24);
|
||||||
|
}
|
||||||
|
header.sCaps.dwCaps1 = DDSCAPS_TEXTURE;
|
||||||
|
/* write it out */
|
||||||
|
fout = fopen( filename, "wb");
|
||||||
|
fwrite( &header, sizeof( DDS_header ), 1, fout );
|
||||||
|
fwrite( DDS_data, 1, DDS_size, fout );
|
||||||
|
fclose( fout );
|
||||||
|
/* done */
|
||||||
|
free( DDS_data );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* convert_image_to_DXT1(
|
||||||
|
const unsigned char *const uncompressed,
|
||||||
|
int width, int height, int channels,
|
||||||
|
int *out_size )
|
||||||
|
{
|
||||||
|
unsigned char *compressed;
|
||||||
|
int i, j, x, y;
|
||||||
|
unsigned char ublock[16*3];
|
||||||
|
unsigned char cblock[8];
|
||||||
|
int index = 0, chan_step = 1;
|
||||||
|
int block_count = 0;
|
||||||
|
/* error check */
|
||||||
|
*out_size = 0;
|
||||||
|
if( (width < 1) || (height < 1) ||
|
||||||
|
(NULL == uncompressed) ||
|
||||||
|
(channels < 1) || (channels > 4) )
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* for channels == 1 or 2, I do not step forward for R,G,B values */
|
||||||
|
if( channels < 3 )
|
||||||
|
{
|
||||||
|
chan_step = 0;
|
||||||
|
}
|
||||||
|
/* get the RAM for the compressed image
|
||||||
|
(8 bytes per 4x4 pixel block) */
|
||||||
|
*out_size = ((width+3) >> 2) * ((height+3) >> 2) * 8;
|
||||||
|
compressed = (unsigned char*)malloc( *out_size );
|
||||||
|
/* go through each block */
|
||||||
|
for( j = 0; j < height; j += 4 )
|
||||||
|
{
|
||||||
|
for( i = 0; i < width; i += 4 )
|
||||||
|
{
|
||||||
|
/* copy this block into a new one */
|
||||||
|
int idx = 0;
|
||||||
|
int mx = 4, my = 4;
|
||||||
|
if( j+4 >= height )
|
||||||
|
{
|
||||||
|
my = height - j;
|
||||||
|
}
|
||||||
|
if( i+4 >= width )
|
||||||
|
{
|
||||||
|
mx = width - i;
|
||||||
|
}
|
||||||
|
for( y = 0; y < my; ++y )
|
||||||
|
{
|
||||||
|
for( x = 0; x < mx; ++x )
|
||||||
|
{
|
||||||
|
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels];
|
||||||
|
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step];
|
||||||
|
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step];
|
||||||
|
}
|
||||||
|
for( x = mx; x < 4; ++x )
|
||||||
|
{
|
||||||
|
ublock[idx++] = ublock[0];
|
||||||
|
ublock[idx++] = ublock[1];
|
||||||
|
ublock[idx++] = ublock[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for( y = my; y < 4; ++y )
|
||||||
|
{
|
||||||
|
for( x = 0; x < 4; ++x )
|
||||||
|
{
|
||||||
|
ublock[idx++] = ublock[0];
|
||||||
|
ublock[idx++] = ublock[1];
|
||||||
|
ublock[idx++] = ublock[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* compress the block */
|
||||||
|
++block_count;
|
||||||
|
compress_DDS_color_block( 3, ublock, cblock );
|
||||||
|
/* copy the data from the block into the main block */
|
||||||
|
for( x = 0; x < 8; ++x )
|
||||||
|
{
|
||||||
|
compressed[index++] = cblock[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* convert_image_to_DXT5(
|
||||||
|
const unsigned char *const uncompressed,
|
||||||
|
int width, int height, int channels,
|
||||||
|
int *out_size )
|
||||||
|
{
|
||||||
|
unsigned char *compressed;
|
||||||
|
int i, j, x, y;
|
||||||
|
unsigned char ublock[16*4];
|
||||||
|
unsigned char cblock[8];
|
||||||
|
int index = 0, chan_step = 1;
|
||||||
|
int block_count = 0, has_alpha;
|
||||||
|
/* error check */
|
||||||
|
*out_size = 0;
|
||||||
|
if( (width < 1) || (height < 1) ||
|
||||||
|
(NULL == uncompressed) ||
|
||||||
|
(channels < 1) || ( channels > 4) )
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* for channels == 1 or 2, I do not step forward for R,G,B vales */
|
||||||
|
if( channels < 3 )
|
||||||
|
{
|
||||||
|
chan_step = 0;
|
||||||
|
}
|
||||||
|
/* # channels = 1 or 3 have no alpha, 2 & 4 do have alpha */
|
||||||
|
has_alpha = 1 - (channels & 1);
|
||||||
|
/* get the RAM for the compressed image
|
||||||
|
(16 bytes per 4x4 pixel block) */
|
||||||
|
*out_size = ((width+3) >> 2) * ((height+3) >> 2) * 16;
|
||||||
|
compressed = (unsigned char*)malloc( *out_size );
|
||||||
|
/* go through each block */
|
||||||
|
for( j = 0; j < height; j += 4 )
|
||||||
|
{
|
||||||
|
for( i = 0; i < width; i += 4 )
|
||||||
|
{
|
||||||
|
/* local variables, and my block counter */
|
||||||
|
int idx = 0;
|
||||||
|
int mx = 4, my = 4;
|
||||||
|
if( j+4 >= height )
|
||||||
|
{
|
||||||
|
my = height - j;
|
||||||
|
}
|
||||||
|
if( i+4 >= width )
|
||||||
|
{
|
||||||
|
mx = width - i;
|
||||||
|
}
|
||||||
|
for( y = 0; y < my; ++y )
|
||||||
|
{
|
||||||
|
for( x = 0; x < mx; ++x )
|
||||||
|
{
|
||||||
|
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels];
|
||||||
|
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step];
|
||||||
|
ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step];
|
||||||
|
ublock[idx++] =
|
||||||
|
has_alpha * uncompressed[(j+y)*width*channels+(i+x)*channels+channels-1]
|
||||||
|
+ (1-has_alpha)*255;
|
||||||
|
}
|
||||||
|
for( x = mx; x < 4; ++x )
|
||||||
|
{
|
||||||
|
ublock[idx++] = ublock[0];
|
||||||
|
ublock[idx++] = ublock[1];
|
||||||
|
ublock[idx++] = ublock[2];
|
||||||
|
ublock[idx++] = ublock[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for( y = my; y < 4; ++y )
|
||||||
|
{
|
||||||
|
for( x = 0; x < 4; ++x )
|
||||||
|
{
|
||||||
|
ublock[idx++] = ublock[0];
|
||||||
|
ublock[idx++] = ublock[1];
|
||||||
|
ublock[idx++] = ublock[2];
|
||||||
|
ublock[idx++] = ublock[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* now compress the alpha block */
|
||||||
|
compress_DDS_alpha_block( ublock, cblock );
|
||||||
|
/* copy the data from the compressed alpha block into the main buffer */
|
||||||
|
for( x = 0; x < 8; ++x )
|
||||||
|
{
|
||||||
|
compressed[index++] = cblock[x];
|
||||||
|
}
|
||||||
|
/* then compress the color block */
|
||||||
|
++block_count;
|
||||||
|
compress_DDS_color_block( 4, ublock, cblock );
|
||||||
|
/* copy the data from the compressed color block into the main buffer */
|
||||||
|
for( x = 0; x < 8; ++x )
|
||||||
|
{
|
||||||
|
compressed[index++] = cblock[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********* Helper Functions *********/
|
||||||
|
int convert_bit_range( int c, int from_bits, int to_bits )
|
||||||
|
{
|
||||||
|
int b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1);
|
||||||
|
return (b + (b >> from_bits)) >> from_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rgb_to_565( int r, int g, int b )
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(convert_bit_range( r, 8, 5 ) << 11) |
|
||||||
|
(convert_bit_range( g, 8, 6 ) << 05) |
|
||||||
|
(convert_bit_range( b, 8, 5 ) << 00);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rgb_888_from_565( unsigned int c, int *r, int *g, int *b )
|
||||||
|
{
|
||||||
|
*r = convert_bit_range( (c >> 11) & 31, 5, 8 );
|
||||||
|
*g = convert_bit_range( (c >> 05) & 63, 6, 8 );
|
||||||
|
*b = convert_bit_range( (c >> 00) & 31, 5, 8 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void compute_color_line_STDEV(
|
||||||
|
const unsigned char *const uncompressed,
|
||||||
|
int channels,
|
||||||
|
float point[3], float direction[3] )
|
||||||
|
{
|
||||||
|
const float inv_16 = 1.0f / 16.0f;
|
||||||
|
int i;
|
||||||
|
float sum_r = 0.0f, sum_g = 0.0f, sum_b = 0.0f;
|
||||||
|
float sum_rr = 0.0f, sum_gg = 0.0f, sum_bb = 0.0f;
|
||||||
|
float sum_rg = 0.0f, sum_rb = 0.0f, sum_gb = 0.0f;
|
||||||
|
/* calculate all data needed for the covariance matrix
|
||||||
|
( to compare with _rygdxt code) */
|
||||||
|
for( i = 0; i < 16*channels; i += channels )
|
||||||
|
{
|
||||||
|
sum_r += uncompressed[i+0];
|
||||||
|
sum_rr += uncompressed[i+0] * uncompressed[i+0];
|
||||||
|
sum_g += uncompressed[i+1];
|
||||||
|
sum_gg += uncompressed[i+1] * uncompressed[i+1];
|
||||||
|
sum_b += uncompressed[i+2];
|
||||||
|
sum_bb += uncompressed[i+2] * uncompressed[i+2];
|
||||||
|
sum_rg += uncompressed[i+0] * uncompressed[i+1];
|
||||||
|
sum_rb += uncompressed[i+0] * uncompressed[i+2];
|
||||||
|
sum_gb += uncompressed[i+1] * uncompressed[i+2];
|
||||||
|
}
|
||||||
|
/* convert the sums to averages */
|
||||||
|
sum_r *= inv_16;
|
||||||
|
sum_g *= inv_16;
|
||||||
|
sum_b *= inv_16;
|
||||||
|
/* and convert the squares to the squares of the value - avg_value */
|
||||||
|
sum_rr -= 16.0f * sum_r * sum_r;
|
||||||
|
sum_gg -= 16.0f * sum_g * sum_g;
|
||||||
|
sum_bb -= 16.0f * sum_b * sum_b;
|
||||||
|
sum_rg -= 16.0f * sum_r * sum_g;
|
||||||
|
sum_rb -= 16.0f * sum_r * sum_b;
|
||||||
|
sum_gb -= 16.0f * sum_g * sum_b;
|
||||||
|
/* the point on the color line is the average */
|
||||||
|
point[0] = sum_r;
|
||||||
|
point[1] = sum_g;
|
||||||
|
point[2] = sum_b;
|
||||||
|
#if USE_COV_MAT
|
||||||
|
/*
|
||||||
|
The following idea was from ryg.
|
||||||
|
(https://mollyrocket.com/forums/viewtopic.php?t=392)
|
||||||
|
The method worked great (less RMSE than mine) most of
|
||||||
|
the time, but had some issues handling some simple
|
||||||
|
boundary cases, like full green next to full red,
|
||||||
|
which would generate a covariance matrix like this:
|
||||||
|
|
||||||
|
| 1 -1 0 |
|
||||||
|
| -1 1 0 |
|
||||||
|
| 0 0 0 |
|
||||||
|
|
||||||
|
For a given starting vector, the power method can
|
||||||
|
generate all zeros! So no starting with {1,1,1}
|
||||||
|
as I was doing! This kind of error is still a
|
||||||
|
slight posibillity, but will be very rare.
|
||||||
|
*/
|
||||||
|
/* use the covariance matrix directly
|
||||||
|
(1st iteration, don't use all 1.0 values!) */
|
||||||
|
sum_r = 1.0f;
|
||||||
|
sum_g = 2.718281828f;
|
||||||
|
sum_b = 3.141592654f;
|
||||||
|
direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb;
|
||||||
|
direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb;
|
||||||
|
direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb;
|
||||||
|
/* 2nd iteration, use results from the 1st guy */
|
||||||
|
sum_r = direction[0];
|
||||||
|
sum_g = direction[1];
|
||||||
|
sum_b = direction[2];
|
||||||
|
direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb;
|
||||||
|
direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb;
|
||||||
|
direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb;
|
||||||
|
/* 3rd iteration, use results from the 2nd guy */
|
||||||
|
sum_r = direction[0];
|
||||||
|
sum_g = direction[1];
|
||||||
|
sum_b = direction[2];
|
||||||
|
direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb;
|
||||||
|
direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb;
|
||||||
|
direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb;
|
||||||
|
#else
|
||||||
|
/* use my standard deviation method
|
||||||
|
(very robust, a tiny bit slower and less accurate) */
|
||||||
|
direction[0] = sqrt( sum_rr );
|
||||||
|
direction[1] = sqrt( sum_gg );
|
||||||
|
direction[2] = sqrt( sum_bb );
|
||||||
|
/* which has a greater component */
|
||||||
|
if( sum_gg > sum_rr )
|
||||||
|
{
|
||||||
|
/* green has greater component, so base the other signs off of green */
|
||||||
|
if( sum_rg < 0.0f )
|
||||||
|
{
|
||||||
|
direction[0] = -direction[0];
|
||||||
|
}
|
||||||
|
if( sum_gb < 0.0f )
|
||||||
|
{
|
||||||
|
direction[2] = -direction[2];
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
/* red has a greater component */
|
||||||
|
if( sum_rg < 0.0f )
|
||||||
|
{
|
||||||
|
direction[1] = -direction[1];
|
||||||
|
}
|
||||||
|
if( sum_rb < 0.0f )
|
||||||
|
{
|
||||||
|
direction[2] = -direction[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void LSE_master_colors_max_min(
|
||||||
|
int *cmax, int *cmin,
|
||||||
|
int channels,
|
||||||
|
const unsigned char *const uncompressed )
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
/* the master colors */
|
||||||
|
int c0[3], c1[3];
|
||||||
|
/* used for fitting the line */
|
||||||
|
float sum_x[] = { 0.0f, 0.0f, 0.0f };
|
||||||
|
float sum_x2[] = { 0.0f, 0.0f, 0.0f };
|
||||||
|
float dot_max = 1.0f, dot_min = -1.0f;
|
||||||
|
float vec_len2 = 0.0f;
|
||||||
|
float dot;
|
||||||
|
/* error check */
|
||||||
|
if( (channels < 3) || (channels > 4) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
compute_color_line_STDEV( uncompressed, channels, sum_x, sum_x2 );
|
||||||
|
vec_len2 = 1.0f / ( 0.00001f +
|
||||||
|
sum_x2[0]*sum_x2[0] + sum_x2[1]*sum_x2[1] + sum_x2[2]*sum_x2[2] );
|
||||||
|
/* finding the max and min vector values */
|
||||||
|
dot_max =
|
||||||
|
(
|
||||||
|
sum_x2[0] * uncompressed[0] +
|
||||||
|
sum_x2[1] * uncompressed[1] +
|
||||||
|
sum_x2[2] * uncompressed[2]
|
||||||
|
);
|
||||||
|
dot_min = dot_max;
|
||||||
|
for( i = 1; i < 16; ++i )
|
||||||
|
{
|
||||||
|
dot =
|
||||||
|
(
|
||||||
|
sum_x2[0] * uncompressed[i*channels+0] +
|
||||||
|
sum_x2[1] * uncompressed[i*channels+1] +
|
||||||
|
sum_x2[2] * uncompressed[i*channels+2]
|
||||||
|
);
|
||||||
|
if( dot < dot_min )
|
||||||
|
{
|
||||||
|
dot_min = dot;
|
||||||
|
} else if( dot > dot_max )
|
||||||
|
{
|
||||||
|
dot_max = dot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* and the offset (from the average location) */
|
||||||
|
dot = sum_x2[0]*sum_x[0] + sum_x2[1]*sum_x[1] + sum_x2[2]*sum_x[2];
|
||||||
|
dot_min -= dot;
|
||||||
|
dot_max -= dot;
|
||||||
|
/* post multiply by the scaling factor */
|
||||||
|
dot_min *= vec_len2;
|
||||||
|
dot_max *= vec_len2;
|
||||||
|
/* OK, build the master colors */
|
||||||
|
for( i = 0; i < 3; ++i )
|
||||||
|
{
|
||||||
|
/* color 0 */
|
||||||
|
c0[i] = (int)(0.5f + sum_x[i] + dot_max * sum_x2[i]);
|
||||||
|
if( c0[i] < 0 )
|
||||||
|
{
|
||||||
|
c0[i] = 0;
|
||||||
|
} else if( c0[i] > 255 )
|
||||||
|
{
|
||||||
|
c0[i] = 255;
|
||||||
|
}
|
||||||
|
/* color 1 */
|
||||||
|
c1[i] = (int)(0.5f + sum_x[i] + dot_min * sum_x2[i]);
|
||||||
|
if( c1[i] < 0 )
|
||||||
|
{
|
||||||
|
c1[i] = 0;
|
||||||
|
} else if( c1[i] > 255 )
|
||||||
|
{
|
||||||
|
c1[i] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* down_sample (with rounding?) */
|
||||||
|
i = rgb_to_565( c0[0], c0[1], c0[2] );
|
||||||
|
j = rgb_to_565( c1[0], c1[1], c1[2] );
|
||||||
|
if( i > j )
|
||||||
|
{
|
||||||
|
*cmax = i;
|
||||||
|
*cmin = j;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
*cmax = j;
|
||||||
|
*cmin = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
compress_DDS_color_block
|
||||||
|
(
|
||||||
|
int channels,
|
||||||
|
const unsigned char *const uncompressed,
|
||||||
|
unsigned char compressed[8]
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* variables */
|
||||||
|
int i;
|
||||||
|
int next_bit;
|
||||||
|
int enc_c0, enc_c1;
|
||||||
|
int c0[4], c1[4];
|
||||||
|
float color_line[] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
float vec_len2 = 0.0f, dot_offset = 0.0f;
|
||||||
|
/* stupid order */
|
||||||
|
int swizzle4[] = { 0, 2, 3, 1 };
|
||||||
|
/* get the master colors */
|
||||||
|
LSE_master_colors_max_min( &enc_c0, &enc_c1, channels, uncompressed );
|
||||||
|
/* store the 565 color 0 and color 1 */
|
||||||
|
compressed[0] = (enc_c0 >> 0) & 255;
|
||||||
|
compressed[1] = (enc_c0 >> 8) & 255;
|
||||||
|
compressed[2] = (enc_c1 >> 0) & 255;
|
||||||
|
compressed[3] = (enc_c1 >> 8) & 255;
|
||||||
|
/* zero out the compressed data */
|
||||||
|
compressed[4] = 0;
|
||||||
|
compressed[5] = 0;
|
||||||
|
compressed[6] = 0;
|
||||||
|
compressed[7] = 0;
|
||||||
|
/* reconstitute the master color vectors */
|
||||||
|
rgb_888_from_565( enc_c0, &c0[0], &c0[1], &c0[2] );
|
||||||
|
rgb_888_from_565( enc_c1, &c1[0], &c1[1], &c1[2] );
|
||||||
|
/* the new vector */
|
||||||
|
vec_len2 = 0.0f;
|
||||||
|
for( i = 0; i < 3; ++i )
|
||||||
|
{
|
||||||
|
color_line[i] = (float)(c1[i] - c0[i]);
|
||||||
|
vec_len2 += color_line[i] * color_line[i];
|
||||||
|
}
|
||||||
|
if( vec_len2 > 0.0f )
|
||||||
|
{
|
||||||
|
vec_len2 = 1.0f / vec_len2;
|
||||||
|
}
|
||||||
|
/* pre-proform the scaling */
|
||||||
|
color_line[0] *= vec_len2;
|
||||||
|
color_line[1] *= vec_len2;
|
||||||
|
color_line[2] *= vec_len2;
|
||||||
|
/* compute the offset (constant) portion of the dot product */
|
||||||
|
dot_offset = color_line[0]*c0[0] + color_line[1]*c0[1] + color_line[2]*c0[2];
|
||||||
|
/* store the rest of the bits */
|
||||||
|
next_bit = 8*4;
|
||||||
|
for( i = 0; i < 16; ++i )
|
||||||
|
{
|
||||||
|
/* find the dot product of this color, to place it on the line
|
||||||
|
(should be [-1,1]) */
|
||||||
|
int next_value = 0;
|
||||||
|
float dot_product =
|
||||||
|
color_line[0] * uncompressed[i*channels+0] +
|
||||||
|
color_line[1] * uncompressed[i*channels+1] +
|
||||||
|
color_line[2] * uncompressed[i*channels+2] -
|
||||||
|
dot_offset;
|
||||||
|
/* map to [0,3] */
|
||||||
|
next_value = (int)( dot_product * 3.0f + 0.5f );
|
||||||
|
if( next_value > 3 )
|
||||||
|
{
|
||||||
|
next_value = 3;
|
||||||
|
} else if( next_value < 0 )
|
||||||
|
{
|
||||||
|
next_value = 0;
|
||||||
|
}
|
||||||
|
/* OK, store this value */
|
||||||
|
compressed[next_bit >> 3] |= swizzle4[ next_value ] << (next_bit & 7);
|
||||||
|
next_bit += 2;
|
||||||
|
}
|
||||||
|
/* done compressing to DXT1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
compress_DDS_alpha_block
|
||||||
|
(
|
||||||
|
const unsigned char *const uncompressed,
|
||||||
|
unsigned char compressed[8]
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* variables */
|
||||||
|
int i;
|
||||||
|
int next_bit;
|
||||||
|
int a0, a1;
|
||||||
|
float scale_me;
|
||||||
|
/* stupid order */
|
||||||
|
int swizzle8[] = { 1, 7, 6, 5, 4, 3, 2, 0 };
|
||||||
|
/* get the alpha limits (a0 > a1) */
|
||||||
|
a0 = a1 = uncompressed[3];
|
||||||
|
for( i = 4+3; i < 16*4; i += 4 )
|
||||||
|
{
|
||||||
|
if( uncompressed[i] > a0 )
|
||||||
|
{
|
||||||
|
a0 = uncompressed[i];
|
||||||
|
} else if( uncompressed[i] < a1 )
|
||||||
|
{
|
||||||
|
a1 = uncompressed[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* store those limits, and zero the rest of the compressed dataset */
|
||||||
|
compressed[0] = a0;
|
||||||
|
compressed[1] = a1;
|
||||||
|
/* zero out the compressed data */
|
||||||
|
compressed[2] = 0;
|
||||||
|
compressed[3] = 0;
|
||||||
|
compressed[4] = 0;
|
||||||
|
compressed[5] = 0;
|
||||||
|
compressed[6] = 0;
|
||||||
|
compressed[7] = 0;
|
||||||
|
/* store the all of the alpha values */
|
||||||
|
next_bit = 8*2;
|
||||||
|
scale_me = 7.9999f / (a0 - a1);
|
||||||
|
for( i = 3; i < 16*4; i += 4 )
|
||||||
|
{
|
||||||
|
/* convert this alpha value to a 3 bit number */
|
||||||
|
int svalue;
|
||||||
|
int value = (int)((uncompressed[i] - a1) * scale_me);
|
||||||
|
svalue = swizzle8[ value&7 ];
|
||||||
|
/* OK, store this value, start with the 1st byte */
|
||||||
|
compressed[next_bit >> 3] |= svalue << (next_bit & 7);
|
||||||
|
if( (next_bit & 7) > 5 )
|
||||||
|
{
|
||||||
|
/* spans 2 bytes, fill in the start of the 2nd byte */
|
||||||
|
compressed[1 + (next_bit >> 3)] |= svalue >> (8 - (next_bit & 7) );
|
||||||
|
}
|
||||||
|
next_bit += 3;
|
||||||
|
}
|
||||||
|
/* done compressing to DXT1 */
|
||||||
|
}
|
435
Source/Core/VideoCommon/Src/SOIL/image_helper.c
Normal file
435
Source/Core/VideoCommon/Src/SOIL/image_helper.c
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
/*
|
||||||
|
Jonathan Dummer
|
||||||
|
|
||||||
|
image helper functions
|
||||||
|
|
||||||
|
MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "image_helper.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
/* Upscaling the image uses simple bilinear interpolation */
|
||||||
|
int
|
||||||
|
up_scale_image
|
||||||
|
(
|
||||||
|
const unsigned char* const orig,
|
||||||
|
int width, int height, int channels,
|
||||||
|
unsigned char* resampled,
|
||||||
|
int resampled_width, int resampled_height
|
||||||
|
)
|
||||||
|
{
|
||||||
|
float dx, dy;
|
||||||
|
int x, y, c;
|
||||||
|
|
||||||
|
/* error(s) check */
|
||||||
|
if ( (width < 1) || (height < 1) ||
|
||||||
|
(resampled_width < 2) || (resampled_height < 2) ||
|
||||||
|
(channels < 1) ||
|
||||||
|
(NULL == orig) || (NULL == resampled) )
|
||||||
|
{
|
||||||
|
/* signify badness */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
for each given pixel in the new map, find the exact location
|
||||||
|
from the original map which would contribute to this guy
|
||||||
|
*/
|
||||||
|
dx = (width - 1.0f) / (resampled_width - 1.0f);
|
||||||
|
dy = (height - 1.0f) / (resampled_height - 1.0f);
|
||||||
|
for ( y = 0; y < resampled_height; ++y )
|
||||||
|
{
|
||||||
|
/* find the base y index and fractional offset from that */
|
||||||
|
float sampley = y * dy;
|
||||||
|
int inty = (int)sampley;
|
||||||
|
/* if( inty < 0 ) { inty = 0; } else */
|
||||||
|
if( inty > height - 2 ) { inty = height - 2; }
|
||||||
|
sampley -= inty;
|
||||||
|
for ( x = 0; x < resampled_width; ++x )
|
||||||
|
{
|
||||||
|
float samplex = x * dx;
|
||||||
|
int intx = (int)samplex;
|
||||||
|
int base_index;
|
||||||
|
/* find the base x index and fractional offset from that */
|
||||||
|
/* if( intx < 0 ) { intx = 0; } else */
|
||||||
|
if( intx > width - 2 ) { intx = width - 2; }
|
||||||
|
samplex -= intx;
|
||||||
|
/* base index into the original image */
|
||||||
|
base_index = (inty * width + intx) * channels;
|
||||||
|
for ( c = 0; c < channels; ++c )
|
||||||
|
{
|
||||||
|
/* do the sampling */
|
||||||
|
float value = 0.5f;
|
||||||
|
value += orig[base_index]
|
||||||
|
*(1.0f-samplex)*(1.0f-sampley);
|
||||||
|
value += orig[base_index+channels]
|
||||||
|
*(samplex)*(1.0f-sampley);
|
||||||
|
value += orig[base_index+width*channels]
|
||||||
|
*(1.0f-samplex)*(sampley);
|
||||||
|
value += orig[base_index+width*channels+channels]
|
||||||
|
*(samplex)*(sampley);
|
||||||
|
/* move to the next channel */
|
||||||
|
++base_index;
|
||||||
|
/* save the new value */
|
||||||
|
resampled[y*resampled_width*channels+x*channels+c] =
|
||||||
|
(unsigned char)(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* done */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mipmap_image
|
||||||
|
(
|
||||||
|
const unsigned char* const orig,
|
||||||
|
int width, int height, int channels,
|
||||||
|
unsigned char* resampled,
|
||||||
|
int block_size_x, int block_size_y
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int mip_width, mip_height;
|
||||||
|
int i, j, c;
|
||||||
|
|
||||||
|
/* error check */
|
||||||
|
if( (width < 1) || (height < 1) ||
|
||||||
|
(channels < 1) || (orig == NULL) ||
|
||||||
|
(resampled == NULL) ||
|
||||||
|
(block_size_x < 1) || (block_size_y < 1) )
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
mip_width = width / block_size_x;
|
||||||
|
mip_height = height / block_size_y;
|
||||||
|
if( mip_width < 1 )
|
||||||
|
{
|
||||||
|
mip_width = 1;
|
||||||
|
}
|
||||||
|
if( mip_height < 1 )
|
||||||
|
{
|
||||||
|
mip_height = 1;
|
||||||
|
}
|
||||||
|
for( j = 0; j < mip_height; ++j )
|
||||||
|
{
|
||||||
|
for( i = 0; i < mip_width; ++i )
|
||||||
|
{
|
||||||
|
for( c = 0; c < channels; ++c )
|
||||||
|
{
|
||||||
|
const int index = (j*block_size_y)*width*channels + (i*block_size_x)*channels + c;
|
||||||
|
int sum_value;
|
||||||
|
int u,v;
|
||||||
|
int u_block = block_size_x;
|
||||||
|
int v_block = block_size_y;
|
||||||
|
int block_area;
|
||||||
|
/* do a bit of checking so we don't over-run the boundaries
|
||||||
|
(necessary for non-square textures!) */
|
||||||
|
if( block_size_x * (i+1) > width )
|
||||||
|
{
|
||||||
|
u_block = width - i*block_size_y;
|
||||||
|
}
|
||||||
|
if( block_size_y * (j+1) > height )
|
||||||
|
{
|
||||||
|
v_block = height - j*block_size_y;
|
||||||
|
}
|
||||||
|
block_area = u_block*v_block;
|
||||||
|
/* for this pixel, see what the average
|
||||||
|
of all the values in the block are.
|
||||||
|
note: start the sum at the rounding value, not at 0 */
|
||||||
|
sum_value = block_area >> 1;
|
||||||
|
for( v = 0; v < v_block; ++v )
|
||||||
|
for( u = 0; u < u_block; ++u )
|
||||||
|
{
|
||||||
|
sum_value += orig[index + v*width*channels + u*channels];
|
||||||
|
}
|
||||||
|
resampled[j*mip_width*channels + i*channels + c] = sum_value / block_area;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
scale_image_RGB_to_NTSC_safe
|
||||||
|
(
|
||||||
|
unsigned char* orig,
|
||||||
|
int width, int height, int channels
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const float scale_lo = 16.0f - 0.499f;
|
||||||
|
const float scale_hi = 235.0f + 0.499f;
|
||||||
|
int i, j;
|
||||||
|
int nc = channels;
|
||||||
|
unsigned char scale_LUT[256];
|
||||||
|
/* error check */
|
||||||
|
if( (width < 1) || (height < 1) ||
|
||||||
|
(channels < 1) || (orig == NULL) )
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* set up the scaling Look Up Table */
|
||||||
|
for( i = 0; i < 256; ++i )
|
||||||
|
{
|
||||||
|
scale_LUT[i] = (unsigned char)((scale_hi - scale_lo) * i / 255.0f + scale_lo);
|
||||||
|
}
|
||||||
|
/* for channels = 2 or 4, ignore the alpha component */
|
||||||
|
nc -= 1 - (channels & 1);
|
||||||
|
/* OK, go through the image and scale any non-alpha components */
|
||||||
|
for( i = 0; i < width*height*channels; i += channels )
|
||||||
|
{
|
||||||
|
for( j = 0; j < nc; ++j )
|
||||||
|
{
|
||||||
|
orig[i+j] = scale_LUT[orig[i+j]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char clamp_byte( int x ) { return ( (x) < 0 ? (0) : ( (x) > 255 ? 255 : (x) ) ); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function takes the RGB components of the image
|
||||||
|
and converts them into YCoCg. 3 components will be
|
||||||
|
re-ordered to CoYCg (for optimum DXT1 compression),
|
||||||
|
while 4 components will be ordered CoCgAY (for DXT5
|
||||||
|
compression).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
convert_RGB_to_YCoCg
|
||||||
|
(
|
||||||
|
unsigned char* orig,
|
||||||
|
int width, int height, int channels
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* error check */
|
||||||
|
if( (width < 1) || (height < 1) ||
|
||||||
|
(channels < 3) || (channels > 4) ||
|
||||||
|
(orig == NULL) )
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* do the conversion */
|
||||||
|
if( channels == 3 )
|
||||||
|
{
|
||||||
|
for( i = 0; i < width*height*3; i += 3 )
|
||||||
|
{
|
||||||
|
int r = orig[i+0];
|
||||||
|
int g = (orig[i+1] + 1) >> 1;
|
||||||
|
int b = orig[i+2];
|
||||||
|
int tmp = (2 + r + b) >> 2;
|
||||||
|
/* Co */
|
||||||
|
orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) );
|
||||||
|
/* Y */
|
||||||
|
orig[i+1] = clamp_byte( g + tmp );
|
||||||
|
/* Cg */
|
||||||
|
orig[i+2] = clamp_byte( 128 + g - tmp );
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
for( i = 0; i < width*height*4; i += 4 )
|
||||||
|
{
|
||||||
|
int r = orig[i+0];
|
||||||
|
int g = (orig[i+1] + 1) >> 1;
|
||||||
|
int b = orig[i+2];
|
||||||
|
unsigned char a = orig[i+3];
|
||||||
|
int tmp = (2 + r + b) >> 2;
|
||||||
|
/* Co */
|
||||||
|
orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) );
|
||||||
|
/* Cg */
|
||||||
|
orig[i+1] = clamp_byte( 128 + g - tmp );
|
||||||
|
/* Alpha */
|
||||||
|
orig[i+2] = a;
|
||||||
|
/* Y */
|
||||||
|
orig[i+3] = clamp_byte( g + tmp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* done */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function takes the YCoCg components of the image
|
||||||
|
and converts them into RGB. See above.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
convert_YCoCg_to_RGB
|
||||||
|
(
|
||||||
|
unsigned char* orig,
|
||||||
|
int width, int height, int channels
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* error check */
|
||||||
|
if( (width < 1) || (height < 1) ||
|
||||||
|
(channels < 3) || (channels > 4) ||
|
||||||
|
(orig == NULL) )
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* do the conversion */
|
||||||
|
if( channels == 3 )
|
||||||
|
{
|
||||||
|
for( i = 0; i < width*height*3; i += 3 )
|
||||||
|
{
|
||||||
|
int co = orig[i+0] - 128;
|
||||||
|
int y = orig[i+1];
|
||||||
|
int cg = orig[i+2] - 128;
|
||||||
|
/* R */
|
||||||
|
orig[i+0] = clamp_byte( y + co - cg );
|
||||||
|
/* G */
|
||||||
|
orig[i+1] = clamp_byte( y + cg );
|
||||||
|
/* B */
|
||||||
|
orig[i+2] = clamp_byte( y - co - cg );
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
for( i = 0; i < width*height*4; i += 4 )
|
||||||
|
{
|
||||||
|
int co = orig[i+0] - 128;
|
||||||
|
int cg = orig[i+1] - 128;
|
||||||
|
unsigned char a = orig[i+2];
|
||||||
|
int y = orig[i+3];
|
||||||
|
/* R */
|
||||||
|
orig[i+0] = clamp_byte( y + co - cg );
|
||||||
|
/* G */
|
||||||
|
orig[i+1] = clamp_byte( y + cg );
|
||||||
|
/* B */
|
||||||
|
orig[i+2] = clamp_byte( y - co - cg );
|
||||||
|
/* A */
|
||||||
|
orig[i+3] = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* done */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
find_max_RGBE
|
||||||
|
(
|
||||||
|
unsigned char *image,
|
||||||
|
int width, int height
|
||||||
|
)
|
||||||
|
{
|
||||||
|
float max_val = 0.0f;
|
||||||
|
unsigned char *img = image;
|
||||||
|
int i, j;
|
||||||
|
for( i = width * height; i > 0; --i )
|
||||||
|
{
|
||||||
|
/* float scale = powf( 2.0f, img[3] - 128.0f ) / 255.0f; */
|
||||||
|
float scale = ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );
|
||||||
|
for( j = 0; j < 3; ++j )
|
||||||
|
{
|
||||||
|
if( img[j] * scale > max_val )
|
||||||
|
{
|
||||||
|
max_val = img[j] * scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* next pixel */
|
||||||
|
img += 4;
|
||||||
|
}
|
||||||
|
return max_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
RGBE_to_RGBdivA
|
||||||
|
(
|
||||||
|
unsigned char *image,
|
||||||
|
int width, int height,
|
||||||
|
int rescale_to_max
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* local variables */
|
||||||
|
int i, iv;
|
||||||
|
unsigned char *img = image;
|
||||||
|
float scale = 1.0f;
|
||||||
|
/* error check */
|
||||||
|
if( (!image) || (width < 1) || (height < 1) )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* convert (note: no negative numbers, but 0.0 is possible) */
|
||||||
|
if( rescale_to_max )
|
||||||
|
{
|
||||||
|
scale = 255.0f / find_max_RGBE( image, width, height );
|
||||||
|
}
|
||||||
|
for( i = width * height; i > 0; --i )
|
||||||
|
{
|
||||||
|
/* decode this pixel, and find the max */
|
||||||
|
float r,g,b,e, m;
|
||||||
|
/* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */
|
||||||
|
e = scale * ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );
|
||||||
|
r = e * img[0];
|
||||||
|
g = e * img[1];
|
||||||
|
b = e * img[2];
|
||||||
|
m = (r > g) ? r : g;
|
||||||
|
m = (b > m) ? b : m;
|
||||||
|
/* and encode it into RGBdivA */
|
||||||
|
iv = (m != 0.0f) ? (int)(255.0f / m) : 1.0f;
|
||||||
|
iv = (iv < 1) ? 1 : iv;
|
||||||
|
img[3] = (iv > 255) ? 255 : iv;
|
||||||
|
iv = (int)(img[3] * r + 0.5f);
|
||||||
|
img[0] = (iv > 255) ? 255 : iv;
|
||||||
|
iv = (int)(img[3] * g + 0.5f);
|
||||||
|
img[1] = (iv > 255) ? 255 : iv;
|
||||||
|
iv = (int)(img[3] * b + 0.5f);
|
||||||
|
img[2] = (iv > 255) ? 255 : iv;
|
||||||
|
/* and on to the next pixel */
|
||||||
|
img += 4;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
RGBE_to_RGBdivA2
|
||||||
|
(
|
||||||
|
unsigned char *image,
|
||||||
|
int width, int height,
|
||||||
|
int rescale_to_max
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* local variables */
|
||||||
|
int i, iv;
|
||||||
|
unsigned char *img = image;
|
||||||
|
float scale = 1.0f;
|
||||||
|
/* error check */
|
||||||
|
if( (!image) || (width < 1) || (height < 1) )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* convert (note: no negative numbers, but 0.0 is possible) */
|
||||||
|
if( rescale_to_max )
|
||||||
|
{
|
||||||
|
scale = 255.0f * 255.0f / find_max_RGBE( image, width, height );
|
||||||
|
}
|
||||||
|
for( i = width * height; i > 0; --i )
|
||||||
|
{
|
||||||
|
/* decode this pixel, and find the max */
|
||||||
|
float r,g,b,e, m;
|
||||||
|
/* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */
|
||||||
|
e = scale * ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );
|
||||||
|
r = e * img[0];
|
||||||
|
g = e * img[1];
|
||||||
|
b = e * img[2];
|
||||||
|
m = (r > g) ? r : g;
|
||||||
|
m = (b > m) ? b : m;
|
||||||
|
/* and encode it into RGBdivA */
|
||||||
|
iv = (m != 0.0f) ? (int)sqrtf( 255.0f * 255.0f / m ) : 1.0f;
|
||||||
|
iv = (iv < 1) ? 1 : iv;
|
||||||
|
img[3] = (iv > 255) ? 255 : iv;
|
||||||
|
iv = (int)(img[3] * img[3] * r / 255.0f + 0.5f);
|
||||||
|
img[0] = (iv > 255) ? 255 : iv;
|
||||||
|
iv = (int)(img[3] * img[3] * g / 255.0f + 0.5f);
|
||||||
|
img[1] = (iv > 255) ? 255 : iv;
|
||||||
|
iv = (int)(img[3] * img[3] * b / 255.0f + 0.5f);
|
||||||
|
img[2] = (iv > 255) ? 255 : iv;
|
||||||
|
/* and on to the next pixel */
|
||||||
|
img += 4;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
3682
Source/Core/VideoCommon/Src/SOIL/stb_image_aug.c
Normal file
3682
Source/Core/VideoCommon/Src/SOIL/stb_image_aug.c
Normal file
File diff suppressed because it is too large
Load Diff
354
Source/Core/VideoCommon/Src/SOIL/stb_image_aug.h
Normal file
354
Source/Core/VideoCommon/Src/SOIL/stb_image_aug.h
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/* 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
|
Loading…
x
Reference in New Issue
Block a user