23 Dec 2007
This commit is contained in:
parent
1d7fe10f27
commit
2761b9d8ec
|
@ -2,10 +2,10 @@
|
|||
|
||||
#define IDI_ICON1 101
|
||||
|
||||
#define VER_FILEVERSION 0,45
|
||||
#define VER_FILEVERSION_STR "0.45"
|
||||
#define VER_PRODUCTVERSION 0,45
|
||||
#define VER_PRODUCTVERSION_STR "0.45"
|
||||
#define VER_FILEVERSION 0,3
|
||||
#define VER_FILEVERSION_STR "0.3"
|
||||
#define VER_PRODUCTVERSION 0,3
|
||||
#define VER_PRODUCTVERSION_STR "0.3"
|
||||
|
||||
#define VER_FILEFLAGSMASK VS_FF_PRERELEASE | VS_FF_PATCHED
|
||||
#define VER_FILEFLAGS VS_FF_PRERELEASE
|
||||
|
|
|
@ -98,7 +98,8 @@ extern uint image_ptr; // common moveable pointer
|
|||
|
||||
// image lib utilites
|
||||
extern uint *d_currentpal;
|
||||
bool Image_Copy8bitRGBA(const byte *in, byte *out, int pixels);
|
||||
bool Image_Copy8bitRGBA(const byte *in, byte *out, int pixels); // convert indexed image to RGBA
|
||||
rgbdata_t *Image_CopyRGBA8bit( rgbdata_t *pix, int numcolors ); // convert RGBA image to indexed
|
||||
void Image_RoundDimensions(int *scaled_width, int *scaled_height);
|
||||
byte *Image_Resample(uint *in, int inwidth, int inheight, int outwidth, int outheight, int in_type);
|
||||
bool FS_AddMipmapToPack( const byte *in, int width, int height );
|
||||
|
|
|
@ -0,0 +1,571 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2007 ©
|
||||
// image_save.c - saving textures
|
||||
//=======================================================================
|
||||
|
||||
#include "launch.h"
|
||||
#include "image.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
#define Sum(c) ((c)->r + (c)->g + (c)->b)
|
||||
|
||||
bool dds_write_header( vfile_t *f, rgbdata_t *pix, uint cubemap_flags )
|
||||
{
|
||||
uint dwFourCC, dwFlags1 = 0, dwFlags2 = 0, dwCaps1 = 0;
|
||||
uint dwLinearSize, dwBlockSize, dwCaps2 = 0;
|
||||
uint dwIdent = DDSHEADER, dwSize = 124, dwSize2 = 32;
|
||||
|
||||
if(!pix || pix->buffer )
|
||||
return false;
|
||||
|
||||
// setup flags
|
||||
dwFlags1 |= DDS_LINEARSIZE | DDS_MIPMAPCOUNT | DDS_WIDTH | DDS_HEIGHT | DDS_CAPS | DDS_PIXELFORMAT;
|
||||
dwFlags2 |= DDS_FOURCC;
|
||||
if( pix->numLayers > 1) dwFlags1 |= DDS_DEPTH;
|
||||
|
||||
switch( pix->type )
|
||||
{
|
||||
case PF_DXT1:
|
||||
dwFourCC = TYPE_DXT1;
|
||||
break;
|
||||
case PF_DXT2:
|
||||
dwFourCC = TYPE_DXT2;
|
||||
break;
|
||||
case PF_DXT3:
|
||||
dwFourCC = TYPE_DXT3;
|
||||
break;
|
||||
case PF_DXT4:
|
||||
dwFourCC = TYPE_DXT4;
|
||||
break;
|
||||
case PF_DXT5:
|
||||
dwFourCC = TYPE_DXT5;
|
||||
break;
|
||||
case PF_ATI1N:
|
||||
dwFourCC = TYPE_ATI1;
|
||||
break;
|
||||
case PF_ATI2N:
|
||||
dwFourCC = TYPE_ATI2;
|
||||
break;
|
||||
case PF_RXGB:
|
||||
dwFourCC = TYPE_RXGB;
|
||||
break;
|
||||
default:
|
||||
MsgDev( D_ERROR, "dds_write_header: unsupported type %s\n", PFDesc[pix->type].name );
|
||||
return false;
|
||||
}
|
||||
|
||||
VFS_Write(f, &dwIdent, sizeof(uint));
|
||||
VFS_Write(f, &dwSize, sizeof(uint));
|
||||
VFS_Write(f, &dwFlags1, sizeof(uint));
|
||||
VFS_Write(f, &pix->height, sizeof(uint));
|
||||
VFS_Write(f, &pix->width, sizeof(uint));
|
||||
|
||||
dwBlockSize = PFDesc[pix->type].block;
|
||||
dwLinearSize = (((pix->width + 3)/4) * ((pix->height + 3)/4)) * dwBlockSize * pix->numLayers;
|
||||
VFS_Write(f, &dwLinearSize, sizeof(uint)); // TODO: use dds_get_linear_size
|
||||
|
||||
if (pix->numLayers > 1)
|
||||
{
|
||||
VFS_Write(f, &pix->numLayers, sizeof(uint));
|
||||
dwCaps2 |= DDS_VOLUME;
|
||||
}
|
||||
else VFS_Write(f, 0, sizeof(uint));
|
||||
|
||||
VFS_Write(f, &pix->numMips, sizeof(uint));
|
||||
VFS_Write(f, 0, sizeof(uint));
|
||||
VFS_Write(f, pix->color, sizeof(vec3_t));
|
||||
VFS_Write(f, &pix->bump_scale, sizeof(float));
|
||||
VFS_Write(f, 0, sizeof(uint) * 6 ); // reserved fields
|
||||
|
||||
VFS_Write(f, &dwSize2, sizeof(uint));
|
||||
VFS_Write(f, &dwFlags2, sizeof(uint));
|
||||
VFS_Write(f, &dwFourCC, sizeof(uint));
|
||||
VFS_Write(f, 0, sizeof(uint) * 5 ); // bit masks
|
||||
|
||||
dwCaps1 |= DDS_TEXTURE;
|
||||
if( pix->numMips > 1 ) dwCaps1 |= DDS_MIPMAP | DDS_COMPLEX;
|
||||
if( cubemap_flags )
|
||||
{
|
||||
dwCaps1 |= DDS_COMPLEX;
|
||||
dwCaps2 |= cubemap_flags;
|
||||
}
|
||||
|
||||
VFS_Write(f, &dwCaps1, sizeof(uint));
|
||||
VFS_Write(f, &dwCaps2, sizeof(uint));
|
||||
VFS_Write(f, 0, sizeof(uint) * 3 ); // other caps and TextureStage
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShortToColor565(word Pixel, color16 *Colour)
|
||||
{
|
||||
Colour->r = (Pixel & 0xF800) >> 11;
|
||||
Colour->g = (Pixel & 0x07E0) >> 5;
|
||||
Colour->b = (Pixel & 0x001F);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void ShortToColor888(word Pixel, color24 *Colour)
|
||||
{
|
||||
Colour->r = ((Pixel & 0xF800) >> 11) << 3;
|
||||
Colour->g = ((Pixel & 0x07E0) >> 5) << 2;
|
||||
Colour->b = ((Pixel & 0x001F)) << 3;
|
||||
return;
|
||||
}
|
||||
|
||||
word Color565ToShort(color16 *Colour)
|
||||
{
|
||||
return (Colour->r << 11) | (Colour->g << 5) | (Colour->b);
|
||||
}
|
||||
|
||||
word Color888ToShort(color24 *Colour)
|
||||
{
|
||||
return ((Colour->r >> 3) << 11) | ((Colour->g >> 2) << 5) | (Colour->b >> 3);
|
||||
}
|
||||
|
||||
void ChooseEndpoints(word *Block, word *ex0, word *ex1)
|
||||
{
|
||||
uint i;
|
||||
color24 Colours[16];
|
||||
int Lowest=0, Highest=0;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
ShortToColor888(Block[i], &Colours[i]);
|
||||
if(Sum(&Colours[i]) < Sum(&Colours[Lowest])) Lowest = i;
|
||||
if(Sum(&Colours[i]) > Sum(&Colours[Highest])) Highest = i;
|
||||
}
|
||||
*ex0 = Block[Highest];
|
||||
*ex1 = Block[Lowest];
|
||||
}
|
||||
|
||||
void ChooseAlphaEndpoints( byte *Block, byte *a0, byte *a1)
|
||||
{
|
||||
uint i, Lowest = 0xFF, Highest = 0;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if( Block[i] < Lowest ) Lowest = Block[i];
|
||||
if( Block[i] > Highest) Highest = Block[i];
|
||||
}
|
||||
*a0 = Lowest;
|
||||
*a1 = Highest;
|
||||
}
|
||||
|
||||
bool Get3DcBlock( byte *Block, byte *Data, rgbdata_t *pix, uint XPos, uint YPos, int channel )
|
||||
{
|
||||
uint x, y, i = 0, Offset = 2*(YPos * pix->width + XPos) + channel;
|
||||
|
||||
for (y = 0; y < 4; y++)
|
||||
{
|
||||
for (x = 0; x < 4; x++)
|
||||
{
|
||||
if(x < pix->width && y < pix->height)
|
||||
Block[i++] = Data[Offset + 2*x];
|
||||
else Block[i++] = Data[Offset];
|
||||
}
|
||||
Offset += 2 * pix->width;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
word *dds_compress_565( rgbdata_t *pix )
|
||||
{
|
||||
word *Data;
|
||||
uint i, j;
|
||||
|
||||
Data = (word*)Mem_Alloc( Sys.imagepool, pix->width * pix->height * 2 * pix->numLayers );
|
||||
|
||||
switch ( pix->type )
|
||||
{
|
||||
case PF_RGB_24:
|
||||
for (i = 0, j = 0; i < pix->size; i += 3, j++)
|
||||
{
|
||||
Data[j] = (pix->buffer[i+0] >> 3) << 11;
|
||||
Data[j] |= (pix->buffer[i+1] >> 2) << 5;
|
||||
Data[j] |= pix->buffer[i+2] >> 3;
|
||||
}
|
||||
break;
|
||||
case PF_RGBA_32:
|
||||
for (i = 0, j = 0; i < pix->size; i += 4, j++)
|
||||
{
|
||||
Data[j] = (pix->buffer[i+0] >> 3) << 11;
|
||||
Data[j] |= (pix->buffer[i+1] >> 2) << 5;
|
||||
Data[j] |= pix->buffer[i+2] >> 3;
|
||||
}
|
||||
break;
|
||||
case PF_RGB_24_FLIP:
|
||||
for (i = 0, j = 0; i < pix->size; i += 3, j++)
|
||||
{
|
||||
Data[j] = (pix->buffer[i+2] >> 3) << 11;
|
||||
Data[j] |= (pix->buffer[i+1] >> 2) << 5;
|
||||
Data[j] |= pix->buffer[i+0] >> 3;
|
||||
}
|
||||
break;
|
||||
case PF_LUMINANCE:
|
||||
for (i = 0, j = 0; i < pix->size; i++, j++)
|
||||
{
|
||||
Data[j] = (pix->buffer[i] >> 3) << 11;
|
||||
Data[j] |= (pix->buffer[i] >> 2) << 5;
|
||||
Data[j] |= pix->buffer[i] >> 3;
|
||||
}
|
||||
break;
|
||||
case PF_LUMINANCE_ALPHA:
|
||||
for (i = 0, j = 0; i < pix->size; i += 2, j++)
|
||||
{
|
||||
Data[j] = (pix->buffer[i] >> 3) << 11;
|
||||
Data[j] |= (pix->buffer[i] >> 2) << 5;
|
||||
Data[j] |= pix->buffer[i] >> 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return Data;
|
||||
}
|
||||
|
||||
byte *dds_compress_88( rgbdata_t *pix )
|
||||
{
|
||||
byte *Data;
|
||||
uint i, j;
|
||||
|
||||
Data = (byte*)Mem_Alloc(Sys.imagepool, pix->width * pix->height * 2 * pix->numLayers );
|
||||
|
||||
switch( pix->type )
|
||||
{
|
||||
case PF_RGB_24:
|
||||
for (i = 0, j = 0; i < pix->size; i += 3, j += 2)
|
||||
{
|
||||
Data[j+0] = pix->buffer[i+1];
|
||||
Data[j+1] = pix->buffer[i+0];
|
||||
}
|
||||
break;
|
||||
case PF_RGBA_32:
|
||||
for (i = 0, j = 0; i < pix->size; i += 4, j += 2)
|
||||
{
|
||||
Data[j+0] = pix->buffer[i+1];
|
||||
Data[j+1] = pix->buffer[i+0];
|
||||
}
|
||||
break;
|
||||
case PF_RGB_24_FLIP:
|
||||
for (i = 0, j = 0; i < pix->size; i += 3, j += 2)
|
||||
{
|
||||
Data[j ] = pix->buffer[i+1];
|
||||
Data[j+1] = pix->buffer[i+2];
|
||||
}
|
||||
break;
|
||||
case PF_LUMINANCE:
|
||||
case PF_LUMINANCE_ALPHA:
|
||||
for (i = 0, j = 0; i < pix->size; i++, j += 2)
|
||||
{
|
||||
Data[j] = Data[j+1] = 0; //??? Luminance is no normal map format...
|
||||
}
|
||||
break;
|
||||
}
|
||||
return Data;
|
||||
}
|
||||
|
||||
void dds_compress_RXGB(rgbdata_t *pix, word **xgb, byte **r )
|
||||
{
|
||||
uint i, j;
|
||||
word *Data;
|
||||
byte *Alpha;
|
||||
|
||||
*xgb = NULL;
|
||||
*r = NULL;
|
||||
|
||||
*xgb = (word*)Mem_Alloc( Sys.imagepool, pix->width * pix->height * 2 * pix->numLayers );
|
||||
*r = Mem_Alloc( Sys.imagepool, pix->width * pix->height * pix->numLayers);
|
||||
|
||||
//alias pointers to be able to use copy'n'pasted code :)
|
||||
Data = *xgb;
|
||||
Alpha = *r;
|
||||
|
||||
switch( pix->type )
|
||||
{
|
||||
case PF_RGB_24:
|
||||
for (i = 0, j = 0; i < pix->size; i += 3, j++)
|
||||
{
|
||||
Alpha[j] = pix->buffer[i+0];
|
||||
Data[j] = (pix->buffer[i+1] >> 2) << 5;
|
||||
Data[j] |= pix->buffer[i+2] >> 3;
|
||||
}
|
||||
break;
|
||||
case PF_RGBA_32:
|
||||
for (i = 0, j = 0; i < pix->size; i += 4, j++)
|
||||
{
|
||||
Alpha[j] = pix->buffer[i+0];
|
||||
Data[j] = (pix->buffer[i+1] >> 2) << 5;
|
||||
Data[j] |= pix->buffer[i+2] >> 3;
|
||||
}
|
||||
break;
|
||||
case PF_RGB_24_FLIP:
|
||||
for (i = 0, j = 0; i < pix->size; i += 3, j++)
|
||||
{
|
||||
Alpha[j] = pix->buffer[i+2];
|
||||
Data[j] = (pix->buffer[i+1] >> 2) << 5;
|
||||
Data[j] |= pix->buffer[i+0] >> 3;
|
||||
}
|
||||
break;
|
||||
case PF_LUMINANCE:
|
||||
for (i = 0, j = 0; i < pix->size; i++, j++)
|
||||
{
|
||||
Alpha[j] = pix->buffer[i];
|
||||
Data[j] = (pix->buffer[i] >> 2) << 5;
|
||||
Data[j] |= pix->buffer[i] >> 3;
|
||||
}
|
||||
break;
|
||||
case PF_LUMINANCE_ALPHA:
|
||||
for (i = 0, j = 0; i < pix->size; i += 2, j++)
|
||||
{
|
||||
Alpha[j] = pix->buffer[i];
|
||||
Data[j] = (pix->buffer[i] >> 2) << 5;
|
||||
Data[j] |= pix->buffer[i] >> 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint dds_compress_dxt( vfile_t *f, int saveformat, rgbdata_t *pix )
|
||||
{
|
||||
word *Data, Block[16], ex0, ex1, *Runner16, t0, t1;
|
||||
byte *Alpha, AlphaBlock[16], AlphaBitMask[6], a0, a1;
|
||||
uint x, y, z, i, BitMask;
|
||||
byte *Data3Dc, *Runner8;
|
||||
bool HasAlpha;
|
||||
uint Count = 0;
|
||||
|
||||
if(!pix || pix->buffer )
|
||||
return 0;
|
||||
|
||||
if( saveformat == PF_ATI2N)
|
||||
{
|
||||
Data3Dc = dds_compress_88( pix );
|
||||
if(!Data3Dc) return 0;
|
||||
Runner8 = Data3Dc;
|
||||
|
||||
for (z = 0; z < pix->numLayers; z++)
|
||||
{
|
||||
for (y = 0; y < pix->height; y += 4)
|
||||
{
|
||||
for (x = 0; x < pix->width; x += 4)
|
||||
{
|
||||
Get3DcBlock( AlphaBlock, Runner8, pix, x, y, 0);
|
||||
ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
|
||||
GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL);
|
||||
VFS_Write(f, &a0, sizeof(byte));
|
||||
VFS_Write(f, &a1, sizeof(byte));
|
||||
VFS_Write(f, &AlphaBitMask, sizeof(byte) * 6 );
|
||||
Get3DcBlock(AlphaBlock, Runner8, pix, x, y, 1);
|
||||
ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
|
||||
GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL);
|
||||
VFS_Write(f, &a0, sizeof(byte));
|
||||
VFS_Write(f, &a1, sizeof(byte));
|
||||
VFS_Write(f, &AlphaBitMask, sizeof(byte) * 6 );
|
||||
Count += 16;
|
||||
}
|
||||
}
|
||||
Runner8 += pix->width * pix->height * 2;
|
||||
|
||||
}
|
||||
Mem_Free( Data3Dc );
|
||||
}
|
||||
else if( saveformat == IL_ATI1N )
|
||||
{
|
||||
rgbdata_t *lum = NULL;
|
||||
if (PFDesc[pix->type].bpp != 1)
|
||||
{
|
||||
//FIXME: lum = Image_Convert( pix, PF_LUMINANCE );
|
||||
if(!lum) return 0;
|
||||
}
|
||||
else lum = pix;
|
||||
|
||||
Runner8 = lum->buffer;
|
||||
for (z = 0; z < pix->numLayers; z++)
|
||||
{
|
||||
for (y = 0; y < pix->height; y += 4)
|
||||
{
|
||||
for (x = 0; x < pix->width; x += 4)
|
||||
{
|
||||
GetAlphaBlock(AlphaBlock, Runner8, pix, x, y);
|
||||
ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
|
||||
GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL);
|
||||
VFS_Write(f, &a0, sizeof(byte));
|
||||
VFS_Write(f, &a1, sizeof(byte));
|
||||
VFS_Write(f, &AlphaBitMask, sizeof(byte) * 6 );
|
||||
Count += 8;
|
||||
}
|
||||
}
|
||||
Runner8 += pix->width * pix->height;
|
||||
}
|
||||
if(lum != pix) FS_FreeImage( lum );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( saveformat != PF_RXGB )
|
||||
{
|
||||
Data = dds_compress_565( pix );
|
||||
if(!Data) return 0;
|
||||
|
||||
Alpha = ilGetAlpha(IL_UNSIGNED_BYTE);
|
||||
if(!Alpha)
|
||||
{
|
||||
Mem_Free(Data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dds_compress_RXGB(pix, &Data, &Alpha);
|
||||
if (!Data || !Alpha)
|
||||
{
|
||||
if( Data ) Mem_Free( Data );
|
||||
if( Alpha) Mem_Free( Alpha);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Runner8 = Alpha;
|
||||
Runner16 = Data;
|
||||
|
||||
switch( saveformat )
|
||||
{
|
||||
case IL_DXT1:
|
||||
|
||||
for (z = 0; z < pix->numLayers; z++) {
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 4) {
|
||||
GetAlphaBlock(AlphaBlock, Runner8, Image, x, y);
|
||||
HasAlpha = IL_FALSE;
|
||||
for (i = 0 ; i < 16; i++) {
|
||||
if (AlphaBlock[i] < 128) {
|
||||
HasAlpha = IL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GetBlock(Block, Runner16, Image, x, y);
|
||||
ChooseEndpoints(Block, &ex0, &ex1);
|
||||
CorrectEndDXT1(&ex0, &ex1, HasAlpha);
|
||||
SaveLittleUShort(ex0);
|
||||
SaveLittleUShort(ex1);
|
||||
if (HasAlpha)
|
||||
BitMask = GenBitMask(ex0, ex1, 3, Block, AlphaBlock, NULL);
|
||||
else
|
||||
BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
|
||||
SaveLittleUInt(BitMask);
|
||||
Count += 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Runner16 += Image->Width * Image->Height;
|
||||
|
||||
Runner8 += Image->Width * Image->Height;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
/*case IL_DXT2:
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 4) {
|
||||
GetAlphaBlock(AlphaBlock, Alpha, Image, x, y);
|
||||
for (i = 0; i < 16; i += 2) {
|
||||
iputc((ILubyte)(((AlphaBlock[i] >> 4) << 4) | (AlphaBlock[i+1] >> 4)));
|
||||
}
|
||||
|
||||
GetBlock(Block, Data, Image, x, y);
|
||||
PreMult(Block, AlphaBlock);
|
||||
ChooseEndpoints(Block, &ex0, &ex1);
|
||||
SaveLittleUShort(ex0);
|
||||
SaveLittleUShort(ex1);
|
||||
BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
|
||||
SaveLittleUInt(BitMask);
|
||||
}
|
||||
}
|
||||
break;*/
|
||||
|
||||
case IL_DXT3:
|
||||
|
||||
for (z = 0; z < Image->Depth; z++) {
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 4) {
|
||||
GetAlphaBlock(AlphaBlock, Runner8, Image, x, y);
|
||||
for (i = 0; i < 16; i += 2) {
|
||||
iputc((ILubyte)(((AlphaBlock[i+1] >> 4) << 4) | (AlphaBlock[i] >> 4)));
|
||||
}
|
||||
|
||||
GetBlock(Block, Runner16, Image, x, y);
|
||||
ChooseEndpoints(Block, &t0, &t1);
|
||||
ex0 = IL_MAX(t0, t1);
|
||||
ex1 = IL_MIN(t0, t1);
|
||||
CorrectEndDXT1(&ex0, &ex1, 0);
|
||||
SaveLittleUShort(ex0);
|
||||
SaveLittleUShort(ex1);
|
||||
BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
|
||||
SaveLittleUInt(BitMask);
|
||||
Count += 16;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Runner16 += Image->Width * Image->Height;
|
||||
|
||||
Runner8 += Image->Width * Image->Height;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case IL_RXGB:
|
||||
case IL_DXT5:
|
||||
|
||||
for (z = 0; z < Image->Depth; z++) {
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 4) {
|
||||
GetAlphaBlock(AlphaBlock, Runner8, Image, x, y);
|
||||
ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
|
||||
GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL/*AlphaOut*/);
|
||||
/*Rms2 = RMSAlpha(AlphaBlock, AlphaOut);
|
||||
GenAlphaBitMask(a0, a1, 8, AlphaBlock, AlphaBitMask, AlphaOut);
|
||||
Rms1 = RMSAlpha(AlphaBlock, AlphaOut);
|
||||
if (Rms2 <= Rms1) { // Yeah, we have to regenerate...
|
||||
GenAlphaBitMask(a0, a1, 6, AlphaBlock, AlphaBitMask, AlphaOut);
|
||||
Rms2 = a1; // Just reuse Rms2 as a temporary variable...
|
||||
a1 = a0;
|
||||
a0 = Rms2;
|
||||
}*/
|
||||
iputc(a0);
|
||||
iputc(a1);
|
||||
iwrite(AlphaBitMask, 1, 6);
|
||||
|
||||
GetBlock(Block, Runner16, Image, x, y);
|
||||
ChooseEndpoints(Block, &t0, &t1);
|
||||
ex0 = IL_MAX(t0, t1);
|
||||
ex1 = IL_MIN(t0, t1);
|
||||
CorrectEndDXT1(&ex0, &ex1, 0);
|
||||
SaveLittleUShort(ex0);
|
||||
SaveLittleUShort(ex1);
|
||||
BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
|
||||
SaveLittleUInt(BitMask);
|
||||
Count += 16;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Runner16 += Image->Width * Image->Height;
|
||||
|
||||
Runner8 += Image->Width * Image->Height;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ifree(Data);
|
||||
ifree(Alpha);
|
||||
} //else no 3dc
|
||||
|
||||
return Count;
|
||||
}
|
|
@ -1266,9 +1266,17 @@ bool LoadDDS( char *name, char *buffer, int filesize )
|
|||
header.dwMipMapCount = BuffLittleLong(fin); fin += 4;
|
||||
header.dwAlphaBitDepth = BuffLittleLong(fin); fin += 4;
|
||||
|
||||
// skip unused stuff
|
||||
for (i = 0; i < 10; i++)
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
header.fReflectivity[i] = BuffLittleFloat(fin);
|
||||
fin += 4;
|
||||
}
|
||||
|
||||
header.fBumpScale = BuffLittleFloat(fin); fin += 4;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
// skip unused stuff
|
||||
header.dwReserved1[i] = BuffLittleLong(fin);
|
||||
fin += 4;
|
||||
}
|
||||
|
@ -2072,12 +2080,102 @@ void FS_FreeImage( rgbdata_t *pack )
|
|||
image_size = 0;
|
||||
}
|
||||
|
||||
bool SaveBMP( const char *filename, byte *data, int width, int height, bool alpha, int imagetype, byte *palette )
|
||||
{
|
||||
file_t *pfile = NULL;
|
||||
BITMAPFILEHEADER bmfh;
|
||||
BITMAPINFOHEADER bmih;
|
||||
RGBQUAD rgrgbPalette[256];
|
||||
dword cbBmpBits;
|
||||
byte* pbBmpBits;
|
||||
byte *pb, *pbPal = NULL;
|
||||
dword cbPalBytes;
|
||||
dword biTrueWidth;
|
||||
int i, rc = 0;
|
||||
|
||||
// bogus parameter check
|
||||
if(!palette || !data ) return false;
|
||||
|
||||
pfile = FS_Open( filename, "wb");
|
||||
if(!pfile) return false;
|
||||
|
||||
switch( imagetype )
|
||||
{
|
||||
case PF_INDEXED_24:
|
||||
case PF_INDEXED_32:
|
||||
break;
|
||||
default:
|
||||
MsgWarn("SaveBMP: unsupported image type %s\n", PFDesc[imagetype].name );
|
||||
return false;
|
||||
}
|
||||
|
||||
biTrueWidth = ((width + 3) & ~3);
|
||||
cbBmpBits = biTrueWidth * height;
|
||||
cbPalBytes = 256 * sizeof( RGBQUAD );
|
||||
|
||||
// Bogus file header check
|
||||
bmfh.bfType = MAKEWORD( 'B', 'M' );
|
||||
bmfh.bfSize = sizeof(bmfh) + sizeof(bmih) + cbBmpBits + cbPalBytes;
|
||||
bmfh.bfReserved1 = 0;
|
||||
bmfh.bfReserved2 = 0;
|
||||
bmfh.bfOffBits = sizeof(bmfh) + sizeof(bmih) + cbPalBytes;
|
||||
|
||||
// write header
|
||||
FS_Write( pfile, &bmfh, sizeof(bmfh));
|
||||
|
||||
// size of structure
|
||||
bmih.biSize = sizeof bmih;
|
||||
bmih.biWidth = biTrueWidth;
|
||||
bmih.biHeight = height;
|
||||
bmih.biPlanes = 1;
|
||||
bmih.biBitCount = 8;
|
||||
bmih.biCompression = BI_RGB;
|
||||
bmih.biSizeImage = 0;
|
||||
bmih.biXPelsPerMeter = 0;
|
||||
bmih.biYPelsPerMeter = 0;
|
||||
bmih.biClrUsed = 256;
|
||||
bmih.biClrImportant = 0;
|
||||
|
||||
// Write info header
|
||||
FS_Write( pfile, &bmih, sizeof(bmih));
|
||||
pb = palette;
|
||||
|
||||
// copy over used entries
|
||||
for (i = 0; i < (int)bmih.biClrUsed; i++)
|
||||
{
|
||||
rgrgbPalette[i].rgbRed = *pb++;
|
||||
rgrgbPalette[i].rgbGreen = *pb++;
|
||||
rgrgbPalette[i].rgbBlue = *pb++;
|
||||
rgrgbPalette[i].rgbReserved = 0;
|
||||
}
|
||||
|
||||
// write palette( bmih.biClrUsed entries )
|
||||
cbPalBytes = bmih.biClrUsed * sizeof( RGBQUAD );
|
||||
FS_Write( pfile, rgrgbPalette, cbPalBytes );
|
||||
pbBmpBits = Mem_Alloc( Sys.imagepool, cbBmpBits );
|
||||
|
||||
pb = data;
|
||||
pb += (height - 1) * width;
|
||||
|
||||
for(i = 0; i < bmih.biHeight; i++)
|
||||
{
|
||||
memmove(&pbBmpBits[biTrueWidth * i], pb, width);
|
||||
pb -= width;
|
||||
}
|
||||
|
||||
// write bitmap bits (remainder of file)
|
||||
FS_Write( pfile, pbBmpBits, cbBmpBits );
|
||||
Mem_Free( pbBmpBits );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SaveTGA
|
||||
=============
|
||||
*/
|
||||
bool SaveTGA( const char *filename, byte *data, int width, int height, bool alpha, int imagetype )
|
||||
bool SaveTGA( const char *filename, byte *data, int width, int height, bool alpha, int imagetype, byte *palette )
|
||||
{
|
||||
int y, outsize, pixel_size;
|
||||
const byte *bufend, *in;
|
||||
|
@ -2113,7 +2211,7 @@ bool SaveTGA( const char *filename, byte *data, int width, int height, bool alph
|
|||
case PF_RGB_24: pixel_size = 3; break;
|
||||
case PF_RGBA_32: pixel_size = 4; break;
|
||||
default:
|
||||
MsgWarn("SaveTGA: unsupported image type %s\n", PFDesc[image_type].name );
|
||||
MsgWarn("SaveTGA: unsupported image type %s\n", PFDesc[imagetype].name );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2157,12 +2255,13 @@ typedef struct saveformat_s
|
|||
{
|
||||
char *formatstring;
|
||||
char *ext;
|
||||
bool (*savefunc)(char *filename, byte *data, int width, int height, bool alpha, int imagetype );
|
||||
bool (*savefunc)(char *filename, byte *data, int width, int height, bool alpha, int imagetype, byte *pal );
|
||||
} saveformat_t;
|
||||
|
||||
saveformat_t save_formats[] =
|
||||
{
|
||||
{"%s%s.%s", "tga", SaveTGA},
|
||||
{"%s%s.%s", "bmp", SaveBMP},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -2173,26 +2272,43 @@ FS_SaveImage
|
|||
writes image as tga RGBA format
|
||||
================
|
||||
*/
|
||||
void FS_SaveImage(const char *filename, rgbdata_t *pix )
|
||||
void FS_SaveImage( const char *filename, rgbdata_t *pix )
|
||||
{
|
||||
bool has_alpha = false;
|
||||
int i, numsides = 1;
|
||||
saveformat_t *format;
|
||||
const char *ext = FS_FileExtension( filename );
|
||||
char path[128], savename[128];
|
||||
bool anyformat = !stricmp(ext, "") ? true : false;
|
||||
int i, filesize = 0;
|
||||
byte *data;
|
||||
char savename[256];
|
||||
bool has_alpha = false;
|
||||
|
||||
if(!pix || !pix->buffer) return;
|
||||
|
||||
data = pix->buffer;
|
||||
FS_StripExtension( (char *)filename );
|
||||
if(pix->flags & IMAGE_HAS_ALPHA) has_alpha = true;
|
||||
if(pix->flags & IMAGE_CUBEMAP) numsides = 6;
|
||||
data = pix->buffer;
|
||||
|
||||
for(i = 0; i < numsides; i++)
|
||||
com_strncpy( savename, filename, sizeof(savename) - 1);
|
||||
FS_StripExtension( savename ); // remove extension if needed
|
||||
|
||||
// developer warning
|
||||
if(!anyformat) MsgDev(D_NOTE, "Note: %s will be saving only with ext .%s\n", savename, ext );
|
||||
|
||||
// now try all the formats in the selected list
|
||||
for (format = save_formats; format->formatstring; format++)
|
||||
{
|
||||
if( anyformat || !com_stricmp( ext, format->ext ))
|
||||
{
|
||||
com_sprintf( path, format->formatstring, savename, "", format->ext );
|
||||
if( format->savefunc( path, data, pix->width, pix->height, has_alpha, pix->type, pix->palette ))
|
||||
return; // saved
|
||||
}
|
||||
}
|
||||
|
||||
/*for(i = 0; i < numsides; i++)
|
||||
{
|
||||
if(numsides > 1) com_sprintf(savename, "%s%s.tga", filename, suf[i] );
|
||||
else com_sprintf(savename, "%s.tga", filename );
|
||||
|
||||
SaveTGA( savename, data, pix->width, pix->height, has_alpha, pix->type );
|
||||
SaveTGA( savename, data, pix->width, pix->height, has_alpha, pix->type, pix->palette );
|
||||
data += pix->width * pix->height * PFDesc[pix->type].bpp;
|
||||
}
|
||||
}*/
|
||||
}
|
|
@ -0,0 +1,445 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2007 ©
|
||||
// pallib.c - create palette images
|
||||
//=======================================================================
|
||||
|
||||
#include "launch.h"
|
||||
#include "image.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
#define PAL_MAXCOLORS 256
|
||||
#define RED 0
|
||||
#define GREEN 1
|
||||
#define BLUE 2
|
||||
|
||||
typedef struct pixel_box_s
|
||||
{
|
||||
int r0; // min value, exclusive
|
||||
int r1; // max value, inclusive
|
||||
int g0;
|
||||
int g1;
|
||||
int b0;
|
||||
int b1;
|
||||
int vol;
|
||||
} pixel_box_t;
|
||||
|
||||
// Histogram is in elements 1..HISTSIZE along each axis,
|
||||
// element 0 is for base or marginal value
|
||||
// NB: these must start out 0!
|
||||
float gm2[33][33][33];
|
||||
int wt[33][33][33];
|
||||
int mr[33][33][33];
|
||||
int mg[33][33][33];
|
||||
int mb[33][33][33];
|
||||
uint size; // image size
|
||||
int K; // colour look-up table size
|
||||
word *Qadd;
|
||||
int WindW, WindH, WindD;
|
||||
int i;
|
||||
byte *buffer;
|
||||
static int Width, Height, Depth, Comp;
|
||||
|
||||
uint n2(int s)
|
||||
{
|
||||
int i;
|
||||
int res = 1;
|
||||
|
||||
for (i = 0; i < s; i++)
|
||||
res = res*2;
|
||||
return res;
|
||||
}
|
||||
|
||||
// build 3-D color histogram of counts, r/g/b, c^2
|
||||
void Hist3d( byte *Ir, byte *Ig, byte *Ib, int *vwt, int *vmr, int *vmg, int *vmb, float *m2 )
|
||||
{
|
||||
int ind, r, g, b;
|
||||
int inr, ing, inb, table[2560];
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < 256; i++) table[i] = i * i;
|
||||
Qadd = (word*)Mem_Alloc( Sys.imagepool, sizeof(word) * size );
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
r = Ir[i]; g = Ig[i]; b = Ib[i];
|
||||
inr = (r>>3) + 1;
|
||||
ing = (g>>3) + 1;
|
||||
inb = (b>>3) + 1;
|
||||
Qadd[i] = ind = (inr<<10) + (inr<<6) + inr + (ing<<5) + ing + inb;
|
||||
|
||||
//[inr][ing][inb]
|
||||
vwt[ind]++;
|
||||
vmr[ind] += r;
|
||||
vmg[ind] += g;
|
||||
vmb[ind] += b;
|
||||
m2[ind] += (float)(table[r] + table[g] + table[b]);
|
||||
}
|
||||
}
|
||||
|
||||
// At conclusion of the histogram step, we can interpret
|
||||
// wt[r][g][b] = sum over voxel of P(c)
|
||||
// mr[r][g][b] = sum over voxel of r*P(c), similarly for mg, mb
|
||||
// m2[r][g][b] = sum over voxel of c^2*P(c)
|
||||
// Actually each of these should be divided by 'size' to give the usual
|
||||
// interpretation of P() as ranging from 0 to 1, but we needn't do that here.
|
||||
// We now convert histogram into moments so that we can rapidly calculate
|
||||
// the sums of the above quantities over any desired Box.
|
||||
|
||||
// compute cumulative moments
|
||||
void M3d( int *vwt, int *vmr, int *vmg, int *vmb, float *m2 )
|
||||
{
|
||||
word ind1, ind2;
|
||||
byte i, r, g, b;
|
||||
int line, line_r, line_g, line_b, area[33], area_r[33], area_g[33], area_b[33];
|
||||
float line2, area2[33];
|
||||
|
||||
for (r = 1; r <= 32; r++)
|
||||
{
|
||||
for (i = 0; i <= 32; i++)
|
||||
{
|
||||
area2[i] = 0.0f;
|
||||
area[i] = area_r[i] = area_g[i] = area_b[i] = 0;
|
||||
}
|
||||
for (g = 1; g <= 32; g++)
|
||||
{
|
||||
line2 = 0.0f;
|
||||
line = line_r = line_g = line_b = 0;
|
||||
for (b = 1; b <= 32; b++)
|
||||
{
|
||||
ind1 = (r<<10) + (r<<6) + r + (g<<5) + g + b; // [r][g][b]
|
||||
line += vwt[ind1];
|
||||
line_r += vmr[ind1];
|
||||
line_g += vmg[ind1];
|
||||
line_b += vmb[ind1];
|
||||
line2 += m2[ind1];
|
||||
area[b] += line;
|
||||
area_r[b] += line_r;
|
||||
area_g[b] += line_g;
|
||||
area_b[b] += line_b;
|
||||
area2[b] += line2;
|
||||
ind2 = ind1 - 1089; // [r-1][g][b]
|
||||
vwt[ind1] = vwt[ind2] + area[b];
|
||||
vmr[ind1] = vmr[ind2] + area_r[b];
|
||||
vmg[ind1] = vmg[ind2] + area_g[b];
|
||||
vmb[ind1] = vmb[ind2] + area_b[b];
|
||||
m2[ind1] = m2[ind2] + area2[b];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compute sum over a Box of any given statistic
|
||||
int Vol(pixel_box_t *cube, int mmt[33][33][33])
|
||||
{
|
||||
return( mmt[cube->r1][cube->g1][cube->b1] -mmt[cube->r1][cube->g1][cube->b0] -mmt[cube->r1][cube->g0][cube->b1] +mmt[cube->r1][cube->g0][cube->b0] -mmt[cube->r0][cube->g1][cube->b1] +mmt[cube->r0][cube->g1][cube->b0] +mmt[cube->r0][cube->g0][cube->b1] -mmt[cube->r0][cube->g0][cube->b0] );
|
||||
}
|
||||
|
||||
// the next two routines allow a slightly more efficient calculation
|
||||
// of Vol() for a proposed subBox of a given Box. The sum of Top()
|
||||
// and Bottom() is the Vol() of a subBox split in the given direction
|
||||
// and with the specified new upper bound.
|
||||
// compute part of Vol(cube, mmt) that doesn't depend on r1, g1, or b1
|
||||
// (depending on dir)
|
||||
|
||||
int Bottom(pixel_box_t *cube, byte dir, int mmt[33][33][33])
|
||||
{
|
||||
switch(dir)
|
||||
{
|
||||
case RED: return( -mmt[cube->r0][cube->g1][cube->b1] +mmt[cube->r0][cube->g1][cube->b0] +mmt[cube->r0][cube->g0][cube->b1] -mmt[cube->r0][cube->g0][cube->b0] );
|
||||
case GREEN: return( -mmt[cube->r1][cube->g0][cube->b1] +mmt[cube->r1][cube->g0][cube->b0] +mmt[cube->r0][cube->g0][cube->b1] -mmt[cube->r0][cube->g0][cube->b0] );
|
||||
case BLUE: return( -mmt[cube->r1][cube->g1][cube->b0] +mmt[cube->r1][cube->g0][cube->b0] +mmt[cube->r0][cube->g1][cube->b0] -mmt[cube->r0][cube->g0][cube->b0] );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// compute remainder of Vol(cube, mmt), substituting pos for
|
||||
// r1, g1, or b1 (depending on dir)
|
||||
|
||||
int Top(pixel_box_t *cube, byte dir, int pos, int mmt[33][33][33])
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case RED: return( mmt[pos][cube->g1][cube->b1] -mmt[pos][cube->g1][cube->b0] -mmt[pos][cube->g0][cube->b1] +mmt[pos][cube->g0][cube->b0] );
|
||||
case GREEN: return( mmt[cube->r1][pos][cube->b1] -mmt[cube->r1][pos][cube->b0] -mmt[cube->r0][pos][cube->b1] +mmt[cube->r0][pos][cube->b0] );
|
||||
case BLUE: return( mmt[cube->r1][cube->g1][pos] -mmt[cube->r1][cube->g0][pos] -mmt[cube->r0][cube->g1][pos] +mmt[cube->r0][cube->g0][pos] );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// compute the weighted variance of a Box
|
||||
// NB: as with the raw statistics, this is really the variance * size
|
||||
float Var(pixel_box_t *cube)
|
||||
{
|
||||
float dr, dg, db, xx;
|
||||
|
||||
dr = (float)Vol(cube, mr);
|
||||
dg = (float)Vol(cube, mg);
|
||||
db = (float)Vol(cube, mb);
|
||||
xx = gm2[cube->r1][cube->g1][cube->b1] -gm2[cube->r1][cube->g1][cube->b0] -gm2[cube->r1][cube->g0][cube->b1] +gm2[cube->r1][cube->g0][cube->b0] -gm2[cube->r0][cube->g1][cube->b1] +gm2[cube->r0][cube->g1][cube->b0] +gm2[cube->r0][cube->g0][cube->b1] -gm2[cube->r0][cube->g0][cube->b0];
|
||||
|
||||
return xx - (dr*dr+dg*dg+db*db) / (float)Vol(cube, wt);
|
||||
}
|
||||
|
||||
// We want to minimize the sum of the variances of two subBoxes.
|
||||
// The sum(c^2) terms can be ignored since their sum over both subBoxes
|
||||
// is the same (the sum for the whole Box) no matter where we split.
|
||||
// The remaining terms have a minus sign in the variance formula,
|
||||
// so we drop the minus sign and MAXIMIZE the sum of the two terms.
|
||||
|
||||
float Maximize( pixel_box_t *cube, byte dir, int first, int last, int *cut, int whole_r, int whole_g, int whole_b, int whole_w )
|
||||
{
|
||||
int half_r, half_g, half_b, half_w;
|
||||
int base_r, base_g, base_b, base_w;
|
||||
int i;
|
||||
float temp, max = 0.0f;
|
||||
|
||||
base_r = Bottom(cube, dir, mr);
|
||||
base_g = Bottom(cube, dir, mg);
|
||||
base_b = Bottom(cube, dir, mb);
|
||||
base_w = Bottom(cube, dir, wt);
|
||||
*cut = -1;
|
||||
|
||||
for (i = first; i < last; ++i)
|
||||
{
|
||||
half_r = base_r + Top(cube, dir, i, mr);
|
||||
half_g = base_g + Top(cube, dir, i, mg);
|
||||
half_b = base_b + Top(cube, dir, i, mb);
|
||||
half_w = base_w + Top(cube, dir, i, wt);
|
||||
|
||||
// now half_x is sum over lower half of pixel_box_t, if split at i
|
||||
if (half_w == 0) continue; // never split into an empty pixel_box_t
|
||||
else temp = ((float)half_r*half_r + (float)half_g * half_g + (float)half_b*half_b) / half_w;
|
||||
|
||||
half_r = whole_r - half_r;
|
||||
half_g = whole_g - half_g;
|
||||
half_b = whole_b - half_b;
|
||||
half_w = whole_w - half_w;
|
||||
if (half_w == 0) continue; // never split into an empty pixel_box_t
|
||||
else temp += ((float)half_r*half_r + (float)half_g * half_g + (float)half_b*half_b) / half_w;
|
||||
|
||||
if (temp > max)
|
||||
{
|
||||
max = temp;
|
||||
*cut = i;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
int Cut( pixel_box_t *set1, pixel_box_t *set2 )
|
||||
{
|
||||
byte dir;
|
||||
int cutr, cutg, cutb;
|
||||
float maxr, maxg, maxb;
|
||||
int whole_r, whole_g, whole_b, whole_w;
|
||||
|
||||
whole_r = Vol(set1, mr);
|
||||
whole_g = Vol(set1, mg);
|
||||
whole_b = Vol(set1, mb);
|
||||
whole_w = Vol(set1, wt);
|
||||
|
||||
maxr = Maximize( set1, RED, set1->r0+1, set1->r1, &cutr, whole_r, whole_g, whole_b, whole_w );
|
||||
maxg = Maximize( set1, GREEN, set1->g0+1, set1->g1, &cutg, whole_r, whole_g, whole_b, whole_w );
|
||||
maxb = Maximize( set1, BLUE, set1->b0+1, set1->b1, &cutb, whole_r, whole_g, whole_b, whole_w );
|
||||
|
||||
if((maxr >= maxg) && (maxr >= maxb))
|
||||
{
|
||||
dir = RED;
|
||||
if(cutr < 0)return 0; // can't split the pixel_box_t
|
||||
}
|
||||
else if ((maxg >= maxr) && (maxg >= maxb))
|
||||
dir = GREEN;
|
||||
else dir = BLUE;
|
||||
|
||||
set2->r1 = set1->r1;
|
||||
set2->g1 = set1->g1;
|
||||
set2->b1 = set1->b1;
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case RED:
|
||||
set2->r0 = set1->r1 = cutr;
|
||||
set2->g0 = set1->g0;
|
||||
set2->b0 = set1->b0;
|
||||
break;
|
||||
case GREEN:
|
||||
set2->g0 = set1->g1 = cutg;
|
||||
set2->r0 = set1->r0;
|
||||
set2->b0 = set1->b0;
|
||||
break;
|
||||
case BLUE:
|
||||
set2->b0 = set1->b1 = cutb;
|
||||
set2->r0 = set1->r0;
|
||||
set2->g0 = set1->g0;
|
||||
break;
|
||||
}
|
||||
|
||||
set1->vol = (set1->r1-set1->r0) * (set1->g1-set1->g0) * (set1->b1-set1->b0);
|
||||
set2->vol = (set2->r1-set2->r0) * (set2->g1-set2->g0) * (set2->b1-set2->b0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void Mark( pixel_box_t *cube, int label, byte *tag )
|
||||
{
|
||||
int r, g, b;
|
||||
|
||||
for (r = cube->r0 + 1; r <= cube->r1; r++)
|
||||
{
|
||||
for (g = cube->g0 + 1; g <= cube->g1; g++)
|
||||
{
|
||||
for (b = cube->b0 + 1; b <= cube->b1; b++)
|
||||
{
|
||||
tag[(r<<10) + (r<<6) + r + (g<<5) + g + b] = label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rgbdata_t *Image_CopyRGBA8bit( rgbdata_t *pix, int numcolors )
|
||||
{
|
||||
pixel_box_t cube[PAL_MAXCOLORS];
|
||||
byte lut_r[PAL_MAXCOLORS];
|
||||
byte lut_g[PAL_MAXCOLORS];
|
||||
byte lut_b[PAL_MAXCOLORS];
|
||||
byte *tag = NULL;
|
||||
int next = 0;
|
||||
int weight;
|
||||
uint k;
|
||||
float vv[PAL_MAXCOLORS], temp;
|
||||
byte *NewData = NULL, *Palette = NULL;
|
||||
byte *Ir = NULL, *Ig = NULL, *Ib = NULL;
|
||||
rgbdata_t *newpix = NULL;
|
||||
int num_alloced_colors;
|
||||
|
||||
if(!pix) return NULL;
|
||||
|
||||
switch( pix->type )
|
||||
{
|
||||
case PF_RGBA_32: break;
|
||||
default:
|
||||
MsgDev(D_ERROR, "Image_ConvertTo8bit: unsupported pixelformat %s\n", PFDesc[pix->type].name );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
num_alloced_colors = bound( 2, numcolors, 256 );
|
||||
buffer = pix->buffer;
|
||||
WindW = Width = pix->width;
|
||||
WindH = Height = pix->height;
|
||||
WindD = Depth = pix->numLayers;
|
||||
Comp = PFDesc[pix->type].bpp;
|
||||
Qadd = NULL;
|
||||
|
||||
NewData = (byte *)Mem_Alloc( Sys.imagepool, Width * Height * Depth );
|
||||
Palette = (byte *)Mem_Alloc( Sys.imagepool, 3 * num_alloced_colors ); // 768 bytes
|
||||
|
||||
Ir = Mem_Alloc( Sys.imagepool, Width * Height * Depth);
|
||||
Ig = Mem_Alloc( Sys.imagepool, Width * Height * Depth);
|
||||
Ib = Mem_Alloc( Sys.imagepool, Width * Height * Depth);
|
||||
size = Width * Height * Depth;
|
||||
|
||||
for (k = 0; k < size; k++)
|
||||
{
|
||||
Ir[k] = pix->buffer[k*3+2];
|
||||
Ig[k] = pix->buffer[k*3+1];
|
||||
Ib[k] = pix->buffer[k*3+0];
|
||||
}
|
||||
|
||||
// set new colors number
|
||||
K = numcolors;
|
||||
|
||||
// begin Wu's color quantization algorithm
|
||||
// may have "leftovers" from a previous run.
|
||||
memset(gm2, 0, 33 * 33 * 33 * sizeof(float));
|
||||
memset(wt, 0, 33 * 33 * 33 * sizeof(int));
|
||||
memset(mr, 0, 33 * 33 * 33 * sizeof(int));
|
||||
memset(mg, 0, 33 * 33 * 33 * sizeof(int));
|
||||
memset(mb, 0, 33 * 33 * 33 * sizeof(int));
|
||||
|
||||
// build 3d color histogramm
|
||||
Hist3d(Ir, Ig, Ib, (int*)wt, (int*)mr, (int*)mg, (int*)mb, (float*)gm2);
|
||||
M3d((int*)wt, (int*)mr, (int*)mg, (int*)mb, (float*)gm2);
|
||||
|
||||
cube[0].r0 = cube[0].g0 = cube[0].b0 = 0;
|
||||
cube[0].r1 = cube[0].g1 = cube[0].b1 = 32;
|
||||
|
||||
for (i = 1; i < K; i++)
|
||||
{
|
||||
if(Cut(&cube[next], &cube[i]))
|
||||
{
|
||||
// volume test ensures we won't try to cut one-cell box
|
||||
vv[next] = (cube[next].vol > 1) ? Var(&cube[next]) : 0.0f;
|
||||
vv[i] = (cube[i].vol>1) ? Var(&cube[i]) : 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
vv[next] = 0.0; // don't try to split this Box again
|
||||
i--; // didn't create Box i
|
||||
}
|
||||
next = 0;
|
||||
temp = vv[0];
|
||||
for (k = 1; (int)k <= i; ++k)
|
||||
{
|
||||
if (vv[k] > temp)
|
||||
temp = vv[k];
|
||||
next = k;
|
||||
}
|
||||
|
||||
if (temp <= 0.0)
|
||||
{
|
||||
// only got K boxes
|
||||
K = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tag = (byte*)Mem_Alloc( Sys.imagepool, 33 * 33 * 33 * sizeof(byte));
|
||||
|
||||
for (k = 0; (int)k < K; k++)
|
||||
{
|
||||
Mark(&cube[k], k, tag);
|
||||
weight = Vol(&cube[k], wt);
|
||||
if (weight)
|
||||
{
|
||||
lut_r[k] = (byte)(Vol(&cube[k], mr) / weight);
|
||||
lut_g[k] = (byte)(Vol(&cube[k], mg) / weight);
|
||||
lut_b[k] = (byte)(Vol(&cube[k], mb) / weight);
|
||||
}
|
||||
else
|
||||
{
|
||||
// bogus box
|
||||
lut_r[k] = lut_g[k] = lut_b[k] = 0;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < (int)size; i++) NewData[i] = tag[Qadd[i]];
|
||||
|
||||
Mem_Free( tag );
|
||||
Mem_Free( Qadd);
|
||||
|
||||
// fill palette
|
||||
for (k = 0; k < numcolors; k++)
|
||||
{
|
||||
Palette[k * 3] = lut_b[k];
|
||||
Palette[k * 3 + 1] = lut_g[k];
|
||||
Palette[k * 3 + 2] = lut_r[k];
|
||||
}
|
||||
|
||||
Mem_Free( Ig );
|
||||
Mem_Free( Ib );
|
||||
Mem_Free( Ir );
|
||||
|
||||
newpix = (rgbdata_t *)Mem_Alloc( Sys.imagepool, sizeof(rgbdata_t));
|
||||
newpix->width = pix->width;
|
||||
newpix->height = pix->height;
|
||||
newpix->numLayers = pix->numLayers;
|
||||
newpix->numMips = pix->numMips;
|
||||
newpix->type = PF_INDEXED_24; // FIXME: do alpha-channel
|
||||
newpix->flags = pix->flags;
|
||||
newpix->palette = Palette;
|
||||
newpix->buffer = NewData;
|
||||
newpix->size = pix->width * pix->height * pix->numLayers;
|
||||
//FS_FreeImage( pix ); // free old image
|
||||
|
||||
return newpix;
|
||||
}
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
#define IDI_ICON1 101
|
||||
|
||||
#define VER_FILEVERSION 0,45
|
||||
#define VER_FILEVERSION_STR "0.45"
|
||||
#define VER_PRODUCTVERSION 0,45
|
||||
#define VER_PRODUCTVERSION_STR "0.45"
|
||||
#define VER_FILEVERSION 0,48
|
||||
#define VER_FILEVERSION_STR "0.48"
|
||||
#define VER_PRODUCTVERSION 0,48
|
||||
#define VER_PRODUCTVERSION_STR "0.48"
|
||||
|
||||
#define VER_FILEFLAGSMASK VS_FF_PRERELEASE | VS_FF_PATCHED
|
||||
#define VER_FILEFLAGS VS_FF_PRERELEASE
|
||||
|
|
|
@ -148,6 +148,10 @@ SOURCE=.\common\memlib.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\common\pallib.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\common\parselib.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
#define IDI_ICON1 101
|
||||
|
||||
#define VER_FILEVERSION 0,45
|
||||
#define VER_FILEVERSION_STR "0.45"
|
||||
#define VER_PRODUCTVERSION 0,45
|
||||
#define VER_PRODUCTVERSION_STR "0.45"
|
||||
#define VER_FILEVERSION 0,29
|
||||
#define VER_FILEVERSION_STR "0.29"
|
||||
#define VER_PRODUCTVERSION 0,29
|
||||
#define VER_PRODUCTVERSION_STR "0.29"
|
||||
|
||||
#define VER_FILEFLAGSMASK VS_FF_PRERELEASE | VS_FF_PATCHED
|
||||
#define VER_FILEFLAGS VS_FF_PRERELEASE
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
#define IDI_ICON1 101
|
||||
|
||||
#define VER_FILEVERSION 0,45
|
||||
#define VER_FILEVERSION_STR "0.45"
|
||||
#define VER_PRODUCTVERSION 0,45
|
||||
#define VER_PRODUCTVERSION_STR "0.45"
|
||||
#define VER_FILEVERSION 0,48
|
||||
#define VER_FILEVERSION_STR "0.48"
|
||||
#define VER_PRODUCTVERSION 0,48
|
||||
#define VER_PRODUCTVERSION_STR "0.48"
|
||||
|
||||
#define VER_FILEFLAGSMASK VS_FF_PRERELEASE | VS_FF_PATCHED
|
||||
#define VER_FILEFLAGS VS_FF_PRERELEASE
|
||||
|
|
|
@ -1699,17 +1699,19 @@ typedef struct tga_s
|
|||
#define DDS_PITCH 0x00000008L
|
||||
#define DDS_COMPLEX 0x00000008L
|
||||
#define DDS_CUBEMAP 0x00000200L
|
||||
#define DDS_TEXTURE 0x00001000L
|
||||
#define DDS_MIPMAPCOUNT 0x00020000L
|
||||
#define DDS_LINEARSIZE 0x00080000L
|
||||
#define DDS_VOLUME 0x00200000L
|
||||
#define DDS_MIPMAP 0x00400000L
|
||||
#define DDS_DEPTH 0x00800000L
|
||||
|
||||
#define DDS_CUBEMAP_POSITIVEX 0x00000400L
|
||||
#define DDS_CUBEMAP_NEGATIVEX 0x00000800L
|
||||
#define DDS_CUBEMAP_POSITIVEY 0x00001000L
|
||||
#define DDS_CUBEMAP_NEGATIVEY 0x00002000L
|
||||
#define DDS_CUBEMAP_POSITIVEZ 0x00004000L
|
||||
#define DDS_CUBEMAP_NEGATIVEZ 0x00008000L
|
||||
#define DDS_MIPMAPCOUNT 0x00020000L
|
||||
#define DDS_LINEARSIZE 0x00080000L
|
||||
#define DDS_VOLUME 0x00200000L
|
||||
#define DDS_MIPMAP 0x00400000L
|
||||
#define DDS_DEPTH 0x00800000L
|
||||
|
||||
typedef struct dds_pf_s
|
||||
{
|
||||
|
@ -1743,7 +1745,9 @@ typedef struct
|
|||
uint dwDepth; // depth if a volume texture
|
||||
uint dwMipMapCount; // number of mip-map levels requested
|
||||
uint dwAlphaBitDepth; // depth of alpha buffer requested
|
||||
uint dwReserved1[10]; // reserved for future expansions
|
||||
float fReflectivity[3]; // average reflectivity value
|
||||
float fBumpScale; // bumpmapping scale factor
|
||||
uint dwReserved1[6]; // reserved for future expansions
|
||||
dds_pixf_t dsPixelFormat;
|
||||
dds_caps_t dsCaps;
|
||||
uint dwTextureStage;
|
||||
|
@ -1893,6 +1897,8 @@ typedef struct rgbdata_s
|
|||
uint flags; // misc image flags
|
||||
byte *palette; // palette if present
|
||||
byte *buffer; // image buffer
|
||||
vec3_t color; // radiocity reflectivity
|
||||
float bump_scale; // internal bumpscale
|
||||
uint size; // for bounds checking
|
||||
} rgbdata_t;
|
||||
|
||||
|
|
Reference in New Issue