mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-22 20:21:20 +00:00
- added stripped down versions of GZDoom's texture classes
We need something more manageable to deal with the textures - and the hightile code in particular needs a better backend to read the images.
This commit is contained in:
parent
bedfc262c4
commit
1a5e64329f
25 changed files with 6137 additions and 6 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -2,11 +2,6 @@
|
|||
obj/
|
||||
|
||||
eduke32
|
||||
mapster32
|
||||
voidsw
|
||||
voidsw-editor
|
||||
kenbuild
|
||||
kenbuild-editor
|
||||
apps/
|
||||
*.exe
|
||||
/*.dll
|
||||
|
@ -25,7 +20,6 @@ apps/
|
|||
*.log
|
||||
*.cache
|
||||
*.cfg
|
||||
textures
|
||||
texturecache
|
||||
*.index
|
||||
|
||||
|
|
|
@ -684,6 +684,8 @@ file( GLOB HEADER_FILES
|
|||
#sw/src/*.h Shadow Warrior does not work yet.
|
||||
thirdparty/include/*.h
|
||||
thirdparty/include/*.hpp
|
||||
common/textures/*.h
|
||||
common/textures/formats/*.h
|
||||
)
|
||||
|
||||
|
||||
|
@ -967,6 +969,20 @@ set (PCH_SOURCES
|
|||
common/utility/file_zip.cpp
|
||||
common/utility/resourcefile.cpp
|
||||
common/utility/matrix.cpp
|
||||
common/utility/m_png.cpp
|
||||
common/utility/memarena.cpp
|
||||
|
||||
common/textures/bitmap.cpp
|
||||
common/textures/texture.cpp
|
||||
common/textures/image.cpp
|
||||
common/textures/imagetexture.cpp
|
||||
common/textures/formats/buildtexture.cpp
|
||||
common/textures/formats/ddstexture.cpp
|
||||
common/textures/formats/jpegtexture.cpp
|
||||
common/textures/formats/pcxtexture.cpp
|
||||
common/textures/formats/pngtexture.cpp
|
||||
common/textures/formats/tgatexture.cpp
|
||||
|
||||
)
|
||||
|
||||
if( MSVC )
|
||||
|
@ -1023,6 +1039,7 @@ include_directories(
|
|||
common
|
||||
common/utility
|
||||
common/console
|
||||
common/textures
|
||||
platform
|
||||
|
||||
${CMAKE_BINARY_DIR}/libraries/gdtoa
|
||||
|
@ -1123,6 +1140,8 @@ install(TARGETS demolition
|
|||
COMPONENT "Game executable")
|
||||
|
||||
source_group("Utility" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/utility/.+")
|
||||
source_group("Code\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/.+")
|
||||
source_group("Code\\Textures\\Formats" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/formats/.+")
|
||||
source_group("Utility\\Audiolib" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/audiolib/.+")
|
||||
source_group("Utility\\Audiolib Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/audiolib/include/.+")
|
||||
source_group("Utility\\Audiolib Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/audiolib/src/.+")
|
||||
|
|
142
source/common/textures/bitmap.cpp
Normal file
142
source/common/textures/bitmap.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
** bitmap.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "bitmap.h"
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// multi-format pixel copy with colormap application
|
||||
// requires the previously defined conversion classes to work
|
||||
//
|
||||
//===========================================================================
|
||||
template<class TSrc, class TDest, class TBlend>
|
||||
void iCopyColors(uint8_t *pout, const uint8_t *pin, int count, int step,
|
||||
uint8_t tr, uint8_t tg, uint8_t tb)
|
||||
{
|
||||
int i;
|
||||
int a;
|
||||
|
||||
for(i=0;i<count;i++)
|
||||
{
|
||||
a = TSrc::A(pin, tr, tg, tb);
|
||||
if (TBlend::ProcessAlpha0() || a)
|
||||
{
|
||||
TBlend::OpC(pout[TDest::RED], TSrc::R(pin), a);
|
||||
TBlend::OpC(pout[TDest::GREEN], TSrc::G(pin), a);
|
||||
TBlend::OpC(pout[TDest::BLUE], TSrc::B(pin), a);
|
||||
TBlend::OpA(pout[TDest::ALPHA], a);
|
||||
}
|
||||
pout+=4;
|
||||
pin+=step;
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*CopyFunc)(uint8_t *pout, const uint8_t *pin, int count, int step, uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
static const CopyFunc copyfuncs[]=
|
||||
{
|
||||
iCopyColors<cRGB, cBGRA, bCopy>,
|
||||
iCopyColors<cRGBT, cBGRA, bCopy>,
|
||||
iCopyColors<cRGBA, cBGRA, bCopy>,
|
||||
iCopyColors<cIA, cBGRA, bCopy>,
|
||||
iCopyColors<cCMYK, cBGRA, bCopy>,
|
||||
iCopyColors<cYCbCr, cBGRA, bCopy>,
|
||||
iCopyColors<cBGR, cBGRA, bCopy>,
|
||||
iCopyColors<cBGRA, cBGRA, bCopy>,
|
||||
iCopyColors<cI16, cBGRA, bCopy>,
|
||||
iCopyColors<cRGB555, cBGRA, bCopy>,
|
||||
iCopyColors<cPalEntry, cBGRA, bCopy>
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// True Color texture copy function
|
||||
//
|
||||
//===========================================================================
|
||||
void FBitmap::CopyPixelDataRGB(int originx, int originy, const uint8_t *patch, int srcwidth,
|
||||
int srcheight, int step_x, int step_y, int rotate, int ct,
|
||||
int r, int g, int b)
|
||||
{
|
||||
uint8_t *buffer = data + 4 * originx + Pitch * originy;
|
||||
for (int y=0;y<srcheight;y++)
|
||||
{
|
||||
copyfuncs[ct](&buffer[y*Pitch], &patch[y*step_y], srcwidth, step_x, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class TDest, class TBlend>
|
||||
void iCopyPaletted(uint8_t *buffer, const uint8_t * patch, int srcwidth, int srcheight, int Pitch,
|
||||
int step_x, int step_y, int rotate, PalEntry * palette)
|
||||
{
|
||||
int x,y,pos;
|
||||
|
||||
for (y=0;y<srcheight;y++)
|
||||
{
|
||||
pos = y*Pitch;
|
||||
for (x=0;x<srcwidth;x++,pos+=4)
|
||||
{
|
||||
int v=(unsigned char)patch[y*step_y+x*step_x];
|
||||
int a = palette[v].a;
|
||||
|
||||
if (TBlend::ProcessAlpha0() || a)
|
||||
{
|
||||
TBlend::OpC(buffer[pos + TDest::RED], palette[v].r, a);
|
||||
TBlend::OpC(buffer[pos + TDest::GREEN], palette[v].g, a);
|
||||
TBlend::OpC(buffer[pos + TDest::BLUE], palette[v].b, a);
|
||||
TBlend::OpA(buffer[pos + TDest::ALPHA], a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*CopyPalettedFunc)(uint8_t *buffer, const uint8_t * patch, int srcwidth, int srcheight, int Pitch,
|
||||
int step_x, int step_y, int rotate, PalEntry * palette);
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Paletted to True Color texture copy function
|
||||
//
|
||||
//===========================================================================
|
||||
void FBitmap::CopyPixelData(int originx, int originy, const uint8_t * patch, int srcwidth, int srcheight,
|
||||
int step_x, int step_y, int rotate, PalEntry * palette)
|
||||
{
|
||||
uint8_t *buffer = data + 4*originx + Pitch*originy;
|
||||
iCopyPaletted<cBGRA, bCopy>(buffer, patch, srcwidth, srcheight, Pitch,
|
||||
step_x, step_y, rotate, palette);
|
||||
}
|
||||
|
360
source/common/textures/bitmap.h
Normal file
360
source/common/textures/bitmap.h
Normal file
|
@ -0,0 +1,360 @@
|
|||
/*
|
||||
** bitmap.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __BITMAP_H__
|
||||
#define __BITMAP_H__
|
||||
|
||||
#include <algorithm>
|
||||
#include "palentry.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
|
||||
struct FCopyInfo;
|
||||
|
||||
struct FClipRect
|
||||
{
|
||||
int x, y, width, height;
|
||||
|
||||
bool Intersect(int ix, int iy, int iw, int ih);
|
||||
};
|
||||
|
||||
typedef int blend_t;
|
||||
|
||||
enum
|
||||
{
|
||||
BLENDBITS = 16,
|
||||
BLENDUNIT = (1<<BLENDBITS)
|
||||
};
|
||||
|
||||
enum ColorType
|
||||
{
|
||||
CF_RGB,
|
||||
CF_RGBT,
|
||||
CF_RGBA,
|
||||
CF_IA,
|
||||
CF_CMYK,
|
||||
CF_YCbCr,
|
||||
CF_BGR,
|
||||
CF_BGRA,
|
||||
CF_I16,
|
||||
CF_RGB555,
|
||||
CF_PalEntry
|
||||
};
|
||||
|
||||
|
||||
class FBitmap
|
||||
{
|
||||
protected:
|
||||
uint8_t *data;
|
||||
int Width;
|
||||
int Height;
|
||||
int Pitch;
|
||||
bool FreeBuffer;
|
||||
|
||||
|
||||
public:
|
||||
FBitmap()
|
||||
{
|
||||
data = NULL;
|
||||
Width = Height = 0;
|
||||
Pitch = 0;
|
||||
FreeBuffer = false;
|
||||
}
|
||||
|
||||
FBitmap(uint8_t *buffer, int pitch, int width, int height)
|
||||
{
|
||||
data = buffer;
|
||||
|
||||
Pitch = pitch;
|
||||
Width = width;
|
||||
Height = height;
|
||||
FreeBuffer = false;
|
||||
}
|
||||
|
||||
FBitmap(const FBitmap &other) = delete; // disallow because in nearly all cases this creates an unwanted copy.
|
||||
|
||||
FBitmap(FBitmap &&other)
|
||||
{
|
||||
data = other.data;
|
||||
Pitch = other.Pitch;
|
||||
Width = other.Width;
|
||||
Height = other.Height;
|
||||
FreeBuffer = other.FreeBuffer;
|
||||
other.data = nullptr;
|
||||
other.FreeBuffer = false;
|
||||
}
|
||||
|
||||
FBitmap &operator=(const FBitmap &other) = delete; // disallow because in nearly all cases this creates an unwanted copy. Use Copy instead.
|
||||
|
||||
FBitmap &operator=(FBitmap &&other)
|
||||
{
|
||||
if (data != nullptr && FreeBuffer) delete[] data;
|
||||
data = other.data;
|
||||
Pitch = other.Pitch;
|
||||
Width = other.Width;
|
||||
Height = other.Height;
|
||||
FreeBuffer = other.FreeBuffer;
|
||||
other.data = nullptr;
|
||||
other.FreeBuffer = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Copy(const FBitmap &other, bool deep = true)
|
||||
{
|
||||
if (data != nullptr && FreeBuffer) delete[] data;
|
||||
Pitch = other.Pitch;
|
||||
Width = other.Width;
|
||||
Height = other.Height;
|
||||
FreeBuffer = deep;
|
||||
if (deep)
|
||||
{
|
||||
data = new uint8_t[Pitch * Height];
|
||||
memcpy(data, other.data, Pitch * Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = other.data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
~FBitmap()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void Destroy()
|
||||
{
|
||||
if (data != NULL && FreeBuffer) delete [] data;
|
||||
data = NULL;
|
||||
FreeBuffer = false;
|
||||
}
|
||||
|
||||
bool Create (int w, int h)
|
||||
{
|
||||
Pitch = w*4;
|
||||
Width = w;
|
||||
Height = h;
|
||||
data = new uint8_t[4*w*h];
|
||||
memset(data, 0, 4*w*h);
|
||||
FreeBuffer = true;
|
||||
return data != NULL;
|
||||
}
|
||||
|
||||
int GetHeight() const
|
||||
{
|
||||
return Height;
|
||||
}
|
||||
|
||||
int GetWidth() const
|
||||
{
|
||||
return Width;
|
||||
}
|
||||
|
||||
int GetPitch() const
|
||||
{
|
||||
return Pitch;
|
||||
}
|
||||
|
||||
const uint8_t *GetPixels() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t *GetPixels()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void CopyPixelDataRGB(int originx, int originy, const uint8_t *patch, int srcwidth,
|
||||
int srcheight, int step_x, int step_y, int rotate, int ct,
|
||||
/* for PNG tRNS */ int r=0, int g=0, int b=0);
|
||||
void CopyPixelData(int originx, int originy, const uint8_t * patch, int srcwidth, int srcheight,
|
||||
int step_x, int step_y, int rotate, PalEntry * palette);
|
||||
|
||||
|
||||
void Blit(int originx, int originy, const FBitmap &src)
|
||||
{
|
||||
CopyPixelDataRGB(originx, originy, src.GetPixels(), src.GetWidth(), src.GetHeight(), 4, src.GetWidth()*4, 0, CF_BGRA);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// True color conversion classes for the different pixel formats
|
||||
// used by the supported texture formats
|
||||
//
|
||||
//===========================================================================
|
||||
struct cRGB
|
||||
{
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return p[0]; }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return p[1]; }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return p[2]; }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return 255; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return (p[0]*77 + p[1]*143 + p[2]*36)>>8; }
|
||||
};
|
||||
|
||||
struct cRGBT
|
||||
{
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return p[0]; }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return p[1]; }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return p[2]; }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t r, uint8_t g, uint8_t b) { return (p[0] != r || p[1] != g || p[2] != b) ? 255 : 0; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return (p[0]*77 + p[1]*143 + p[2]*36)>>8; }
|
||||
};
|
||||
|
||||
struct cRGBA
|
||||
{
|
||||
enum
|
||||
{
|
||||
RED = 0,
|
||||
GREEN = 1,
|
||||
BLUE = 1,
|
||||
ALPHA = 3
|
||||
};
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return p[0]; }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return p[1]; }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return p[2]; }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return p[3]; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return (p[0]*77 + p[1]*143 + p[2]*36)>>8; }
|
||||
};
|
||||
|
||||
struct cIA
|
||||
{
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return p[0]; }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return p[0]; }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return p[0]; }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return p[1]; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return p[0]; }
|
||||
};
|
||||
|
||||
struct cCMYK
|
||||
{
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return p[3] - (((256-p[0])*p[3]) >> 8); }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return p[3] - (((256-p[1])*p[3]) >> 8); }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return p[3] - (((256-p[2])*p[3]) >> 8); }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return 255; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; }
|
||||
};
|
||||
|
||||
struct cYCbCr
|
||||
{
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return clamp((int)(p[0] + 1.40200 * (int(p[2]) - 0x80)), 0, 255); }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return clamp((int)(p[0] - 0.34414 * (int(p[1] - 0x80)) - 0.71414 * (int(p[2]) - 0x80)), 0, 255); }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return clamp((int)(p[0] + 1.77200 * (int(p[1]) - 0x80)), 0, 255); }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return 255; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return (R(p) * 77 + G(p) * 143 + B(p) * 36) >> 8; }
|
||||
};
|
||||
|
||||
struct cBGR
|
||||
{
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return p[2]; }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return p[1]; }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return p[0]; }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return 255; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return (p[2]*77 + p[1]*143 + p[0]*36)>>8; }
|
||||
};
|
||||
|
||||
struct cBGRA
|
||||
{
|
||||
enum
|
||||
{
|
||||
RED = 2,
|
||||
GREEN = 1,
|
||||
BLUE = 0,
|
||||
ALPHA = 3
|
||||
};
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return p[2]; }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return p[1]; }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return p[0]; }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return p[3]; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return (p[2]*77 + p[1]*143 + p[0]*36)>>8; }
|
||||
};
|
||||
|
||||
struct cARGB
|
||||
{
|
||||
enum
|
||||
{
|
||||
RED = 1,
|
||||
GREEN = 2,
|
||||
BLUE = 3,
|
||||
ALPHA = 0
|
||||
};
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return p[1]; }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return p[2]; }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return p[3]; }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return p[0]; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return (p[1]*77 + p[2]*143 + p[3]*36)>>8; }
|
||||
};
|
||||
|
||||
struct cI16
|
||||
{
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return p[1]; }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return p[1]; }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return p[1]; }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return 255; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return p[1]; }
|
||||
};
|
||||
|
||||
struct cRGB555
|
||||
{
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return (((*(uint16_t*)p)&0x1f)<<3); }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return (((*(uint16_t*)p)&0x3e0)>>2); }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return (((*(uint16_t*)p)&0x7c00)>>7); }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return 255; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; }
|
||||
};
|
||||
|
||||
struct cPalEntry
|
||||
{
|
||||
static __forceinline unsigned char R(const unsigned char * p) { return ((PalEntry*)p)->r; }
|
||||
static __forceinline unsigned char G(const unsigned char * p) { return ((PalEntry*)p)->g; }
|
||||
static __forceinline unsigned char B(const unsigned char * p) { return ((PalEntry*)p)->b; }
|
||||
static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return ((PalEntry*)p)->a; }
|
||||
static __forceinline int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; }
|
||||
};
|
||||
|
||||
struct bCopy
|
||||
{
|
||||
static __forceinline void OpC(uint8_t &d, uint8_t s, uint8_t a) { d = s; }
|
||||
static __forceinline void OpA(uint8_t &d, uint8_t s) { d = s; }
|
||||
static __forceinline bool ProcessAlpha0() { return false; }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
248
source/common/textures/formats/buildtexture.cpp
Normal file
248
source/common/textures/formats/buildtexture.cpp
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
** buildtexture.cpp
|
||||
** Handling Build textures (now as a usable editing feature!)
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2004-2006 Randy Heit
|
||||
** Copyright 2018 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "zstring.h"
|
||||
#include "files.h"
|
||||
#include "templates.h"
|
||||
#include "bitmap.h"
|
||||
#include "textures/textures.h"
|
||||
#include "image.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// A texture defined in a Build TILESxxx.ART file
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FBuildTexture : public FImageSource
|
||||
{
|
||||
public:
|
||||
FBuildTexture (const FString &pathprefix, int tilenum, const uint8_t *pixels, int width, int height, int left, int top);
|
||||
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
|
||||
|
||||
protected:
|
||||
const uint8_t *RawPixels;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FBuildTexture::FBuildTexture(const FString &pathprefix, int tilenum, const uint8_t *pixels, int width, int height, int left, int top)
|
||||
: RawPixels (pixels)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
LeftOffset = left;
|
||||
TopOffset = top;
|
||||
}
|
||||
|
||||
TArray<uint8_t> FBuildTexture::CreatePalettedPixels(int conversion)
|
||||
{
|
||||
TArray<uint8_t> Pixels(Width * Height, true);
|
||||
memcpy(Pixels.Data(), RawPixels, Width * Height);
|
||||
return Pixels;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//===========================================================================
|
||||
//
|
||||
// AddTiles
|
||||
//
|
||||
// Adds all the tiles in an artfile to the texture manager.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FTextureManager::AddTiles (const FString &pathprefix, const void *tiles)
|
||||
{
|
||||
|
||||
// int numtiles = LittleLong(((uint32_t *)tiles)[1]); // This value is not reliable
|
||||
int tilestart = LittleLong(((uint32_t *)tiles)[2]);
|
||||
int tileend = LittleLong(((uint32_t *)tiles)[3]);
|
||||
const uint16_t *tilesizx = &((const uint16_t *)tiles)[8];
|
||||
const uint16_t *tilesizy = &tilesizx[tileend - tilestart + 1];
|
||||
const uint32_t *picanm = (const uint32_t *)&tilesizy[tileend - tilestart + 1];
|
||||
const uint8_t *tiledata = (const uint8_t *)&picanm[tileend - tilestart + 1];
|
||||
|
||||
for (int i = tilestart; i <= tileend; ++i)
|
||||
{
|
||||
int pic = i - tilestart;
|
||||
int width = LittleShort(tilesizx[pic]);
|
||||
int height = LittleShort(tilesizy[pic]);
|
||||
uint32_t anm = LittleLong(picanm[pic]);
|
||||
int xoffs = (int8_t)((anm >> 8) & 255) + width/2;
|
||||
int yoffs = (int8_t)((anm >> 16) & 255) + height/2;
|
||||
int size = width*height;
|
||||
//FTextureID texnum;
|
||||
FTexture *tex;
|
||||
|
||||
if (width <= 0 || height <= 0) continue;
|
||||
|
||||
tex = new FImageTexture(new FBuildTexture (pathprefix, i, tiledata, width, height, xoffs, yoffs));
|
||||
//texnum = AddTexture (tex);
|
||||
tiledata += size;
|
||||
tex->Name.Format("%sTILE%04d", pathprefix.GetChars(), i);
|
||||
|
||||
// I have no idea if this makes sense or if we better leave animation control to the game code.
|
||||
// To be decided later.
|
||||
#if 0
|
||||
if ((picanm[pic] & 63) && (picanm[pic] & 192))
|
||||
{
|
||||
int type, speed;
|
||||
|
||||
switch (picanm[pic] & 192)
|
||||
{
|
||||
case 64: type = 2; break;
|
||||
case 128: type = 0; break;
|
||||
case 192: type = 1; break;
|
||||
default: type = 0; break; // Won't happen, but GCC bugs me if I don't put this here.
|
||||
}
|
||||
|
||||
speed = (anm >> 24) & 15;
|
||||
speed = MAX (1, (1 << speed) * 1000 / 120); // Convert from 120 Hz to 1000 Hz.
|
||||
|
||||
AddSimpleAnim (texnum, picanm[pic] & 63, type, speed);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Blood's rotation types:
|
||||
// 0 - Single
|
||||
// 1 - 5 Full
|
||||
// 2 - 8 Full
|
||||
// 3 - Bounce (looks no different from Single; seems to signal bouncy sprites)
|
||||
// 4 - 5 Half (not used in game)
|
||||
// 5 - 3 Flat (not used in game)
|
||||
// 6 - Voxel
|
||||
// 7 - Spin Voxel
|
||||
|
||||
#if 0
|
||||
int rotType = (anm >> 28) & 7;
|
||||
if (rotType == 1)
|
||||
{
|
||||
spriteframe_t rot;
|
||||
rot.Texture[0] =
|
||||
rot.Texture[1] = texnum;
|
||||
for (int j = 1; j < 4; ++j)
|
||||
{
|
||||
rot.Texture[j*2] =
|
||||
rot.Texture[j*2+1] =
|
||||
rot.Texture[16-j*2] =
|
||||
rot.Texture[17-j*2] = texnum.GetIndex() + j;
|
||||
}
|
||||
rot.Texture[8] =
|
||||
rot.Texture[9] = texnum.GetIndex() + 4;
|
||||
rot.Flip = 0x00FC;
|
||||
rot.Voxel = NULL;
|
||||
tex->Rotations = SpriteFrames.Push (rot);
|
||||
}
|
||||
else if (rotType == 2)
|
||||
{
|
||||
spriteframe_t rot;
|
||||
rot.Texture[0] =
|
||||
rot.Texture[1] = texnum;
|
||||
for (int j = 1; j < 8; ++j)
|
||||
{
|
||||
rot.Texture[16-j*2] =
|
||||
rot.Texture[17-j*2] = texnum.GetIndex() + j;
|
||||
}
|
||||
rot.Flip = 0;
|
||||
rot.Voxel = NULL;
|
||||
tex->Rotations = SpriteFrames.Push (rot);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// CountTiles
|
||||
//
|
||||
// Returns the number of tiles provided by an artfile
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static int CountTiles (const void *tiles)
|
||||
{
|
||||
int version = LittleLong(*(uint32_t *)tiles);
|
||||
if (version != 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tilestart = LittleLong(((uint32_t *)tiles)[2]);
|
||||
int tileend = LittleLong(((uint32_t *)tiles)[3]);
|
||||
|
||||
return tileend >= tilestart ? tileend - tilestart + 1 : 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// R_CountBuildTiles
|
||||
//
|
||||
// Returns the number of tiles found. Also loads all the data for
|
||||
// R_InitBuildTiles() to process later.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FTextureManager::InitBuildTiles(TArray<FString> &tileFiles)
|
||||
{
|
||||
int numtiles;
|
||||
int totaltiles = 0;
|
||||
|
||||
for (auto &artpath : tileFiles)
|
||||
{
|
||||
int lumpnum = fileSystem.FindFile(artpath);
|
||||
if (lumpnum >= 0)
|
||||
{
|
||||
BuildTileData.Reserve(1);
|
||||
auto &artdata = BuildTileData.Last();
|
||||
artdata = fileSystem.GetFileData(lumpnum);
|
||||
|
||||
if ((numtiles = CountTiles(artdata.Data())) > 0)
|
||||
{
|
||||
AddTiles("", &artdata[0]);
|
||||
totaltiles += numtiles;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
760
source/common/textures/formats/ddstexture.cpp
Normal file
760
source/common/textures/formats/ddstexture.cpp
Normal file
|
@ -0,0 +1,760 @@
|
|||
/*
|
||||
** pngtexture.cpp
|
||||
** Texture class for DDS images
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2006-2007 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
** DDS is short for "DirectDraw Surface" and is essentially that. It's
|
||||
** interesting to us because it is a standard file format for DXTC/S3TC
|
||||
** encoded images. Look up "DDS File Reference" in the DirectX SDK or
|
||||
** the online MSDN documentation to the specs for this file format. Look up
|
||||
** "Compressed Texture Resources" for information about DXTC encoding.
|
||||
**
|
||||
** Perhaps the most important part of DXTC to realize is that every 4x4
|
||||
** pixel block can only have four different colors, and only two of those
|
||||
** are discrete. So depending on the texture, there may be very noticable
|
||||
** quality degradation, or it may look virtually indistinguishable from
|
||||
** the uncompressed texture.
|
||||
**
|
||||
** Note: Although this class supports reading RGB textures from a DDS,
|
||||
** DO NOT use DDS images with plain RGB data. PNG does everything useful
|
||||
** better. Since DDS lets the R, G, B, and A components lie anywhere in
|
||||
** the pixel data, it is fairly inefficient to process.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "files.h"
|
||||
#include "bitmap.h"
|
||||
#include "image.h"
|
||||
#include "m_png.h"
|
||||
#include "cache1d.h"
|
||||
|
||||
// Since we want this to compile under Linux too, we need to define this
|
||||
// stuff ourselves instead of including a DirectX header.
|
||||
|
||||
enum
|
||||
{
|
||||
ID_DDS = MAKE_ID('D', 'D', 'S', ' '),
|
||||
ID_DXT1 = MAKE_ID('D', 'X', 'T', '1'),
|
||||
ID_DXT2 = MAKE_ID('D', 'X', 'T', '2'),
|
||||
ID_DXT3 = MAKE_ID('D', 'X', 'T', '3'),
|
||||
ID_DXT4 = MAKE_ID('D', 'X', 'T', '4'),
|
||||
ID_DXT5 = MAKE_ID('D', 'X', 'T', '5'),
|
||||
|
||||
// Bits in dwFlags
|
||||
DDSD_CAPS = 0x00000001,
|
||||
DDSD_HEIGHT = 0x00000002,
|
||||
DDSD_WIDTH = 0x00000004,
|
||||
DDSD_PITCH = 0x00000008,
|
||||
DDSD_PIXELFORMAT = 0x00001000,
|
||||
DDSD_MIPMAPCOUNT = 0x00020000,
|
||||
DDSD_LINEARSIZE = 0x00080000,
|
||||
DDSD_DEPTH = 0x00800000,
|
||||
|
||||
// Bits in ddpfPixelFormat
|
||||
DDPF_ALPHAPIXELS = 0x00000001,
|
||||
DDPF_FOURCC = 0x00000004,
|
||||
DDPF_RGB = 0x00000040,
|
||||
|
||||
// Bits in DDSCAPS2.dwCaps1
|
||||
DDSCAPS_COMPLEX = 0x00000008,
|
||||
DDSCAPS_TEXTURE = 0x00001000,
|
||||
DDSCAPS_MIPMAP = 0x00400000,
|
||||
|
||||
// Bits in DDSCAPS2.dwCaps2
|
||||
DDSCAPS2_CUBEMAP = 0x00000200,
|
||||
DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400,
|
||||
DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800,
|
||||
DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000,
|
||||
DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000,
|
||||
DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000,
|
||||
DDSCAPS2_CUBEMAP_NEGATIZEZ = 0x00008000,
|
||||
DDSCAPS2_VOLUME = 0x00200000,
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct DDPIXELFORMAT
|
||||
{
|
||||
uint32_t Size; // Must be 32
|
||||
uint32_t Flags;
|
||||
uint32_t FourCC;
|
||||
uint32_t RGBBitCount;
|
||||
uint32_t RBitMask, GBitMask, BBitMask;
|
||||
uint32_t RGBAlphaBitMask;
|
||||
};
|
||||
|
||||
struct DDCAPS2
|
||||
{
|
||||
uint32_t Caps1, Caps2;
|
||||
uint32_t Reserved[2];
|
||||
};
|
||||
|
||||
struct DDSURFACEDESC2
|
||||
{
|
||||
uint32_t Size; // Must be 124. DevIL claims some writers set it to 'DDS ' instead.
|
||||
uint32_t Flags;
|
||||
uint32_t Height;
|
||||
uint32_t Width;
|
||||
union
|
||||
{
|
||||
int32_t Pitch;
|
||||
uint32_t LinearSize;
|
||||
};
|
||||
uint32_t Depth;
|
||||
uint32_t MipMapCount;
|
||||
uint32_t Reserved1[11];
|
||||
DDPIXELFORMAT PixelFormat;
|
||||
DDCAPS2 Caps;
|
||||
uint32_t Reserved2;
|
||||
};
|
||||
|
||||
struct DDSFileHeader
|
||||
{
|
||||
uint32_t Magic;
|
||||
DDSURFACEDESC2 Desc;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// A DDS image, with DXTx compression
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FDDSTexture : public FImageSource
|
||||
{
|
||||
enum
|
||||
{
|
||||
PIX_Palette = 0,
|
||||
PIX_Alphatex = 1,
|
||||
PIX_ARGB = 2
|
||||
};
|
||||
public:
|
||||
FDDSTexture (FileReader &lump, void *surfdesc);
|
||||
|
||||
protected:
|
||||
uint32_t Format;
|
||||
|
||||
uint32_t RMask, GMask, BMask, AMask;
|
||||
uint8_t RShiftL, GShiftL, BShiftL, AShiftL;
|
||||
uint8_t RShiftR, GShiftR, BShiftR, AShiftR;
|
||||
|
||||
int32_t Pitch;
|
||||
uint32_t LinearSize;
|
||||
|
||||
static void CalcBitShift (uint32_t mask, uint8_t *lshift, uint8_t *rshift);
|
||||
|
||||
void ReadRGB (FileReader &lump, uint8_t *buffer, int pixelmode);
|
||||
void DecompressDXT1 (FileReader &lump, uint8_t *buffer, int pixelmode);
|
||||
void DecompressDXT3 (FileReader &lump, bool premultiplied, uint8_t *buffer, int pixelmode);
|
||||
void DecompressDXT5 (FileReader &lump, bool premultiplied, uint8_t *buffer, int pixelmode);
|
||||
|
||||
int CopyPixels(FBitmap *bmp, int conversion) override;
|
||||
|
||||
friend class FTexture;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static bool CheckDDS (FileReader &file)
|
||||
{
|
||||
DDSFileHeader Header;
|
||||
|
||||
file.Seek(0, FileReader::SeekSet);
|
||||
if (file.Read (&Header, sizeof(Header)) != sizeof(Header))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Header.Magic == ID_DDS &&
|
||||
(LittleLong(Header.Desc.Size) == sizeof(DDSURFACEDESC2) || Header.Desc.Size == ID_DDS) &&
|
||||
LittleLong(Header.Desc.PixelFormat.Size) == sizeof(DDPIXELFORMAT) &&
|
||||
(LittleLong(Header.Desc.Flags) & (DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT)) == (DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT) &&
|
||||
Header.Desc.Width != 0 &&
|
||||
Header.Desc.Height != 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FImageSource *DDSImage_TryCreate (FileReader &data)
|
||||
{
|
||||
union
|
||||
{
|
||||
DDSURFACEDESC2 surfdesc;
|
||||
uint32_t byteswapping[sizeof(DDSURFACEDESC2) / 4];
|
||||
};
|
||||
|
||||
if (!CheckDDS(data)) return NULL;
|
||||
|
||||
data.Seek(4, FileReader::SeekSet);
|
||||
data.Read (&surfdesc, sizeof(surfdesc));
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
// Every single element of the header is a uint32_t
|
||||
for (unsigned int i = 0; i < sizeof(DDSURFACEDESC2) / 4; ++i)
|
||||
{
|
||||
byteswapping[i] = LittleLong(byteswapping[i]);
|
||||
}
|
||||
// Undo the byte swap for the pixel format
|
||||
surfdesc.PixelFormat.FourCC = LittleLong(surfdesc.PixelFormat.FourCC);
|
||||
#endif
|
||||
|
||||
if (surfdesc.PixelFormat.Flags & DDPF_FOURCC)
|
||||
{
|
||||
// Check for supported FourCC
|
||||
if (surfdesc.PixelFormat.FourCC != ID_DXT1 &&
|
||||
surfdesc.PixelFormat.FourCC != ID_DXT2 &&
|
||||
surfdesc.PixelFormat.FourCC != ID_DXT3 &&
|
||||
surfdesc.PixelFormat.FourCC != ID_DXT4 &&
|
||||
surfdesc.PixelFormat.FourCC != ID_DXT5)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (!(surfdesc.Flags & DDSD_LINEARSIZE))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (surfdesc.PixelFormat.Flags & DDPF_RGB)
|
||||
{
|
||||
if ((surfdesc.PixelFormat.RGBBitCount >> 3) < 1 ||
|
||||
(surfdesc.PixelFormat.RGBBitCount >> 3) > 4)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if ((surfdesc.Flags & DDSD_PITCH) && (surfdesc.Pitch <= 0))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return new FDDSTexture (data, &surfdesc);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FDDSTexture::FDDSTexture (FileReader &lump, void *vsurfdesc)
|
||||
{
|
||||
DDSURFACEDESC2 *surf = (DDSURFACEDESC2 *)vsurfdesc;
|
||||
|
||||
bMasked = false;
|
||||
Width = uint16_t(surf->Width);
|
||||
Height = uint16_t(surf->Height);
|
||||
|
||||
if (surf->PixelFormat.Flags & DDPF_FOURCC)
|
||||
{
|
||||
Format = surf->PixelFormat.FourCC;
|
||||
Pitch = 0;
|
||||
LinearSize = surf->LinearSize;
|
||||
}
|
||||
else // DDPF_RGB
|
||||
{
|
||||
Format = surf->PixelFormat.RGBBitCount >> 3;
|
||||
CalcBitShift (RMask = surf->PixelFormat.RBitMask, &RShiftL, &RShiftR);
|
||||
CalcBitShift (GMask = surf->PixelFormat.GBitMask, &GShiftL, &GShiftR);
|
||||
CalcBitShift (BMask = surf->PixelFormat.BBitMask, &BShiftL, &BShiftR);
|
||||
if (surf->PixelFormat.Flags & DDPF_ALPHAPIXELS)
|
||||
{
|
||||
CalcBitShift (AMask = surf->PixelFormat.RGBAlphaBitMask, &AShiftL, &AShiftR);
|
||||
}
|
||||
else
|
||||
{
|
||||
AMask = 0;
|
||||
AShiftL = AShiftR = 0;
|
||||
}
|
||||
if (surf->Flags & DDSD_PITCH)
|
||||
{
|
||||
Pitch = surf->Pitch;
|
||||
}
|
||||
else
|
||||
{
|
||||
Pitch = (Width * Format + 3) & ~3;
|
||||
}
|
||||
LinearSize = Pitch * Height;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Returns the number of bits the color must be shifted to produce
|
||||
// an 8-bit value, as in:
|
||||
//
|
||||
// c = (color & mask) << lshift;
|
||||
// c |= c >> rshift;
|
||||
// c >>= 24;
|
||||
//
|
||||
// For any color of at least 4 bits, this ensures that the result
|
||||
// of the calculation for c will be fully saturated, given a maximum
|
||||
// value for the input bit mask.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FDDSTexture::CalcBitShift (uint32_t mask, uint8_t *lshiftp, uint8_t *rshiftp)
|
||||
{
|
||||
uint8_t shift;
|
||||
|
||||
if (mask == 0)
|
||||
{
|
||||
*lshiftp = *rshiftp = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
shift = 0;
|
||||
while ((mask & 0x80000000) == 0)
|
||||
{
|
||||
mask <<= 1;
|
||||
shift++;
|
||||
}
|
||||
*lshiftp = shift;
|
||||
|
||||
shift = 0;
|
||||
while (mask & 0x80000000)
|
||||
{
|
||||
mask <<= 1;
|
||||
shift++;
|
||||
}
|
||||
*rshiftp = shift;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Note that pixel size == 8 is column-major, but 32 is row-major!
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FDDSTexture::ReadRGB (FileReader &lump, uint8_t *buffer, int pixelmode)
|
||||
{
|
||||
uint32_t x, y;
|
||||
uint32_t amask = AMask == 0 ? 0 : 0x80000000 >> AShiftL;
|
||||
uint8_t *linebuff = new uint8_t[Pitch];
|
||||
|
||||
for (y = Height; y > 0; --y)
|
||||
{
|
||||
uint8_t *buffp = linebuff;
|
||||
uint8_t *pixelp = pixelmode == PIX_ARGB ? buffer + 4 * (y - 1)*Width : buffer + y - 1;
|
||||
lump.Read (linebuff, Pitch);
|
||||
for (x = Width; x > 0; --x)
|
||||
{
|
||||
uint32_t c;
|
||||
if (Format == 4)
|
||||
{
|
||||
c = LittleLong(*(uint32_t *)buffp); buffp += 4;
|
||||
}
|
||||
else if (Format == 2)
|
||||
{
|
||||
c = LittleShort(*(uint16_t *)buffp); buffp += 2;
|
||||
}
|
||||
else if (Format == 3)
|
||||
{
|
||||
c = buffp[0] | (buffp[1] << 8) | (buffp[2] << 16); buffp += 3;
|
||||
}
|
||||
else // Format == 1
|
||||
{
|
||||
c = *buffp++;
|
||||
}
|
||||
if (pixelmode != PIX_ARGB)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t r = (c & RMask) << RShiftL; r |= r >> RShiftR;
|
||||
uint32_t g = (c & GMask) << GShiftL; g |= g >> GShiftR;
|
||||
uint32_t b = (c & BMask) << BShiftL; b |= b >> BShiftR;
|
||||
uint32_t a = (c & AMask) << AShiftL; a |= a >> AShiftR;
|
||||
pixelp[0] = (uint8_t)(b>>24);
|
||||
pixelp[1] = (uint8_t)(g>>24);
|
||||
pixelp[2] = (uint8_t)(r>>24);
|
||||
pixelp[3] = (uint8_t)(a>>24);
|
||||
pixelp+=4;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] linebuff;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FDDSTexture::DecompressDXT1 (FileReader &lump, uint8_t *buffer, int pixelmode)
|
||||
{
|
||||
const long blocklinelen = ((Width + 3) >> 2) << 3;
|
||||
uint8_t *blockbuff = new uint8_t[blocklinelen];
|
||||
uint8_t *block;
|
||||
PalEntry color[4];
|
||||
uint8_t palcol[4] = { 0,0,0,0 }; // shut up compiler warnings.
|
||||
int ox, oy, x, y, i;
|
||||
|
||||
color[0].a = 255;
|
||||
color[1].a = 255;
|
||||
color[2].a = 255;
|
||||
|
||||
for (oy = 0; oy < Height; oy += 4)
|
||||
{
|
||||
lump.Read (blockbuff, blocklinelen);
|
||||
block = blockbuff;
|
||||
for (ox = 0; ox < Width; ox += 4)
|
||||
{
|
||||
uint16_t color16[2] = { LittleShort(((uint16_t *)block)[0]), LittleShort(((uint16_t *)block)[1]) };
|
||||
|
||||
// Convert color from R5G6B5 to R8G8B8.
|
||||
for (i = 1; i >= 0; --i)
|
||||
{
|
||||
color[i].r = ((color16[i] & 0xF800) >> 8) | (color16[i] >> 13);
|
||||
color[i].g = ((color16[i] & 0x07E0) >> 3) | ((color16[i] & 0x0600) >> 9);
|
||||
color[i].b = ((color16[i] & 0x001F) << 3) | ((color16[i] & 0x001C) >> 2);
|
||||
}
|
||||
if (color16[0] > color16[1])
|
||||
{ // Four-color block: derive the other two colors.
|
||||
color[2].r = (color[0].r + color[0].r + color[1].r + 1) / 3;
|
||||
color[2].g = (color[0].g + color[0].g + color[1].g + 1) / 3;
|
||||
color[2].b = (color[0].b + color[0].b + color[1].b + 1) / 3;
|
||||
|
||||
color[3].r = (color[0].r + color[1].r + color[1].r + 1) / 3;
|
||||
color[3].g = (color[0].g + color[1].g + color[1].g + 1) / 3;
|
||||
color[3].b = (color[0].b + color[1].b + color[1].b + 1) / 3;
|
||||
color[3].a = 255;
|
||||
}
|
||||
else
|
||||
{ // Three-color block: derive the other color.
|
||||
color[2].r = (color[0].r + color[1].r) / 2;
|
||||
color[2].g = (color[0].g + color[1].g) / 2;
|
||||
color[2].b = (color[0].b + color[1].b) / 2;
|
||||
|
||||
color[3].a = color[3].b = color[3].g = color[3].r = 0;
|
||||
|
||||
// If you have a three-color block, presumably that transparent
|
||||
// color is going to be used.
|
||||
bMasked = true;
|
||||
}
|
||||
// Pick colors from the palette for each of the four colors.
|
||||
if (pixelmode != PIX_ARGB) for (i = 3; i >= 0; --i)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
// Now decode this 4x4 block to the pixel buffer.
|
||||
for (y = 0; y < 4; ++y)
|
||||
{
|
||||
if (oy + y >= Height)
|
||||
{
|
||||
break;
|
||||
}
|
||||
uint8_t yslice = block[4 + y];
|
||||
for (x = 0; x < 4; ++x)
|
||||
{
|
||||
if (ox + x >= Width)
|
||||
{
|
||||
break;
|
||||
}
|
||||
int ci = (yslice >> (x + x)) & 3;
|
||||
if (pixelmode != PIX_ARGB)
|
||||
{
|
||||
buffer[oy + y + (ox + x) * Height] = palcol[ci];
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t * tcp = &buffer[(ox + x)*4 + (oy + y) * Width*4];
|
||||
tcp[0] = color[ci].b;
|
||||
tcp[1] = color[ci].g;
|
||||
tcp[2] = color[ci].r;
|
||||
tcp[3] = color[ci].a;
|
||||
}
|
||||
}
|
||||
}
|
||||
block += 8;
|
||||
}
|
||||
}
|
||||
delete[] blockbuff;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DXT3: Decompression is identical to DXT1, except every 64-bit block is
|
||||
// preceded by another 64-bit block with explicit alpha values.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FDDSTexture::DecompressDXT3 (FileReader &lump, bool premultiplied, uint8_t *buffer, int pixelmode)
|
||||
{
|
||||
const long blocklinelen = ((Width + 3) >> 2) << 4;
|
||||
uint8_t *blockbuff = new uint8_t[blocklinelen];
|
||||
uint8_t *block;
|
||||
PalEntry color[4];
|
||||
uint8_t palcol[4] = { 0,0,0,0 };
|
||||
int ox, oy, x, y, i;
|
||||
|
||||
for (oy = 0; oy < Height; oy += 4)
|
||||
{
|
||||
lump.Read (blockbuff, blocklinelen);
|
||||
block = blockbuff;
|
||||
for (ox = 0; ox < Width; ox += 4)
|
||||
{
|
||||
uint16_t color16[2] = { LittleShort(((uint16_t *)block)[4]), LittleShort(((uint16_t *)block)[5]) };
|
||||
|
||||
// Convert color from R5G6B5 to R8G8B8.
|
||||
for (i = 1; i >= 0; --i)
|
||||
{
|
||||
color[i].r = ((color16[i] & 0xF800) >> 8) | (color16[i] >> 13);
|
||||
color[i].g = ((color16[i] & 0x07E0) >> 3) | ((color16[i] & 0x0600) >> 9);
|
||||
color[i].b = ((color16[i] & 0x001F) << 3) | ((color16[i] & 0x001C) >> 2);
|
||||
}
|
||||
// Derive the other two colors.
|
||||
color[2].r = (color[0].r + color[0].r + color[1].r + 1) / 3;
|
||||
color[2].g = (color[0].g + color[0].g + color[1].g + 1) / 3;
|
||||
color[2].b = (color[0].b + color[0].b + color[1].b + 1) / 3;
|
||||
|
||||
color[3].r = (color[0].r + color[1].r + color[1].r + 1) / 3;
|
||||
color[3].g = (color[0].g + color[1].g + color[1].g + 1) / 3;
|
||||
color[3].b = (color[0].b + color[1].b + color[1].b + 1) / 3;
|
||||
|
||||
// Pick colors from the palette for each of the four colors.
|
||||
if (pixelmode != PIX_ARGB) for (i = 3; i >= 0; --i)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// Now decode this 4x4 block to the pixel buffer.
|
||||
for (y = 0; y < 4; ++y)
|
||||
{
|
||||
if (oy + y >= Height)
|
||||
{
|
||||
break;
|
||||
}
|
||||
uint8_t yslice = block[12 + y];
|
||||
uint16_t yalphaslice = LittleShort(((uint16_t *)block)[y]);
|
||||
for (x = 0; x < 4; ++x)
|
||||
{
|
||||
if (ox + x >= Width)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (pixelmode == PIX_Palette)
|
||||
{
|
||||
buffer[oy + y + (ox + x) * Height] = ((yalphaslice >> (x*4)) & 15) < 8 ?
|
||||
(bMasked = true, 0) : palcol[(yslice >> (x + x)) & 3];
|
||||
}
|
||||
else if (pixelmode == PIX_Alphatex)
|
||||
{
|
||||
int alphaval = ((yalphaslice >> (x * 4)) & 15);
|
||||
int palval = palcol[(yslice >> (x + x)) & 3];
|
||||
buffer[oy + y + (ox + x) * Height] = palval * alphaval / 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t * tcp = &buffer[(ox + x)*4 + (oy + y) * Width*4];
|
||||
int c = (yslice >> (x + x)) & 3;
|
||||
tcp[0] = color[c].b;
|
||||
tcp[1] = color[c].g;
|
||||
tcp[2] = color[c].r;
|
||||
tcp[3] = ((yalphaslice >> (x * 4)) & 15) * 0x11;
|
||||
}
|
||||
}
|
||||
}
|
||||
block += 16;
|
||||
}
|
||||
}
|
||||
delete[] blockbuff;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DXT5: Decompression is identical to DXT3, except every 64-bit alpha block
|
||||
// contains interpolated alpha values, similar to the 64-bit color block.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FDDSTexture::DecompressDXT5 (FileReader &lump, bool premultiplied, uint8_t *buffer, int pixelmode)
|
||||
{
|
||||
const long blocklinelen = ((Width + 3) >> 2) << 4;
|
||||
uint8_t *blockbuff = new uint8_t[blocklinelen];
|
||||
uint8_t *block;
|
||||
PalEntry color[4];
|
||||
uint8_t palcol[4] = { 0,0,0,0 };
|
||||
uint32_t yalphaslice = 0;
|
||||
int ox, oy, x, y, i;
|
||||
|
||||
for (oy = 0; oy < Height; oy += 4)
|
||||
{
|
||||
lump.Read (blockbuff, blocklinelen);
|
||||
block = blockbuff;
|
||||
for (ox = 0; ox < Width; ox += 4)
|
||||
{
|
||||
uint16_t color16[2] = { LittleShort(((uint16_t *)block)[4]), LittleShort(((uint16_t *)block)[5]) };
|
||||
uint8_t alpha[8];
|
||||
|
||||
// Calculate the eight alpha values.
|
||||
alpha[0] = block[0];
|
||||
alpha[1] = block[1];
|
||||
|
||||
if (alpha[0] >= alpha[1])
|
||||
{ // Eight-alpha block: derive the other six alphas.
|
||||
for (i = 0; i < 6; ++i)
|
||||
{
|
||||
alpha[i + 2] = ((6 - i) * alpha[0] + (i + 1) * alpha[1] + 3) / 7;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Six-alpha block: derive the other four alphas.
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
alpha[i + 2] = ((4 - i) * alpha[0] + (i + 1) * alpha[1] + 2) / 5;
|
||||
}
|
||||
alpha[6] = 0;
|
||||
alpha[7] = 255;
|
||||
}
|
||||
|
||||
// Convert color from R5G6B5 to R8G8B8.
|
||||
for (i = 1; i >= 0; --i)
|
||||
{
|
||||
color[i].r = ((color16[i] & 0xF800) >> 8) | (color16[i] >> 13);
|
||||
color[i].g = ((color16[i] & 0x07E0) >> 3) | ((color16[i] & 0x0600) >> 9);
|
||||
color[i].b = ((color16[i] & 0x001F) << 3) | ((color16[i] & 0x001C) >> 2);
|
||||
}
|
||||
// Derive the other two colors.
|
||||
color[2].r = (color[0].r + color[0].r + color[1].r + 1) / 3;
|
||||
color[2].g = (color[0].g + color[0].g + color[1].g + 1) / 3;
|
||||
color[2].b = (color[0].b + color[0].b + color[1].b + 1) / 3;
|
||||
|
||||
color[3].r = (color[0].r + color[1].r + color[1].r + 1) / 3;
|
||||
color[3].g = (color[0].g + color[1].g + color[1].g + 1) / 3;
|
||||
color[3].b = (color[0].b + color[1].b + color[1].b + 1) / 3;
|
||||
|
||||
// Pick colors from the palette for each of the four colors.
|
||||
if (pixelmode != PIX_ARGB) for (i = 3; i >= 0; --i)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
// Now decode this 4x4 block to the pixel buffer.
|
||||
for (y = 0; y < 4; ++y)
|
||||
{
|
||||
if (oy + y >= Height)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Alpha values are stored in 3 bytes for 2 rows
|
||||
if ((y & 1) == 0)
|
||||
{
|
||||
yalphaslice = block[y*3] | (block[y*3+1] << 8) | (block[y*3+2] << 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
yalphaslice >>= 12;
|
||||
}
|
||||
uint8_t yslice = block[12 + y];
|
||||
for (x = 0; x < 4; ++x)
|
||||
{
|
||||
if (ox + x >= Width)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (pixelmode == PIX_Palette)
|
||||
{
|
||||
buffer[oy + y + (ox + x) * Height] = alpha[((yalphaslice >> (x*3)) & 7)] < 128 ?
|
||||
(bMasked = true, 0) : palcol[(yslice >> (x + x)) & 3];
|
||||
}
|
||||
else if (pixelmode == PIX_Alphatex)
|
||||
{
|
||||
int alphaval = alpha[((yalphaslice >> (x * 3)) & 7)];
|
||||
int palval = palcol[(yslice >> (x + x)) & 3];
|
||||
buffer[oy + y + (ox + x) * Height] = palval * alphaval / 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t * tcp = &buffer[(ox + x)*4 + (oy + y) * Width*4];
|
||||
int c = (yslice >> (x + x)) & 3;
|
||||
tcp[0] = color[c].b;
|
||||
tcp[1] = color[c].g;
|
||||
tcp[2] = color[c].r;
|
||||
tcp[3] = alpha[((yalphaslice >> (x*3)) & 7)];
|
||||
}
|
||||
}
|
||||
}
|
||||
block += 16;
|
||||
}
|
||||
}
|
||||
delete[] blockbuff;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDDSTexture::CopyPixels
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FDDSTexture::CopyPixels(FBitmap *bmp, int conversion)
|
||||
{
|
||||
auto lump = kopenFileReader(Name, 0);
|
||||
if (!lump.isOpen()) return -1; // Just leave the texture blank.
|
||||
|
||||
uint8_t *TexBuffer = bmp->GetPixels();
|
||||
|
||||
lump.Seek (sizeof(DDSURFACEDESC2) + 4, FileReader::SeekSet);
|
||||
|
||||
if (Format >= 1 && Format <= 4) // RGB: Format is # of bytes per pixel
|
||||
{
|
||||
ReadRGB (lump, TexBuffer, PIX_ARGB);
|
||||
}
|
||||
else if (Format == ID_DXT1)
|
||||
{
|
||||
DecompressDXT1 (lump, TexBuffer, PIX_ARGB);
|
||||
}
|
||||
else if (Format == ID_DXT3 || Format == ID_DXT2)
|
||||
{
|
||||
DecompressDXT3 (lump, Format == ID_DXT2, TexBuffer, PIX_ARGB);
|
||||
}
|
||||
else if (Format == ID_DXT5 || Format == ID_DXT4)
|
||||
{
|
||||
DecompressDXT5 (lump, Format == ID_DXT4, TexBuffer, PIX_ARGB);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
339
source/common/textures/formats/jpegtexture.cpp
Normal file
339
source/common/textures/formats/jpegtexture.cpp
Normal file
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
** jpegtexture.cpp
|
||||
** Texture class for JPEG images
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2006-2007 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "files.h"
|
||||
#include "printf.h"
|
||||
#include "bitmap.h"
|
||||
#include "image.h"
|
||||
#include "cache1d.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <jpeglib.h>
|
||||
}
|
||||
|
||||
|
||||
struct FLumpSourceMgr : public jpeg_source_mgr
|
||||
{
|
||||
FileReader *Lump;
|
||||
JOCTET Buffer[4096];
|
||||
bool StartOfFile;
|
||||
|
||||
FLumpSourceMgr (FileReader *lump, j_decompress_ptr cinfo);
|
||||
static void InitSource (j_decompress_ptr cinfo);
|
||||
static boolean FillInputBuffer (j_decompress_ptr cinfo);
|
||||
static void SkipInputData (j_decompress_ptr cinfo, long num_bytes);
|
||||
static void TermSource (j_decompress_ptr cinfo);
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FLumpSourceMgr::InitSource (j_decompress_ptr cinfo)
|
||||
{
|
||||
((FLumpSourceMgr *)(cinfo->src))->StartOfFile = true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
boolean FLumpSourceMgr::FillInputBuffer (j_decompress_ptr cinfo)
|
||||
{
|
||||
FLumpSourceMgr *me = (FLumpSourceMgr *)(cinfo->src);
|
||||
auto nbytes = me->Lump->Read (me->Buffer, sizeof(me->Buffer));
|
||||
|
||||
if (nbytes <= 0)
|
||||
{
|
||||
me->Buffer[0] = (JOCTET)0xFF;
|
||||
me->Buffer[1] = (JOCTET)JPEG_EOI;
|
||||
nbytes = 2;
|
||||
}
|
||||
me->next_input_byte = me->Buffer;
|
||||
me->bytes_in_buffer = nbytes;
|
||||
me->StartOfFile = false;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FLumpSourceMgr::SkipInputData (j_decompress_ptr cinfo, long num_bytes)
|
||||
{
|
||||
FLumpSourceMgr *me = (FLumpSourceMgr *)(cinfo->src);
|
||||
if (num_bytes <= (long)me->bytes_in_buffer)
|
||||
{
|
||||
me->bytes_in_buffer -= num_bytes;
|
||||
me->next_input_byte += num_bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
num_bytes -= (long)me->bytes_in_buffer;
|
||||
me->Lump->Seek (num_bytes, FileReader::SeekCur);
|
||||
FillInputBuffer (cinfo);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FLumpSourceMgr::TermSource (j_decompress_ptr cinfo)
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FLumpSourceMgr::FLumpSourceMgr (FileReader *lump, j_decompress_ptr cinfo)
|
||||
: Lump (lump)
|
||||
{
|
||||
cinfo->src = this;
|
||||
init_source = InitSource;
|
||||
fill_input_buffer = FillInputBuffer;
|
||||
skip_input_data = SkipInputData;
|
||||
resync_to_restart = jpeg_resync_to_restart;
|
||||
term_source = TermSource;
|
||||
bytes_in_buffer = 0;
|
||||
next_input_byte = NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void JPEG_ErrorExit (j_common_ptr cinfo)
|
||||
{
|
||||
(*cinfo->err->output_message) (cinfo);
|
||||
throw -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void JPEG_OutputMessage (j_common_ptr cinfo)
|
||||
{
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
|
||||
(*cinfo->err->format_message) (cinfo, buffer);
|
||||
Printf (TEXTCOLOR_ORANGE "JPEG failure: %s\n", buffer);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// A JPEG texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FJPEGTexture : public FImageSource
|
||||
{
|
||||
public:
|
||||
FJPEGTexture (int width, int height);
|
||||
|
||||
int CopyPixels(FBitmap *bmp, int conversion) override;
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FImageSource *JPEGImage_TryCreate(FileReader & data)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t dw;
|
||||
uint16_t w[2];
|
||||
uint8_t b[4];
|
||||
} first4bytes;
|
||||
|
||||
data.Seek(0, FileReader::SeekSet);
|
||||
if (data.Read(&first4bytes, 4) < 4) return NULL;
|
||||
|
||||
if (first4bytes.b[0] != 0xFF || first4bytes.b[1] != 0xD8 || first4bytes.b[2] != 0xFF)
|
||||
return NULL;
|
||||
|
||||
// Find the SOFn marker to extract the image dimensions,
|
||||
// where n is 0, 1, or 2 (other types are unsupported).
|
||||
while ((unsigned)first4bytes.b[3] - 0xC0 >= 3)
|
||||
{
|
||||
if (data.Read (first4bytes.w, 2) != 2)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
data.Seek (BigShort(first4bytes.w[0]) - 2, FileReader::SeekCur);
|
||||
if (data.Read (first4bytes.b + 2, 2) != 2 || first4bytes.b[2] != 0xFF)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (data.Read (first4bytes.b, 3) != 3)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (BigShort (first4bytes.w[0]) < 5)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (data.Read (first4bytes.b, 4) != 4)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return new FJPEGTexture (BigShort(first4bytes.w[1]), BigShort(first4bytes.w[0]));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FJPEGTexture::FJPEGTexture (int width, int height)
|
||||
{
|
||||
bMasked = false;
|
||||
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FJPEGTexture::CopyPixels
|
||||
//
|
||||
// Preserves the full color information (unlike software mode)
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FJPEGTexture::CopyPixels(FBitmap *bmp, int conversion)
|
||||
{
|
||||
PalEntry pe[256];
|
||||
|
||||
auto lump = kopenFileReader(Name, 0);
|
||||
if (!lump.isOpen()) return -1; // Just leave the texture blank.
|
||||
|
||||
jpeg_decompress_struct cinfo;
|
||||
jpeg_error_mgr jerr;
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
cinfo.err->output_message = JPEG_OutputMessage;
|
||||
cinfo.err->error_exit = JPEG_ErrorExit;
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
FLumpSourceMgr sourcemgr(&lump, &cinfo);
|
||||
try
|
||||
{
|
||||
jpeg_read_header(&cinfo, TRUE);
|
||||
|
||||
if (!((cinfo.out_color_space == JCS_RGB && cinfo.num_components == 3) ||
|
||||
(cinfo.out_color_space == JCS_CMYK && cinfo.num_components == 4) ||
|
||||
(cinfo.out_color_space == JCS_YCbCr && cinfo.num_components == 3) ||
|
||||
(cinfo.out_color_space == JCS_GRAYSCALE && cinfo.num_components == 1)))
|
||||
{
|
||||
Printf(TEXTCOLOR_ORANGE "Unsupported color format in %s\n", Name.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
jpeg_start_decompress(&cinfo);
|
||||
|
||||
int yc = 0;
|
||||
TArray<uint8_t> buff(cinfo.output_height * cinfo.output_width * cinfo.output_components, true);
|
||||
|
||||
while (cinfo.output_scanline < cinfo.output_height)
|
||||
{
|
||||
uint8_t * ptr = buff.Data() + cinfo.output_width * cinfo.output_components * yc;
|
||||
jpeg_read_scanlines(&cinfo, &ptr, 1);
|
||||
yc++;
|
||||
}
|
||||
|
||||
switch (cinfo.out_color_space)
|
||||
{
|
||||
case JCS_RGB:
|
||||
bmp->CopyPixelDataRGB(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height,
|
||||
3, cinfo.output_width * cinfo.output_components, 0, CF_RGB);
|
||||
break;
|
||||
|
||||
case JCS_GRAYSCALE:
|
||||
for (int i = 0; i < 256; i++) pe[i] = PalEntry(255, i, i, i); // default to a gray map
|
||||
bmp->CopyPixelData(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height,
|
||||
1, cinfo.output_width, 0, pe);
|
||||
break;
|
||||
|
||||
case JCS_CMYK:
|
||||
bmp->CopyPixelDataRGB(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height,
|
||||
4, cinfo.output_width * cinfo.output_components, 0, CF_CMYK);
|
||||
break;
|
||||
|
||||
case JCS_YCbCr:
|
||||
bmp->CopyPixelDataRGB(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height,
|
||||
4, cinfo.output_width * cinfo.output_components, 0, CF_YCbCr);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
}
|
||||
}
|
||||
catch (int)
|
||||
{
|
||||
Printf(TEXTCOLOR_ORANGE "JPEG error in %s\n", Name.GetChars());
|
||||
}
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
return 0;
|
||||
}
|
||||
|
412
source/common/textures/formats/pcxtexture.cpp
Normal file
412
source/common/textures/formats/pcxtexture.cpp
Normal file
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
** pcxtexture.cpp
|
||||
** Texture class for PCX images
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005 David HENRY
|
||||
** Copyright 2006 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
#include "files.h"
|
||||
#include "bitmap.h"
|
||||
#include "image.h"
|
||||
#include "cache1d.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PCX file header
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct PCXHeader
|
||||
{
|
||||
uint8_t manufacturer;
|
||||
uint8_t version;
|
||||
uint8_t encoding;
|
||||
uint8_t bitsPerPixel;
|
||||
|
||||
uint16_t xmin, ymin;
|
||||
uint16_t xmax, ymax;
|
||||
uint16_t horzRes, vertRes;
|
||||
|
||||
uint8_t palette[48];
|
||||
uint8_t reserved;
|
||||
uint8_t numColorPlanes;
|
||||
|
||||
uint16_t bytesPerScanLine;
|
||||
uint16_t paletteType;
|
||||
uint16_t horzSize, vertSize;
|
||||
|
||||
uint8_t padding[54];
|
||||
|
||||
} FORCE_PACKED;
|
||||
#pragma pack()
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// a PCX texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FPCXTexture : public FImageSource
|
||||
{
|
||||
public:
|
||||
FPCXTexture (PCXHeader &);
|
||||
|
||||
int CopyPixels(FBitmap *bmp, int conversion) override;
|
||||
|
||||
protected:
|
||||
void ReadPCX1bit (uint8_t *dst, FileReader & lump, PCXHeader *hdr);
|
||||
void ReadPCX4bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr);
|
||||
void ReadPCX8bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr);
|
||||
void ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr, int planes);
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FImageSource * PCXImage_TryCreate(FileReader & file)
|
||||
{
|
||||
PCXHeader hdr;
|
||||
|
||||
|
||||
file.Seek(0, FileReader::SeekSet);
|
||||
if (file.Read(&hdr, sizeof(hdr)) != sizeof(hdr))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hdr.xmin = LittleShort(hdr.xmin);
|
||||
hdr.xmax = LittleShort(hdr.xmax);
|
||||
hdr.bytesPerScanLine = LittleShort(hdr.bytesPerScanLine);
|
||||
|
||||
if (hdr.manufacturer != 10 || hdr.encoding != 1) return NULL;
|
||||
if (hdr.version != 0 && hdr.version != 2 && hdr.version != 3 && hdr.version != 4 && hdr.version != 5) return NULL;
|
||||
if (hdr.bitsPerPixel != 1 && hdr.bitsPerPixel != 8 && hdr.bitsPerPixel != 4) return NULL;
|
||||
if (hdr.bitsPerPixel == 1 && hdr.numColorPlanes !=1 && hdr.numColorPlanes != 4) return NULL;
|
||||
if (hdr.bitsPerPixel == 8 && hdr.bytesPerScanLine != ((hdr.xmax - hdr.xmin + 2)&~1)) return NULL;
|
||||
|
||||
for (int i = 0; i < 54; i++)
|
||||
{
|
||||
if (hdr.padding[i] != 0) return NULL;
|
||||
}
|
||||
|
||||
file.Seek(0, FileReader::SeekSet);
|
||||
file.Read(&hdr, sizeof(hdr));
|
||||
|
||||
return new FPCXTexture(hdr);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FPCXTexture::FPCXTexture(PCXHeader & hdr)
|
||||
{
|
||||
bMasked = false;
|
||||
Width = LittleShort(hdr.xmax) - LittleShort(hdr.xmin) + 1;
|
||||
Height = LittleShort(hdr.ymax) - LittleShort(hdr.ymin) + 1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FPCXTexture::ReadPCX1bit (uint8_t *dst, FileReader & lump, PCXHeader *hdr)
|
||||
{
|
||||
int y, i, bytes;
|
||||
int rle_count = 0;
|
||||
uint8_t rle_value = 0;
|
||||
|
||||
TArray<uint8_t> srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader));
|
||||
uint8_t * src = srcp.Data();
|
||||
|
||||
for (y = 0; y < Height; ++y)
|
||||
{
|
||||
uint8_t * ptr = &dst[y * Width];
|
||||
|
||||
bytes = hdr->bytesPerScanLine;
|
||||
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if ( (rle_value = *src++) < 0xc0)
|
||||
{
|
||||
rle_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
rle_value = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
|
||||
for (i = 7; i >= 0; --i, ptr ++)
|
||||
{
|
||||
// This can overflow for the last byte if not checked.
|
||||
if (ptr < dst+Width*Height)
|
||||
*ptr = ((rle_value & (1 << i)) > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FPCXTexture::ReadPCX4bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr)
|
||||
{
|
||||
int rle_count = 0, rle_value = 0;
|
||||
int x, y, c;
|
||||
int bytes;
|
||||
TArray<uint8_t> line(hdr->bytesPerScanLine, true);
|
||||
TArray<uint8_t> colorIndex(Width, true);
|
||||
|
||||
TArray<uint8_t> srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader));
|
||||
uint8_t * src = srcp.Data();
|
||||
|
||||
for (y = 0; y < Height; ++y)
|
||||
{
|
||||
uint8_t * ptr = &dst[y * Width];
|
||||
memset (ptr, 0, Width * sizeof (uint8_t));
|
||||
|
||||
for (c = 0; c < 4; ++c)
|
||||
{
|
||||
uint8_t * pLine = line.Data();
|
||||
|
||||
bytes = hdr->bytesPerScanLine;
|
||||
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if ( (rle_value = *src++) < 0xc0)
|
||||
{
|
||||
rle_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
rle_value = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
*(pLine++) = rle_value;
|
||||
}
|
||||
}
|
||||
|
||||
/* compute line's color indexes */
|
||||
for (x = 0; x < Width; ++x)
|
||||
{
|
||||
if (line[x / 8] & (128 >> (x % 8)))
|
||||
ptr[x] += (1 << c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FPCXTexture::ReadPCX8bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr)
|
||||
{
|
||||
int rle_count = 0, rle_value = 0;
|
||||
int y, bytes;
|
||||
|
||||
auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader));
|
||||
uint8_t * src = srcp.Data();
|
||||
|
||||
for (y = 0; y < Height; ++y)
|
||||
{
|
||||
uint8_t * ptr = &dst[y * Width];
|
||||
|
||||
bytes = hdr->bytesPerScanLine;
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if( (rle_value = *src++) < 0xc0)
|
||||
{
|
||||
rle_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
rle_value = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
*ptr++ = rle_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FPCXTexture::ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr, int planes)
|
||||
{
|
||||
int rle_count = 0, rle_value = 0;
|
||||
int y, c;
|
||||
int bytes;
|
||||
|
||||
auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader));
|
||||
uint8_t * src = srcp.Data();
|
||||
|
||||
for (y = 0; y < Height; ++y)
|
||||
{
|
||||
/* for each color plane */
|
||||
for (c = 0; c < planes; ++c)
|
||||
{
|
||||
uint8_t * ptr = &dst[y * Width * planes];
|
||||
bytes = hdr->bytesPerScanLine;
|
||||
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if( (rle_value = *src++) < 0xc0)
|
||||
{
|
||||
rle_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
rle_value = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
ptr[c] = (uint8_t)rle_value;
|
||||
ptr += planes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FPCXTexture::CopyPixels
|
||||
//
|
||||
// Preserves the full color information (unlike software mode)
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FPCXTexture::CopyPixels(FBitmap *bmp, int conversion)
|
||||
{
|
||||
PalEntry pe[256];
|
||||
PCXHeader header;
|
||||
int bitcount;
|
||||
TArray<uint8_t> Pixels;
|
||||
|
||||
auto lump = kopenFileReader(Name, 0);
|
||||
if (!lump.isOpen()) return -1; // Just leave the texture blank.
|
||||
|
||||
lump.Read(&header, sizeof(header));
|
||||
|
||||
bitcount = header.bitsPerPixel * header.numColorPlanes;
|
||||
|
||||
if (bitcount < 24)
|
||||
{
|
||||
Pixels.Resize(Width*Height);
|
||||
if (bitcount < 8)
|
||||
{
|
||||
switch (bitcount)
|
||||
{
|
||||
default:
|
||||
case 1:
|
||||
pe[0] = PalEntry(255, 0, 0, 0);
|
||||
pe[1] = PalEntry(255, 255, 255, 255);
|
||||
ReadPCX1bit (Pixels.Data(), lump, &header);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
for (int i = 0; i<16; i++)
|
||||
{
|
||||
pe[i] = PalEntry(255, header.palette[i * 3], header.palette[i * 3 + 1], header.palette[i * 3 + 2]);
|
||||
}
|
||||
ReadPCX4bits (Pixels.Data(), lump, &header);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (bitcount == 8)
|
||||
{
|
||||
lump.Seek(-769, FileReader::SeekEnd);
|
||||
uint8_t c = lump.ReadUInt8();
|
||||
c=0x0c; // Apparently there's many non-compliant PCXs out there...
|
||||
if (c !=0x0c)
|
||||
{
|
||||
for(int i=0;i<256;i++) pe[i]=PalEntry(255,i,i,i); // default to a gray map
|
||||
}
|
||||
else for(int i=0;i<256;i++)
|
||||
{
|
||||
uint8_t r = lump.ReadUInt8();
|
||||
uint8_t g = lump.ReadUInt8();
|
||||
uint8_t b = lump.ReadUInt8();
|
||||
pe[i] = PalEntry(255, r,g,b);
|
||||
}
|
||||
lump.Seek(sizeof(header), FileReader::SeekSet);
|
||||
ReadPCX8bits (Pixels.Data(), lump, &header);
|
||||
}
|
||||
bmp->CopyPixelData(0, 0, Pixels.Data(), Width, Height, 1, Width, 0, pe);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pixels.Resize(Width*Height*4);
|
||||
ReadPCX24bits (Pixels.Data(), lump, &header, 3);
|
||||
bmp->CopyPixelDataRGB(0, 0, Pixels.Data(), Width, Height, 3, Width*3, 0, CF_RGB);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
364
source/common/textures/formats/pngtexture.cpp
Normal file
364
source/common/textures/formats/pngtexture.cpp
Normal file
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
** pngtexture.cpp
|
||||
** Texture class for PNG images
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2004-2007 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include "files.h"
|
||||
#include "templates.h"
|
||||
#include "m_png.h"
|
||||
#include "bitmap.h"
|
||||
#include "image.h"
|
||||
#include "printf.h"
|
||||
#include "cache1d.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// A PNG texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FPNGTexture : public FImageSource
|
||||
{
|
||||
public:
|
||||
FPNGTexture (FileReader &lump, int width, int height, uint8_t bitdepth, uint8_t colortype, uint8_t interlace);
|
||||
|
||||
int CopyPixels(FBitmap *bmp, int conversion) override;
|
||||
|
||||
protected:
|
||||
uint8_t BitDepth;
|
||||
uint8_t ColorType;
|
||||
uint8_t Interlace;
|
||||
bool HaveTrans;
|
||||
uint16_t NonPaletteTrans[3];
|
||||
|
||||
int PaletteSize = 0;
|
||||
uint32_t StartOfIDAT = 0;
|
||||
uint32_t StartOfPalette = 0;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FImageSource *PNGImage_TryCreate(FileReader & data)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t dw;
|
||||
uint16_t w[2];
|
||||
uint8_t b[4];
|
||||
} first4bytes;
|
||||
|
||||
|
||||
// This is most likely a PNG, but make sure. (Note that if the
|
||||
// first 4 bytes match, but later bytes don't, we assume it's
|
||||
// a corrupt PNG.)
|
||||
|
||||
data.Seek(0, FileReader::SeekSet);
|
||||
if (data.Read (first4bytes.b, 4) != 4) return NULL;
|
||||
if (first4bytes.dw != MAKE_ID(137,'P','N','G')) return NULL;
|
||||
if (data.Read (first4bytes.b, 4) != 4) return NULL;
|
||||
if (first4bytes.dw != MAKE_ID(13,10,26,10)) return NULL;
|
||||
if (data.Read (first4bytes.b, 4) != 4) return NULL;
|
||||
if (first4bytes.dw != MAKE_ID(0,0,0,13)) return NULL;
|
||||
if (data.Read (first4bytes.b, 4) != 4) return NULL;
|
||||
if (first4bytes.dw != MAKE_ID('I','H','D','R')) return NULL;
|
||||
|
||||
// The PNG looks valid so far. Check the IHDR to make sure it's a
|
||||
// type of PNG we support.
|
||||
int width = data.ReadInt32BE();
|
||||
int height = data.ReadInt32BE();
|
||||
uint8_t bitdepth = data.ReadUInt8();
|
||||
uint8_t colortype = data.ReadUInt8();
|
||||
uint8_t compression = data.ReadUInt8();
|
||||
uint8_t filter = data.ReadUInt8();
|
||||
uint8_t interlace = data.ReadUInt8();
|
||||
|
||||
if (compression != 0 || filter != 0 || interlace > 1)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (!((1 << colortype) & 0x5D))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (!((1 << bitdepth) & 0x116))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Just for completeness, make sure the PNG has something more than an IHDR.
|
||||
data.Seek (4, FileReader::SeekSet);
|
||||
data.Read (first4bytes.b, 4);
|
||||
if (first4bytes.dw == 0)
|
||||
{
|
||||
data.Read (first4bytes.b, 4);
|
||||
if (first4bytes.dw == MAKE_ID('I','E','N','D'))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return new FPNGTexture (data, width, height, bitdepth, colortype, interlace);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FPNGTexture::FPNGTexture (FileReader &lump, int width, int height,
|
||||
uint8_t depth, uint8_t colortype, uint8_t interlace)
|
||||
: BitDepth(depth), ColorType(colortype), Interlace(interlace), HaveTrans(false)
|
||||
{
|
||||
uint8_t trans[256];
|
||||
uint32_t len, id;
|
||||
|
||||
bMasked = false;
|
||||
|
||||
Width = width;
|
||||
Height = height;
|
||||
|
||||
memset(trans, 255, 256);
|
||||
|
||||
// Parse pre-IDAT chunks. I skip the CRCs. Is that bad?
|
||||
lump.Seek(33, FileReader::SeekSet);
|
||||
|
||||
lump.Read(&len, 4);
|
||||
lump.Read(&id, 4);
|
||||
while (id != MAKE_ID('I','D','A','T') && id != MAKE_ID('I','E','N','D'))
|
||||
{
|
||||
len = BigLong((unsigned int)len);
|
||||
switch (id)
|
||||
{
|
||||
default:
|
||||
lump.Seek (len, FileReader::SeekCur);
|
||||
break;
|
||||
|
||||
case MAKE_ID('g','r','A','b'):
|
||||
// This is like GRAB found in an ILBM, except coordinates use 4 bytes
|
||||
{
|
||||
uint32_t hotx, hoty;
|
||||
int ihotx, ihoty;
|
||||
|
||||
lump.Read(&hotx, 4);
|
||||
lump.Read(&hoty, 4);
|
||||
ihotx = BigLong((int)hotx);
|
||||
ihoty = BigLong((int)hoty);
|
||||
if (ihotx < -32768 || ihotx > 32767)
|
||||
{
|
||||
Printf ("X-Offset for PNG texture %s is bad: %d (0x%08x)\n", Name.GetChars(), ihotx, ihotx);
|
||||
ihotx = 0;
|
||||
}
|
||||
if (ihoty < -32768 || ihoty > 32767)
|
||||
{
|
||||
Printf ("Y-Offset for PNG texture %s is bad: %d (0x%08x)\n", Name.GetChars(), ihoty, ihoty);
|
||||
ihoty = 0;
|
||||
}
|
||||
LeftOffset = ihotx;
|
||||
TopOffset = ihoty;
|
||||
}
|
||||
break;
|
||||
|
||||
case MAKE_ID('P','L','T','E'):
|
||||
PaletteSize = std::min<int> (len / 3, 256);
|
||||
StartOfPalette = (uint32_t)lump.Tell();
|
||||
break;
|
||||
|
||||
case MAKE_ID('t','R','N','S'):
|
||||
lump.Read (trans, len);
|
||||
HaveTrans = true;
|
||||
// Save for colortype 2
|
||||
NonPaletteTrans[0] = uint16_t(trans[0] * 256 + trans[1]);
|
||||
NonPaletteTrans[1] = uint16_t(trans[2] * 256 + trans[3]);
|
||||
NonPaletteTrans[2] = uint16_t(trans[4] * 256 + trans[5]);
|
||||
break;
|
||||
}
|
||||
lump.Seek(4, FileReader::SeekCur); // Skip CRC
|
||||
lump.Read(&len, 4);
|
||||
id = MAKE_ID('I','E','N','D');
|
||||
lump.Read(&id, 4);
|
||||
}
|
||||
StartOfIDAT = (uint32_t)lump.Tell() - 8;
|
||||
|
||||
switch (colortype)
|
||||
{
|
||||
case 4: // Grayscale + Alpha
|
||||
bMasked = true;
|
||||
break;
|
||||
|
||||
case 0: // Grayscale
|
||||
if (colortype == 0 && HaveTrans && NonPaletteTrans[0] < 256)
|
||||
{
|
||||
bMasked = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // Paletted
|
||||
break;
|
||||
|
||||
case 6: // RGB + Alpha
|
||||
bMasked = true;
|
||||
break;
|
||||
|
||||
case 2: // RGB
|
||||
bMasked = HaveTrans;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FPNGTexture::CopyPixels
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FPNGTexture::CopyPixels(FBitmap *bmp, int conversion)
|
||||
{
|
||||
// Parse pre-IDAT chunks. I skip the CRCs. Is that bad?
|
||||
PalEntry pe[256];
|
||||
uint32_t len, id;
|
||||
static char bpp[] = {1, 0, 3, 1, 2, 0, 4};
|
||||
int pixwidth = Width * bpp[ColorType];
|
||||
int transpal = false;
|
||||
|
||||
FileReader *lump;
|
||||
FileReader lfr;
|
||||
|
||||
lfr = kopenFileReader(Name, 0);
|
||||
if (!lfr.isOpen()) return -1; // Just leave the texture blank.
|
||||
|
||||
lump = 𝔩
|
||||
|
||||
lump->Seek(33, FileReader::SeekSet);
|
||||
for(int i = 0; i < 256; i++) // default to a gray map
|
||||
pe[i] = PalEntry(255,i,i,i);
|
||||
|
||||
lump->Read(&len, 4);
|
||||
lump->Read(&id, 4);
|
||||
while (id != MAKE_ID('I','D','A','T') && id != MAKE_ID('I','E','N','D'))
|
||||
{
|
||||
len = BigLong((unsigned int)len);
|
||||
switch (id)
|
||||
{
|
||||
default:
|
||||
lump->Seek (len, FileReader::SeekCur);
|
||||
break;
|
||||
|
||||
case MAKE_ID('P','L','T','E'):
|
||||
for(int i = 0; i < PaletteSize; i++)
|
||||
{
|
||||
pe[i].r = lump->ReadUInt8();
|
||||
pe[i].g = lump->ReadUInt8();
|
||||
pe[i].b = lump->ReadUInt8();
|
||||
}
|
||||
break;
|
||||
|
||||
case MAKE_ID('t','R','N','S'):
|
||||
if (ColorType == 3)
|
||||
{
|
||||
for(uint32_t i = 0; i < len; i++)
|
||||
{
|
||||
pe[i].a = lump->ReadUInt8();
|
||||
if (pe[i].a != 0 && pe[i].a != 255)
|
||||
transpal = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lump->Seek(len, FileReader::SeekCur);
|
||||
}
|
||||
break;
|
||||
}
|
||||
lump->Seek(4, FileReader::SeekCur); // Skip CRC
|
||||
lump->Read(&len, 4);
|
||||
id = MAKE_ID('I','E','N','D');
|
||||
lump->Read(&id, 4);
|
||||
}
|
||||
|
||||
if (ColorType == 0 && HaveTrans && NonPaletteTrans[0] < 256)
|
||||
{
|
||||
pe[NonPaletteTrans[0]].a = 0;
|
||||
transpal = true;
|
||||
}
|
||||
|
||||
uint8_t * Pixels = new uint8_t[pixwidth * Height];
|
||||
|
||||
lump->Seek (StartOfIDAT, FileReader::SeekSet);
|
||||
lump->Read(&len, 4);
|
||||
lump->Read(&id, 4);
|
||||
M_ReadIDAT (*lump, Pixels, Width, Height, pixwidth, BitDepth, ColorType, Interlace, BigLong((unsigned int)len));
|
||||
|
||||
switch (ColorType)
|
||||
{
|
||||
case 0:
|
||||
case 3:
|
||||
bmp->CopyPixelData(0, 0, Pixels, Width, Height, 1, Width, 0, pe);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (!HaveTrans)
|
||||
{
|
||||
bmp->CopyPixelDataRGB(0, 0, Pixels, Width, Height, 3, pixwidth, 0, CF_RGB);
|
||||
}
|
||||
else
|
||||
{
|
||||
bmp->CopyPixelDataRGB(0, 0, Pixels, Width, Height, 3, pixwidth, 0, CF_RGBT,
|
||||
NonPaletteTrans[0], NonPaletteTrans[1], NonPaletteTrans[2]);
|
||||
transpal = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
bmp->CopyPixelDataRGB(0, 0, Pixels, Width, Height, 2, pixwidth, 0, CF_IA);
|
||||
transpal = -1;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
bmp->CopyPixelDataRGB(0, 0, Pixels, Width, Height, 4, pixwidth, 0, CF_RGBA);
|
||||
transpal = -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
delete[] Pixels;
|
||||
return transpal;
|
||||
}
|
||||
|
||||
|
319
source/common/textures/formats/tgatexture.cpp
Normal file
319
source/common/textures/formats/tgatexture.cpp
Normal file
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
** tgatexture.cpp
|
||||
** Texture class for TGA images
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2006 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include "files.h"
|
||||
#include "templates.h"
|
||||
#include "bitmap.h"
|
||||
#include "image.h"
|
||||
#include "cache1d.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TGA file header
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct TGAHeader
|
||||
{
|
||||
uint8_t id_len;
|
||||
uint8_t has_cm;
|
||||
uint8_t img_type;
|
||||
int16_t cm_first;
|
||||
int16_t cm_length;
|
||||
uint8_t cm_size;
|
||||
|
||||
int16_t x_origin;
|
||||
int16_t y_origin;
|
||||
int16_t width;
|
||||
int16_t height;
|
||||
uint8_t bpp;
|
||||
uint8_t img_desc;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// a TGA texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FTGATexture : public FImageSource
|
||||
{
|
||||
public:
|
||||
FTGATexture (TGAHeader *);
|
||||
|
||||
int CopyPixels(FBitmap *bmp, int conversion) override;
|
||||
|
||||
protected:
|
||||
void ReadCompressed(FileReader &lump, uint8_t * buffer, int bytesperpixel);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FImageSource *TGAImage_TryCreate(FileReader & file)
|
||||
{
|
||||
TGAHeader hdr;
|
||||
|
||||
if (file.GetLength() < (long)sizeof(hdr)) return NULL;
|
||||
|
||||
file.Seek(0, FileReader::SeekSet);
|
||||
file.Read(&hdr, sizeof(hdr));
|
||||
hdr.width = LittleShort(hdr.width);
|
||||
hdr.height = LittleShort(hdr.height);
|
||||
|
||||
// Not much that can be done here because TGA does not have a proper
|
||||
// header to be identified with.
|
||||
if (hdr.has_cm != 0 && hdr.has_cm != 1) return NULL;
|
||||
if (hdr.width <=0 || hdr.height <=0 || hdr.width > 2048 || hdr.height > 2048) return NULL;
|
||||
if (hdr.bpp != 8 && hdr.bpp != 15 && hdr.bpp != 16 && hdr.bpp !=24 && hdr.bpp !=32) return NULL;
|
||||
if (hdr.img_type <= 0 || hdr.img_type > 11) return NULL;
|
||||
if (hdr.img_type >=4 && hdr.img_type <= 8) return NULL;
|
||||
if ((hdr.img_desc & 16) != 0) return NULL;
|
||||
|
||||
file.Seek(0, FileReader::SeekSet);
|
||||
file.Read(&hdr, sizeof(hdr));
|
||||
hdr.width = LittleShort(hdr.width);
|
||||
hdr.height = LittleShort(hdr.height);
|
||||
|
||||
return new FTGATexture(&hdr);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FTGATexture::FTGATexture(TGAHeader * hdr)
|
||||
{
|
||||
Width = hdr->width;
|
||||
Height = hdr->height;
|
||||
// Alpha channel is used only for 32 bit RGBA and paletted images with RGBA palettes.
|
||||
bMasked = (hdr->img_desc&15)==8 && (hdr->bpp==32 || (hdr->img_type==1 && hdr->cm_size==32));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FTGATexture::ReadCompressed(FileReader &lump, uint8_t * buffer, int bytesperpixel)
|
||||
{
|
||||
uint8_t data[4];
|
||||
int Size = Width * Height;
|
||||
|
||||
while (Size > 0)
|
||||
{
|
||||
uint8_t b = lump.ReadUInt8();
|
||||
if (b & 128)
|
||||
{
|
||||
b&=~128;
|
||||
lump.Read(data, bytesperpixel);
|
||||
for (int i=std::min<int>(Size, (b+1)); i>0; i--)
|
||||
{
|
||||
buffer[0] = data[0];
|
||||
if (bytesperpixel>=2) buffer[1] = data[1];
|
||||
if (bytesperpixel>=3) buffer[2] = data[2];
|
||||
if (bytesperpixel==4) buffer[3] = data[3];
|
||||
buffer+=bytesperpixel;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lump.Read(buffer, std::min<int>(Size, (b+1))*bytesperpixel);
|
||||
buffer += (b+1)*bytesperpixel;
|
||||
}
|
||||
Size -= b+1;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTGATexture::CopyPixels
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FTGATexture::CopyPixels(FBitmap *bmp, int conversion)
|
||||
{
|
||||
PalEntry pe[256];
|
||||
auto lump = kopenFileReader(Name, 0);
|
||||
TGAHeader hdr;
|
||||
uint16_t w;
|
||||
uint8_t r,g,b,a;
|
||||
int transval = 0;
|
||||
|
||||
lump.Read(&hdr, sizeof(hdr));
|
||||
lump.Seek(hdr.id_len, FileReader::SeekCur);
|
||||
|
||||
hdr.width = LittleShort(hdr.width);
|
||||
hdr.height = LittleShort(hdr.height);
|
||||
hdr.cm_first = LittleShort(hdr.cm_first);
|
||||
hdr.cm_length = LittleShort(hdr.cm_length);
|
||||
|
||||
if (hdr.has_cm)
|
||||
{
|
||||
memset(pe, 0, 256*sizeof(PalEntry));
|
||||
for (int i = hdr.cm_first; i < hdr.cm_first + hdr.cm_length && i < 256; i++)
|
||||
{
|
||||
switch (hdr.cm_size)
|
||||
{
|
||||
case 15:
|
||||
case 16:
|
||||
w = lump.ReadUInt16();
|
||||
r = (w & 0x001F) << 3;
|
||||
g = (w & 0x03E0) >> 2;
|
||||
b = (w & 0x7C00) >> 7;
|
||||
a = 255;
|
||||
break;
|
||||
|
||||
case 24:
|
||||
b = lump.ReadUInt8();
|
||||
g = lump.ReadUInt8();
|
||||
r = lump.ReadUInt8();
|
||||
a = 255;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
b = lump.ReadUInt8();
|
||||
g = lump.ReadUInt8();
|
||||
r = lump.ReadUInt8();
|
||||
a = lump.ReadUInt8();
|
||||
if ((hdr.img_desc & 15) != 8) a = 255;
|
||||
else if (a != 0 && a != 255) transval = true;
|
||||
break;
|
||||
|
||||
default: // should never happen
|
||||
r=g=b=a=0;
|
||||
break;
|
||||
}
|
||||
pe[i] = PalEntry(a, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
int Size = Width * Height * (hdr.bpp>>3);
|
||||
TArray<uint8_t> sbuffer(Size);
|
||||
|
||||
if (hdr.img_type < 4) // uncompressed
|
||||
{
|
||||
lump.Read(sbuffer.Data(), Size);
|
||||
}
|
||||
else // compressed
|
||||
{
|
||||
ReadCompressed(lump, sbuffer.Data(), hdr.bpp>>3);
|
||||
}
|
||||
|
||||
uint8_t * ptr = sbuffer.Data();
|
||||
int step_x = (hdr.bpp>>3);
|
||||
int Pitch = Width * step_x;
|
||||
|
||||
/*
|
||||
if (hdr.img_desc&32)
|
||||
{
|
||||
ptr += (Width-1) * step_x;
|
||||
step_x =- step_x;
|
||||
}
|
||||
*/
|
||||
if (!(hdr.img_desc&32))
|
||||
{
|
||||
ptr += (Height-1) * Pitch;
|
||||
Pitch = -Pitch;
|
||||
}
|
||||
|
||||
switch (hdr.img_type & 7)
|
||||
{
|
||||
case 1: // paletted
|
||||
bmp->CopyPixelData(0, 0, ptr, Width, Height, step_x, Pitch, 0, pe);
|
||||
break;
|
||||
|
||||
case 2: // RGB
|
||||
switch (hdr.bpp)
|
||||
{
|
||||
case 15:
|
||||
case 16:
|
||||
bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_RGB555);
|
||||
break;
|
||||
|
||||
case 24:
|
||||
bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_BGR);
|
||||
break;
|
||||
|
||||
case 32:
|
||||
if ((hdr.img_desc&15)!=8) // 32 bits without a valid alpha channel
|
||||
{
|
||||
bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_BGR);
|
||||
}
|
||||
else
|
||||
{
|
||||
bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_BGRA);
|
||||
transval = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // Grayscale
|
||||
switch (hdr.bpp)
|
||||
{
|
||||
case 8:
|
||||
for(int i=0;i<256;i++) pe[i]=PalEntry(255,i,i,i); // gray map
|
||||
bmp->CopyPixelData(0, 0, ptr, Width, Height, step_x, Pitch, 0, pe);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_I16);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return transval;
|
||||
}
|
130
source/common/textures/image.cpp
Normal file
130
source/common/textures/image.cpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
** texture.cpp
|
||||
** The base texture class
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2004-2007 Randy Heit
|
||||
** Copyright 2006-2018 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include "memarena.h"
|
||||
#include "bitmap.h"
|
||||
#include "image.h"
|
||||
#include "files.h"
|
||||
#include "cache1d.h"
|
||||
|
||||
int FImageSource::NextID;
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// the default just returns an empty texture.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
TArray<uint8_t> FImageSource::CreatePalettedPixels(int conversion)
|
||||
{
|
||||
TArray<uint8_t> Pixels(Width * Height, true);
|
||||
memset(Pixels.Data(), 0, Width * Height);
|
||||
return Pixels;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FImageSource::CopyPixels
|
||||
//
|
||||
// this is the generic case that can handle
|
||||
// any properly implemented texture for software rendering.
|
||||
// Its drawback is that it is limited to the base palette which is
|
||||
// why all classes that handle different palettes should subclass this
|
||||
// method
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FImageSource::CopyTranslatedPixels(FBitmap *bmp, PalEntry *remap)
|
||||
{
|
||||
auto ppix = CreatePalettedPixels(false);
|
||||
bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, remap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FImageSource::CopyPixels(FBitmap* bmp, int conversion)
|
||||
{
|
||||
return CopyTranslatedPixels(bmp, nullptr); // This should never get called for ART tiles.
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
typedef FImageSource * (*CreateFunc)(FileReader & file);
|
||||
|
||||
struct TexCreateInfo
|
||||
{
|
||||
CreateFunc TryCreate;
|
||||
};
|
||||
|
||||
FImageSource *PNGImage_TryCreate(FileReader &);
|
||||
FImageSource *JPEGImage_TryCreate(FileReader &);
|
||||
FImageSource *DDSImage_TryCreate(FileReader &);
|
||||
FImageSource *PCXImage_TryCreate(FileReader &);
|
||||
FImageSource *TGAImage_TryCreate(FileReader &);
|
||||
|
||||
|
||||
// Examines the lump contents to decide what type of texture to create,
|
||||
// and creates the texture.
|
||||
FImageSource * FImageSource::GetImage(const char *name)
|
||||
{
|
||||
static TexCreateInfo CreateInfo[] = {
|
||||
{ PNGImage_TryCreate },
|
||||
{ JPEGImage_TryCreate },
|
||||
{ DDSImage_TryCreate },
|
||||
{ PCXImage_TryCreate },
|
||||
{ TGAImage_TryCreate },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
auto data = kopenFileReader(name, 0);
|
||||
if (!data.isOpen()) return nullptr;
|
||||
|
||||
for (size_t i = 0; CreateInfo[i].TryCreate; i++)
|
||||
{
|
||||
auto image = CreateInfo[i].TryCreate(data);
|
||||
if (image != nullptr)
|
||||
{
|
||||
image->Name = name;
|
||||
return image;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
138
source/common/textures/image.h
Normal file
138
source/common/textures/image.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "zstring.h"
|
||||
#include "tarray.h"
|
||||
#include "textures.h"
|
||||
#include "bitmap.h"
|
||||
#include "memarena.h"
|
||||
|
||||
class FImageSource;
|
||||
using PrecacheInfo = TMap<int, std::pair<int, int>>;
|
||||
|
||||
struct PalettedPixels
|
||||
{
|
||||
friend class FImageSource;
|
||||
TArrayView<uint8_t> Pixels;
|
||||
private:
|
||||
TArray<uint8_t> PixelStore;
|
||||
|
||||
bool ownsPixels() const
|
||||
{
|
||||
return Pixels.Data() == PixelStore.Data();
|
||||
}
|
||||
};
|
||||
|
||||
// This represents a naked image. It has no high level logic attached to it.
|
||||
// All it can do is provide raw image data to its users.
|
||||
class FImageSource
|
||||
{
|
||||
protected:
|
||||
|
||||
static int NextID;
|
||||
|
||||
int SourceLump;
|
||||
int Width = 0, Height = 0;
|
||||
int LeftOffset = 0, TopOffset = 0; // Offsets stored in the image.
|
||||
bool bUseGamePalette = false; // true if this is an image without its own color set.
|
||||
int ImageID = -1;
|
||||
FString Name;
|
||||
|
||||
// Internal image creation functions. All external access should go through the cache interface,
|
||||
// so that all code can benefit from future improvements to that.
|
||||
|
||||
public:
|
||||
|
||||
virtual ~FImageSource() = default;
|
||||
void CopySize(FImageSource &other)
|
||||
{
|
||||
Width = other.Width;
|
||||
Height = other.Height;
|
||||
LeftOffset = other.LeftOffset;
|
||||
TopOffset = other.TopOffset;
|
||||
SourceLump = other.SourceLump;
|
||||
}
|
||||
|
||||
bool bMasked = true; // Image (might) have holes (Assume true unless proven otherwise!)
|
||||
int8_t bTranslucent = -1; // Image has pixels with a non-0/1 value. (-1 means the user needs to do a real check)
|
||||
|
||||
int GetId() const { return ImageID; }
|
||||
|
||||
// 'noremap0' will only be looked at by FPatchTexture and forwarded by FMultipatchTexture.
|
||||
static FImageSource * GetImage(const char *name);
|
||||
|
||||
virtual TArray<uint8_t> CreatePalettedPixels(int conversion);
|
||||
virtual int CopyPixels(FBitmap* bmp, int conversion); // This will always ignore 'luminance'.
|
||||
int CopyTranslatedPixels(FBitmap* bmp, PalEntry* remap);
|
||||
|
||||
|
||||
// Conversion option
|
||||
enum EType
|
||||
{
|
||||
normal = 0,
|
||||
luminance = 1,
|
||||
noremap0 = 2
|
||||
};
|
||||
|
||||
FImageSource(int sourcelump = -1) : SourceLump(sourcelump) { ImageID = ++NextID; }
|
||||
|
||||
int GetWidth() const
|
||||
{
|
||||
return Width;
|
||||
}
|
||||
|
||||
int GetHeight() const
|
||||
{
|
||||
return Height;
|
||||
}
|
||||
|
||||
std::pair<int, int> GetSize() const
|
||||
{
|
||||
return std::make_pair(Width, Height);
|
||||
}
|
||||
|
||||
std::pair<int, int> GetOffsets() const
|
||||
{
|
||||
return std::make_pair(LeftOffset, TopOffset);
|
||||
}
|
||||
|
||||
void SetOffsets(int x, int y)
|
||||
{
|
||||
LeftOffset = x;
|
||||
TopOffset = y;
|
||||
}
|
||||
|
||||
int LumpNum() const
|
||||
{
|
||||
return SourceLump;
|
||||
}
|
||||
|
||||
bool UseGamePalette() const
|
||||
{
|
||||
return bUseGamePalette;
|
||||
}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// a TGA texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FImageTexture : public FTexture
|
||||
{
|
||||
FImageSource *mImage;
|
||||
public:
|
||||
FImageTexture (FImageSource *image, const char *name = nullptr);
|
||||
virtual TArray<uint8_t> Get8BitPixels(bool alphatex);
|
||||
|
||||
void SetImage(FImageSource *img) // This is only for the multipatch texture builder!
|
||||
{
|
||||
mImage = img;
|
||||
}
|
||||
|
||||
FImageSource *GetImage() const override { return mImage; }
|
||||
FBitmap GetBgraBitmap(PalEntry *p, int *trans) override;
|
||||
|
||||
};
|
||||
|
89
source/common/textures/imagetexture.cpp
Normal file
89
source/common/textures/imagetexture.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
** imagetexture.cpp
|
||||
** Texture class based on FImageSource
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2018 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include "files.h"
|
||||
#include "templates.h"
|
||||
#include "bitmap.h"
|
||||
#include "image.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FImageTexture::FImageTexture(FImageSource *img, const char *name)
|
||||
: FTexture(name)
|
||||
{
|
||||
mImage = img;
|
||||
if (img != nullptr)
|
||||
{
|
||||
Width = img->GetWidth();
|
||||
Height = img->GetHeight();
|
||||
|
||||
auto offsets = img->GetOffsets();
|
||||
LeftOffset = offsets.first;
|
||||
TopOffset = offsets.second;
|
||||
|
||||
bMasked = img->bMasked;
|
||||
bTranslucent = img->bTranslucent;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FBitmap FImageTexture::GetBgraBitmap(PalEntry *p, int *trans)
|
||||
{
|
||||
FBitmap bmp;
|
||||
mImage->CopyPixels(&bmp, 0); // Todo: Handle translations.
|
||||
return bmp;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
TArray<uint8_t> FImageTexture::Get8BitPixels(bool alpha)
|
||||
{
|
||||
return mImage->CreatePalettedPixels(0);
|
||||
}
|
||||
|
63
source/common/textures/skyboxtexture.cpp
Normal file
63
source/common/textures/skyboxtexture.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2004-2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include "filesystem.h"
|
||||
#include "textures.h"
|
||||
#include "skyboxtexture.h"
|
||||
#include "bitmap.h"
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
FSkyBox::FSkyBox(const char *name)
|
||||
: FTexture(name)
|
||||
{
|
||||
bSkybox = true;
|
||||
fliptop = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
FBitmap FSkyBox::GetBgraBitmap(PalEntry *p, int *trans)
|
||||
{
|
||||
return faces[0]->GetBgraBitmap(p, trans);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
FImageSource *FSkyBox::GetImage() const
|
||||
{
|
||||
return faces[0]->GetImage();
|
||||
}
|
37
source/common/textures/skyboxtexture.h
Normal file
37
source/common/textures/skyboxtexture.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "textures.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// This is not a real texture but will be added to the texture manager
|
||||
// so that it can be handled like any other sky.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class FSkyBox : public FTexture
|
||||
{
|
||||
public:
|
||||
|
||||
FTexture* faces[6] = {};
|
||||
bool fliptop;
|
||||
|
||||
FSkyBox(const char *name);
|
||||
FBitmap GetBgraBitmap(PalEntry *, int *trans) override;
|
||||
FImageSource *GetImage() const override;
|
||||
|
||||
|
||||
void SetSize()
|
||||
{
|
||||
CopySize(faces[0]);
|
||||
}
|
||||
|
||||
bool Is3Face() const
|
||||
{
|
||||
return faces[5] == nullptr;
|
||||
}
|
||||
|
||||
bool IsFlipped() const
|
||||
{
|
||||
return fliptop;
|
||||
}
|
||||
};
|
419
source/common/textures/texture.cpp
Normal file
419
source/common/textures/texture.cpp
Normal file
|
@ -0,0 +1,419 @@
|
|||
/*
|
||||
** texture.cpp
|
||||
** The base texture class
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2004-2007 Randy Heit
|
||||
** Copyright 2006-2018 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include "files.h"
|
||||
#include "templates.h"
|
||||
|
||||
#include "bitmap.h"
|
||||
#include "image.h"
|
||||
|
||||
FTexture *CreateBrightmapTexture(FImageSource*);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
||||
// Examines the lump contents to decide what type of texture to create,
|
||||
// and creates the texture.
|
||||
FTexture * FTexture::CreateTexture(const char *name)
|
||||
{
|
||||
auto image = FImageSource::GetImage(name);
|
||||
if (image != nullptr)
|
||||
{
|
||||
FTexture *tex = new FImageTexture(image);
|
||||
if (tex != nullptr)
|
||||
{
|
||||
tex->Name = name;
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FTexture::FTexture (const char *name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
FTexture::~FTexture ()
|
||||
{
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTexture::GetBgraBitmap
|
||||
//
|
||||
// Default returns just an empty bitmap. This needs to be overridden by
|
||||
// any subclass that actually does return a software pixel buffer.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FBitmap FTexture::GetBgraBitmap(PalEntry *remap, int *ptrans)
|
||||
{
|
||||
FBitmap bmp;
|
||||
bmp.Create(Width, Height);
|
||||
return bmp;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Gets the average color of a texture for use as a sky cap color
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
#define APART(c) (((c)>>24)&0xff)
|
||||
#define RPART(c) (((c)>>16)&0xff)
|
||||
#define GPART(c) (((c)>>8)&0xff)
|
||||
#define BPART(c) ((c)&0xff)
|
||||
|
||||
PalEntry FTexture::averageColor(const uint32_t *data, int size, int maxout)
|
||||
{
|
||||
int i;
|
||||
unsigned int r, g, b;
|
||||
|
||||
// First clear them.
|
||||
r = g = b = 0;
|
||||
if (size == 0)
|
||||
{
|
||||
return PalEntry(255, 255, 255);
|
||||
}
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
b += BPART(data[i]);
|
||||
g += GPART(data[i]);
|
||||
r += RPART(data[i]);
|
||||
}
|
||||
|
||||
r = r / size;
|
||||
g = g / size;
|
||||
b = b / size;
|
||||
|
||||
int maxv = std::max(std::max(r, g), b);
|
||||
|
||||
if (maxv && maxout)
|
||||
{
|
||||
r = uint64_t(r) * maxout / maxv;
|
||||
g = uint64_t(g) * maxout / maxv;
|
||||
b = uint64_t(b) * maxout / maxv;
|
||||
}
|
||||
return PalEntry(255, r, g, b);
|
||||
}
|
||||
|
||||
PalEntry FTexture::GetSkyCapColor(bool bottom)
|
||||
{
|
||||
if (!skyColorDone)
|
||||
{
|
||||
skyColorDone = true;
|
||||
|
||||
FBitmap bitmap = GetBgraBitmap(nullptr);
|
||||
int w = bitmap.GetWidth();
|
||||
int h = bitmap.GetHeight();
|
||||
|
||||
const uint32_t *buffer = (const uint32_t *)bitmap.GetPixels();
|
||||
if (buffer)
|
||||
{
|
||||
CeilingSkyColor = averageColor((uint32_t *)buffer, w * std::min(30, h), 0);
|
||||
if (h>30)
|
||||
{
|
||||
FloorSkyColor = averageColor(((uint32_t *)buffer) + (h - 30)*w, w * 30, 0);
|
||||
}
|
||||
else FloorSkyColor = CeilingSkyColor;
|
||||
}
|
||||
}
|
||||
return bottom ? FloorSkyColor : CeilingSkyColor;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void FTexture::CheckTrans(unsigned char * buffer, int size, int trans)
|
||||
{
|
||||
if (bTranslucent == -1)
|
||||
{
|
||||
bTranslucent = trans;
|
||||
if (trans == -1)
|
||||
{
|
||||
uint32_t * dwbuf = (uint32_t*)buffer;
|
||||
for (int i = 0; i<size; i++)
|
||||
{
|
||||
uint32_t alpha = dwbuf[i] >> 24;
|
||||
|
||||
if (alpha != 0xff && alpha != 0)
|
||||
{
|
||||
bTranslucent = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
bTranslucent = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// smooth the edges of transparent fields in the texture
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define MSB 0
|
||||
#define SOME_MASK 0xffffff00
|
||||
#else
|
||||
#define MSB 3
|
||||
#define SOME_MASK 0x00ffffff
|
||||
#endif
|
||||
|
||||
#define CHKPIX(ofs) (l1[(ofs)*4+MSB]==255 ? (( ((uint32_t*)l1)[0] = ((uint32_t*)l1)[ofs]&SOME_MASK), trans=true ) : false)
|
||||
|
||||
int FTexture::SmoothEdges(unsigned char * buffer, int w, int h)
|
||||
{
|
||||
int x, y;
|
||||
int trans = buffer[MSB] == 0; // If I set this to false here the code won't detect textures
|
||||
// that only contain transparent pixels.
|
||||
int semitrans = false;
|
||||
unsigned char * l1;
|
||||
|
||||
if (h <= 1 || w <= 1) return false; // makes (a) no sense and (b) doesn't work with this code!
|
||||
|
||||
l1 = buffer;
|
||||
|
||||
|
||||
if (l1[MSB] == 0 && !CHKPIX(1)) CHKPIX(w);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
l1 += 4;
|
||||
for (x = 1; x<w - 1; x++, l1 += 4)
|
||||
{
|
||||
if (l1[MSB] == 0 && !CHKPIX(-1) && !CHKPIX(1)) CHKPIX(w);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
}
|
||||
if (l1[MSB] == 0 && !CHKPIX(-1)) CHKPIX(w);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
l1 += 4;
|
||||
|
||||
for (y = 1; y<h - 1; y++)
|
||||
{
|
||||
if (l1[MSB] == 0 && !CHKPIX(-w) && !CHKPIX(1)) CHKPIX(w);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
l1 += 4;
|
||||
for (x = 1; x<w - 1; x++, l1 += 4)
|
||||
{
|
||||
if (l1[MSB] == 0 && !CHKPIX(-w) && !CHKPIX(-1) && !CHKPIX(1) && !CHKPIX(-w - 1) && !CHKPIX(-w + 1) && !CHKPIX(w - 1) && !CHKPIX(w + 1)) CHKPIX(w);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
}
|
||||
if (l1[MSB] == 0 && !CHKPIX(-w) && !CHKPIX(-1)) CHKPIX(w);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
l1 += 4;
|
||||
}
|
||||
|
||||
if (l1[MSB] == 0 && !CHKPIX(-w)) CHKPIX(1);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
l1 += 4;
|
||||
for (x = 1; x<w - 1; x++, l1 += 4)
|
||||
{
|
||||
if (l1[MSB] == 0 && !CHKPIX(-w) && !CHKPIX(-1)) CHKPIX(1);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
}
|
||||
if (l1[MSB] == 0 && !CHKPIX(-w)) CHKPIX(-1);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
|
||||
return trans || (semitrans << 1);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Post-process the texture data after the buffer has been created
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FTexture::ProcessData(unsigned char * buffer, int w, int h, bool ispatch)
|
||||
{
|
||||
if (bMasked)
|
||||
{
|
||||
int res = SmoothEdges(buffer, w, h);
|
||||
bMasked = !!(res & 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Initializes the buffer for the texture data
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
|
||||
{
|
||||
FTextureBuffer result;
|
||||
|
||||
unsigned char * buffer = nullptr;
|
||||
int W, H;
|
||||
int isTransparent = -1;
|
||||
bool checkonly = !!(flags & CTF_CheckOnly);
|
||||
|
||||
#if 0
|
||||
if (flags & CTF_CheckHires)
|
||||
{
|
||||
// No image means that this cannot be checked,
|
||||
if (GetImage() && LoadHiresTexture(result, checkonly)) return result;
|
||||
}
|
||||
#endif
|
||||
int exx = !!(flags & CTF_Expand);
|
||||
|
||||
W = GetWidth() + 2 * exx;
|
||||
H = GetHeight() + 2 * exx;
|
||||
|
||||
if (!checkonly)
|
||||
{
|
||||
buffer = new unsigned char[W*(H + 1) * 4];
|
||||
memset(buffer, 0, W * (H + 1) * 4);
|
||||
|
||||
auto remap = nullptr;// translation <= 0 ? nullptr : FUniquePalette::GetPalette(translation);
|
||||
FBitmap bmp(buffer, W * 4, W, H);
|
||||
|
||||
int trans;
|
||||
auto Pixels = GetBgraBitmap(remap, &trans);
|
||||
bmp.Blit(exx, exx, Pixels);
|
||||
|
||||
if (remap == nullptr)
|
||||
{
|
||||
CheckTrans(buffer, W*H, trans);
|
||||
isTransparent = bTranslucent;
|
||||
}
|
||||
else
|
||||
{
|
||||
isTransparent = 0;
|
||||
// A translated image is not conclusive for setting the texture's transparency info.
|
||||
}
|
||||
}
|
||||
|
||||
if (GetImage())
|
||||
{
|
||||
FContentIdBuilder builder;
|
||||
builder.id = 0;
|
||||
builder.imageID = GetImage()->GetId();
|
||||
builder.translation = std::max(0, translation);
|
||||
builder.expand = exx;
|
||||
result.mContentId = builder.id;
|
||||
}
|
||||
else result.mContentId = 0; // for non-image backed textures this has no meaning so leave it at 0.
|
||||
|
||||
result.mBuffer = buffer;
|
||||
result.mWidth = W;
|
||||
result.mHeight = H;
|
||||
|
||||
// Only do postprocessing for image-backed textures. (i.e. not for the burn texture which can also pass through here.)
|
||||
if (GetImage() && flags & CTF_ProcessData)
|
||||
{
|
||||
#if 0
|
||||
CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly);
|
||||
#endif
|
||||
if (!checkonly) ProcessData(result.mBuffer, result.mWidth, result.mHeight, false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Dummy texture for the 0-entry.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FTexture::GetTranslucency()
|
||||
{
|
||||
if (bTranslucent == -1)
|
||||
{
|
||||
if (true)//!bHasCanvas)
|
||||
{
|
||||
// This will calculate all we need, so just discard the result.
|
||||
CreateTexBuffer(0);
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
bTranslucent = 0;
|
||||
}*/
|
||||
}
|
||||
return !!bTranslucent;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// the default just returns an empty texture.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
TArray<uint8_t> FTexture::Get8BitPixels(bool alphatex)
|
||||
{
|
||||
TArray<uint8_t> Pixels(Width * Height, true);
|
||||
memset(Pixels.Data(), 0, Width * Height);
|
||||
return Pixels;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FWrapperTexture::FWrapperTexture(int w, int h, int bits)
|
||||
{
|
||||
Width = w;
|
||||
Height = h;
|
||||
Format = bits;
|
||||
UseType = ETextureType::SWCanvas;
|
||||
bNoCompress = true;
|
||||
auto hwtex = screen->CreateHardwareTexture();
|
||||
// todo: Initialize here.
|
||||
SystemTextures.AddHardwareTexture(0, false, hwtex);
|
||||
}
|
||||
|
||||
#endif
|
36
source/common/textures/textureid.h
Normal file
36
source/common/textures/textureid.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
class FTextureID
|
||||
{
|
||||
friend class FTextureManager;
|
||||
|
||||
public:
|
||||
FTextureID() = default;
|
||||
bool isNull() const { return texnum == 0; }
|
||||
bool isValid() const { return texnum > 0; }
|
||||
bool Exists() const { return texnum >= 0; }
|
||||
void SetInvalid() { texnum = -1; }
|
||||
void SetNull() { texnum = 0; }
|
||||
bool operator ==(const FTextureID &other) const { return texnum == other.texnum; }
|
||||
bool operator !=(const FTextureID &other) const { return texnum != other.texnum; }
|
||||
FTextureID operator +(int offset) throw();
|
||||
int GetIndex() const { return texnum; } // Use this only if you absolutely need the index!
|
||||
|
||||
// The switch list needs these to sort the switches by texture index
|
||||
int operator -(FTextureID other) const { return texnum - other.texnum; }
|
||||
bool operator < (FTextureID other) const { return texnum < other.texnum; }
|
||||
bool operator > (FTextureID other) const { return texnum > other.texnum; }
|
||||
|
||||
protected:
|
||||
FTextureID(int num) { texnum = num; }
|
||||
private:
|
||||
int texnum;
|
||||
};
|
||||
|
||||
// This is for the script interface which needs to do casts from int to texture.
|
||||
class FSetTextureID : public FTextureID
|
||||
{
|
||||
public:
|
||||
FSetTextureID(int v) : FTextureID(v) {}
|
||||
};
|
||||
|
198
source/common/textures/textures.h
Normal file
198
source/common/textures/textures.h
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
** textures.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005-2016 Randy Heit
|
||||
** Copyright 2005-2016 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __TEXTURES_H
|
||||
#define __TEXTURES_H
|
||||
|
||||
#include "textureid.h"
|
||||
#include "palentry.h"
|
||||
/*
|
||||
#include "v_palette.h"
|
||||
#include "r_data/v_colortables.h"
|
||||
#include "colormatcher.h"
|
||||
#include "r_data/renderstyle.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "hwrenderer/textures/hw_texcontainer.h"
|
||||
*/
|
||||
#include <vector>
|
||||
|
||||
class FImageSource;
|
||||
|
||||
enum ECreateTexBufferFlags
|
||||
{
|
||||
CTF_CheckHires = 1, // use external hires replacement if found
|
||||
CTF_Expand = 2, // create buffer with a one-pixel wide border
|
||||
CTF_ProcessData = 4, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture.
|
||||
CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures.
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FBitmap;
|
||||
struct FRemapTable;
|
||||
struct FCopyInfo;
|
||||
class FScanner;
|
||||
|
||||
// Texture IDs
|
||||
class FTextureManager;
|
||||
class FTerrainTypeArray;
|
||||
class IHardwareTexture;
|
||||
class FMaterial;
|
||||
class FMultipatchTextureBuilder;
|
||||
|
||||
extern int r_spriteadjustSW, r_spriteadjustHW;
|
||||
|
||||
class FNullTextureID : public FTextureID
|
||||
{
|
||||
public:
|
||||
FNullTextureID() : FTextureID(0) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FGLRenderState;
|
||||
|
||||
class FSerializer;
|
||||
namespace OpenGLRenderer
|
||||
{
|
||||
class FGLRenderState;
|
||||
class FHardwareTexture;
|
||||
}
|
||||
|
||||
union FContentIdBuilder
|
||||
{
|
||||
uint64_t id;
|
||||
struct
|
||||
{
|
||||
unsigned imageID : 24;
|
||||
unsigned translation : 16;
|
||||
unsigned expand : 1;
|
||||
unsigned scaler : 4;
|
||||
unsigned scalefactor : 4;
|
||||
};
|
||||
};
|
||||
|
||||
struct FTextureBuffer
|
||||
{
|
||||
uint8_t *mBuffer = nullptr;
|
||||
int mWidth = 0;
|
||||
int mHeight = 0;
|
||||
uint64_t mContentId = 0; // unique content identifier. (Two images created from the same image source with the same settings will return the same value.)
|
||||
|
||||
FTextureBuffer() = default;
|
||||
|
||||
~FTextureBuffer()
|
||||
{
|
||||
if (mBuffer) delete[] mBuffer;
|
||||
}
|
||||
|
||||
FTextureBuffer(const FTextureBuffer &other) = delete;
|
||||
FTextureBuffer(FTextureBuffer &&other)
|
||||
{
|
||||
mBuffer = other.mBuffer;
|
||||
mWidth = other.mWidth;
|
||||
mHeight = other.mHeight;
|
||||
mContentId = other.mContentId;
|
||||
other.mBuffer = nullptr;
|
||||
}
|
||||
|
||||
FTextureBuffer& operator=(FTextureBuffer &&other)
|
||||
{
|
||||
mBuffer = other.mBuffer;
|
||||
mWidth = other.mWidth;
|
||||
mHeight = other.mHeight;
|
||||
mContentId = other.mContentId;
|
||||
other.mBuffer = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Base texture class
|
||||
class FTexture
|
||||
{
|
||||
|
||||
public:
|
||||
static FTexture *CreateTexture(const char *name);
|
||||
virtual ~FTexture ();
|
||||
virtual FImageSource *GetImage() const { return nullptr; }
|
||||
|
||||
const FString &GetName() const { return Name; }
|
||||
bool isMasked() const { return bMasked; }
|
||||
bool isTranslucent() const { return bMasked; }
|
||||
PalEntry GetSkyCapColor(bool bottom);
|
||||
|
||||
// Returns the whole texture, stored in column-major order
|
||||
virtual TArray<uint8_t> Get8BitPixels(bool alphatex);
|
||||
virtual FBitmap GetBgraBitmap(PalEntry *remap, int *trans = nullptr);
|
||||
|
||||
static int SmoothEdges(unsigned char * buffer,int w, int h);
|
||||
static PalEntry averageColor(const uint32_t *data, int size, int maxout);
|
||||
|
||||
int GetWidth() { return Width; }
|
||||
int GetHeight() { return Height; }
|
||||
int GetLeftOffset() { return LeftOffset; }
|
||||
int GetTopOffset() { return TopOffset; }
|
||||
FTextureBuffer CreateTexBuffer(int translation, int flags = 0);
|
||||
bool GetTranslucency();
|
||||
void CheckTrans(unsigned char * buffer, int size, int trans);
|
||||
bool ProcessData(unsigned char * buffer, int w, int h, bool ispatch);
|
||||
|
||||
protected:
|
||||
|
||||
void CopySize(FTexture *BaseTexture)
|
||||
{
|
||||
Width = BaseTexture->GetWidth();
|
||||
Height = BaseTexture->GetHeight();
|
||||
TopOffset = BaseTexture->TopOffset;
|
||||
TopOffset = BaseTexture->TopOffset;
|
||||
}
|
||||
|
||||
int Width = 0, Height = 0;
|
||||
int LeftOffset = 0, TopOffset = 0;
|
||||
FString Name;
|
||||
uint8_t bMasked = true; // Texture (might) have holes
|
||||
int8_t bTranslucent = -1; // Does this texture have an active alpha channel?
|
||||
bool skyColorDone = false;
|
||||
PalEntry FloorSkyColor;
|
||||
PalEntry CeilingSkyColor;
|
||||
|
||||
FTexture (const char *name = NULL);
|
||||
};
|
||||
|
||||
extern TMap<FString, FTexture *> textures;
|
||||
|
||||
#endif
|
||||
|
||||
|
52
source/common/utility/m_crc32.h
Normal file
52
source/common/utility/m_crc32.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
** m_crc32.h
|
||||
** Simple interface to zlib's CRC table
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2006 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <zlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// zlib includes some CRC32 stuff, so just use that
|
||||
|
||||
inline const uint32_t *GetCRCTable () { return (const uint32_t *)get_crc_table(); }
|
||||
inline uint32_t CalcCRC32 (const uint8_t *buf, unsigned int len)
|
||||
{
|
||||
return crc32 (0, buf, len);
|
||||
}
|
||||
inline uint32_t AddCRC32 (uint32_t crc, const uint8_t *buf, unsigned int len)
|
||||
{
|
||||
return crc32 (crc, buf, len);
|
||||
}
|
||||
inline uint32_t CRC1 (uint32_t crc, const uint8_t c, const uint32_t *crcTable)
|
||||
{
|
||||
return crcTable[(crc & 0xff) ^ c] ^ (crc >> 8);
|
||||
}
|
1282
source/common/utility/m_png.cpp
Normal file
1282
source/common/utility/m_png.cpp
Normal file
File diff suppressed because it is too large
Load diff
133
source/common/utility/m_png.h
Normal file
133
source/common/utility/m_png.h
Normal file
|
@ -0,0 +1,133 @@
|
|||
#ifndef __M_PNG_H
|
||||
#define __M_PNG_H
|
||||
/*
|
||||
** m_png.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2005 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "zstring.h"
|
||||
#include "files.h"
|
||||
#include "palentry.h"
|
||||
|
||||
// Screenshot buffer image data types
|
||||
enum ESSType
|
||||
{
|
||||
SS_PAL,
|
||||
SS_RGB,
|
||||
SS_BGRA
|
||||
};
|
||||
|
||||
class FileWriter;
|
||||
// PNG Writing --------------------------------------------------------------
|
||||
|
||||
// Start writing an 8-bit palettized PNG file.
|
||||
// The passed file should be a newly created file.
|
||||
// This function writes the PNG signature and the IHDR, gAMA, PLTE, and IDAT
|
||||
// chunks.
|
||||
bool M_CreatePNG (FileWriter *file, const uint8_t *buffer, const PalEntry *pal,
|
||||
ESSType color_type, int width, int height, int pitch, float gamma);
|
||||
|
||||
// Creates a grayscale 1x1 PNG file. Used for savegames without savepics.
|
||||
bool M_CreateDummyPNG (FileWriter *file);
|
||||
|
||||
// Appends any chunk to a PNG file started with M_CreatePNG.
|
||||
bool M_AppendPNGChunk (FileWriter *file, uint32_t chunkID, const uint8_t *chunkData, uint32_t len);
|
||||
|
||||
// Adds a tEXt chunk to a PNG file started with M_CreatePNG.
|
||||
bool M_AppendPNGText (FileWriter *file, const char *keyword, const char *text);
|
||||
|
||||
// Appends the IEND chunk to a PNG file.
|
||||
bool M_FinishPNG (FileWriter *file);
|
||||
|
||||
bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height, int pitch, FileWriter *file);
|
||||
|
||||
// PNG Reading --------------------------------------------------------------
|
||||
|
||||
struct PNGHandle
|
||||
{
|
||||
struct Chunk
|
||||
{
|
||||
uint32_t ID;
|
||||
uint32_t Offset;
|
||||
uint32_t Size;
|
||||
};
|
||||
|
||||
FileReader File;
|
||||
bool bDeleteFilePtr;
|
||||
TArray<Chunk> Chunks;
|
||||
TArray<char *> TextChunks;
|
||||
unsigned int ChunkPt;
|
||||
|
||||
PNGHandle(FileReader &file);
|
||||
~PNGHandle();
|
||||
};
|
||||
|
||||
// Verify that a file really is a PNG file. This includes not only checking
|
||||
// the signature, but also checking for the IEND chunk. CRC checking of
|
||||
// each chunk is not done. If it is valid, you get a PNGHandle to pass to
|
||||
// the following functions.
|
||||
PNGHandle *M_VerifyPNG (FileReader &file);
|
||||
|
||||
// Finds a chunk in a PNG file. The file pointer will be positioned at the
|
||||
// beginning of the chunk data, and its length will be returned. A return
|
||||
// value of 0 indicates the chunk was either not present or had 0 length.
|
||||
unsigned int M_FindPNGChunk (PNGHandle *png, uint32_t chunkID);
|
||||
|
||||
// Finds a chunk in the PNG file, starting its search at whatever chunk
|
||||
// the file pointer is currently positioned at.
|
||||
unsigned int M_NextPNGChunk (PNGHandle *png, uint32_t chunkID);
|
||||
|
||||
// Finds a PNG text chunk with the given signature and returns a pointer
|
||||
// to a NULL-terminated string if present. Returns NULL on failure.
|
||||
// (Note: tEXt, not zTXt.)
|
||||
char *M_GetPNGText (PNGHandle *png, const char *keyword);
|
||||
bool M_GetPNGText (PNGHandle *png, const char *keyword, char *buffer, size_t buffsize);
|
||||
|
||||
// The file must be positioned at the start of the first IDAT. It reads
|
||||
// image data into the provided buffer. Returns true on success.
|
||||
bool M_ReadIDAT (FileReader &file, uint8_t *buffer, int width, int height, int pitch,
|
||||
uint8_t bitdepth, uint8_t colortype, uint8_t interlace, unsigned int idatlen);
|
||||
|
||||
|
||||
class FTexture;
|
||||
|
||||
FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename);
|
||||
|
||||
#ifndef MAKE_ID
|
||||
#ifndef __BIG_ENDIAN__
|
||||
#define MAKE_ID(a,b,c,d) ((uint32_t)((a)|((b)<<8)|((c)<<16)|((d)<<24)))
|
||||
#else
|
||||
#define MAKE_ID(a,b,c,d) ((uint32_t)((d)|((c)<<8)|((b)<<16)|((a)<<24)))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
417
source/common/utility/memarena.cpp
Normal file
417
source/common/utility/memarena.cpp
Normal file
|
@ -0,0 +1,417 @@
|
|||
/*
|
||||
** memarena.cpp
|
||||
** Implements memory arenas.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
** A memory arena is used for efficient allocation of many small objects that
|
||||
** will all be freed at once. Note that since individual destructors are not
|
||||
** called, you must not use an arena to allocate any objects that use a
|
||||
** destructor, either explicitly or implicitly (because they have members
|
||||
** with destructors).
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
#include "memarena.h"
|
||||
#include "printf.h"
|
||||
|
||||
struct FMemArena::Block
|
||||
{
|
||||
Block *NextBlock;
|
||||
void *Limit; // End of this block
|
||||
void *Avail; // Start of free space in this block
|
||||
void *alignme; // align to 16 bytes.
|
||||
|
||||
void Reset();
|
||||
void *Alloc(size_t size);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// RoundPointer
|
||||
//
|
||||
// Rounds a pointer up to a pointer-sized boundary.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static inline void *RoundPointer(void *ptr)
|
||||
{
|
||||
return (void *)(((size_t)ptr + sizeof(void*) - 1) & ~(sizeof(void*) - 1));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FMemArena::FMemArena(size_t blocksize)
|
||||
{
|
||||
TopBlock = NULL;
|
||||
FreeBlocks = NULL;
|
||||
BlockSize = blocksize;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena Destructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FMemArena::~FMemArena()
|
||||
{
|
||||
FreeAllBlocks();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: Alloc
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void *FMemArena::iAlloc(size_t size)
|
||||
{
|
||||
Block *block;
|
||||
|
||||
for (block = TopBlock; block != NULL; block = block->NextBlock)
|
||||
{
|
||||
void *res = block->Alloc(size);
|
||||
if (res != NULL)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
block = AddBlock(size);
|
||||
return block->Alloc(size);
|
||||
}
|
||||
|
||||
void *FMemArena::Alloc(size_t size)
|
||||
{
|
||||
return iAlloc((size + 15) & ~15);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: FreeAll
|
||||
//
|
||||
// Moves all blocks to the free list. No system-level deallocation occurs.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FMemArena::FreeAll()
|
||||
{
|
||||
for (Block *next, *block = TopBlock; block != NULL; block = next)
|
||||
{
|
||||
next = block->NextBlock;
|
||||
block->Reset();
|
||||
block->NextBlock = FreeBlocks;
|
||||
FreeBlocks = block;
|
||||
}
|
||||
TopBlock = NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: FreeAllBlocks
|
||||
//
|
||||
// Frees all blocks used by this arena.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FMemArena::FreeAllBlocks()
|
||||
{
|
||||
FreeBlockChain(TopBlock);
|
||||
FreeBlockChain(FreeBlocks);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: DumpInfo
|
||||
//
|
||||
// Prints some info about this arena
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FMemArena::DumpInfo()
|
||||
{
|
||||
size_t allocated = 0;
|
||||
size_t used = 0;
|
||||
for (auto block = TopBlock; block != NULL; block = block->NextBlock)
|
||||
{
|
||||
allocated += BlockSize;
|
||||
used += BlockSize - ((char*)block->Limit - (char*)block->Avail);
|
||||
}
|
||||
Printf("%zu bytes allocated, %zu bytes in use\n", allocated, used);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: DumpInfo
|
||||
//
|
||||
// Dumps the arena to a file (for debugging)
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FMemArena::DumpData(FILE *f)
|
||||
{
|
||||
for (auto block = TopBlock; block != NULL; block = block->NextBlock)
|
||||
{
|
||||
auto used = BlockSize - ((char*)block->Limit - (char*)block->Avail);
|
||||
fwrite(block, 1, used, f);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: FreeBlockChain
|
||||
//
|
||||
// Frees a chain of blocks.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FMemArena::FreeBlockChain(Block *&top)
|
||||
{
|
||||
for (Block *next, *block = top; block != NULL; block = next)
|
||||
{
|
||||
next = block->NextBlock;
|
||||
free(block);
|
||||
}
|
||||
top = NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: AddBlock
|
||||
//
|
||||
// Allocates a block large enough to hold at least <size> bytes and adds it
|
||||
// to the TopBlock chain.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FMemArena::Block *FMemArena::AddBlock(size_t size)
|
||||
{
|
||||
Block *mem, **last;
|
||||
size += sizeof(Block); // Account for header size
|
||||
|
||||
// Search for a free block to use
|
||||
for (last = &FreeBlocks, mem = FreeBlocks; mem != NULL; last = &mem->NextBlock, mem = mem->NextBlock)
|
||||
{
|
||||
if ((uint8_t *)mem->Limit - (uint8_t *)mem >= (ptrdiff_t)size)
|
||||
{
|
||||
*last = mem->NextBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mem == NULL)
|
||||
{
|
||||
// Allocate a new block
|
||||
if (size < BlockSize)
|
||||
{
|
||||
size = BlockSize;
|
||||
}
|
||||
else
|
||||
{ // Stick some free space at the end so we can use this block for
|
||||
// other things.
|
||||
size += BlockSize/2;
|
||||
}
|
||||
mem = (Block *)malloc(size);
|
||||
mem->Limit = (uint8_t *)mem + size;
|
||||
}
|
||||
mem->Reset();
|
||||
mem->NextBlock = TopBlock;
|
||||
TopBlock = mem;
|
||||
return mem;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: Block :: Reset
|
||||
//
|
||||
// Resets this block's Avail pointer.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FMemArena::Block::Reset()
|
||||
{
|
||||
Avail = RoundPointer(reinterpret_cast<char*>(this) + sizeof(*this));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: Block :: Alloc
|
||||
//
|
||||
// Allocates memory from the block if it has space. Returns NULL if not.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void *FMemArena::Block::Alloc(size_t size)
|
||||
{
|
||||
if ((char *)Avail + size > Limit)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void *res = Avail;
|
||||
Avail = RoundPointer((char *)Avail + size);
|
||||
return res;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FSharedStringArena::FSharedStringArena()
|
||||
{
|
||||
memset(Buckets, 0, sizeof(Buckets));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena Destructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FSharedStringArena::~FSharedStringArena()
|
||||
{
|
||||
FreeAll();
|
||||
// FMemArena destructor will free the blocks.
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena :: Alloc
|
||||
//
|
||||
// Allocates a new string and initializes it with the passed string. This
|
||||
// version takes an FString as a parameter, so it won't need to allocate any
|
||||
// memory for the string text if it already exists in the arena.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString *FSharedStringArena::Alloc(const FString &source)
|
||||
{
|
||||
unsigned int hash;
|
||||
Node *strnode;
|
||||
|
||||
strnode = FindString(source, source.Len(), hash);
|
||||
if (strnode == NULL)
|
||||
{
|
||||
strnode = (Node *)iAlloc(sizeof(Node));
|
||||
::new(&strnode->String) FString(source);
|
||||
strnode->Hash = hash;
|
||||
hash %= Bucket_Count;
|
||||
strnode->Next = Buckets[hash];
|
||||
Buckets[hash] = strnode;
|
||||
}
|
||||
return &strnode->String;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena :: Alloc
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString *FSharedStringArena::Alloc(const char *source)
|
||||
{
|
||||
return Alloc(source, strlen(source));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena :: Alloc
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString *FSharedStringArena::Alloc(const char *source, size_t strlen)
|
||||
{
|
||||
unsigned int hash;
|
||||
Node *strnode;
|
||||
|
||||
strnode = FindString(source, strlen, hash);
|
||||
if (strnode == NULL)
|
||||
{
|
||||
strnode = (Node *)iAlloc(sizeof(Node));
|
||||
::new(&strnode->String) FString(source, strlen);
|
||||
strnode->Hash = hash;
|
||||
hash %= Bucket_Count;
|
||||
strnode->Next = Buckets[hash];
|
||||
Buckets[hash] = strnode;
|
||||
}
|
||||
return &strnode->String;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena :: FindString
|
||||
//
|
||||
// Finds the string if it's already in the arena. Returns NULL if not.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FSharedStringArena::Node *FSharedStringArena::FindString(const char *str, size_t strlen, unsigned int &hash)
|
||||
{
|
||||
hash = SuperFastHash(str, strlen);
|
||||
|
||||
for (Node *node = Buckets[hash % Bucket_Count]; node != NULL; node = node->Next)
|
||||
{
|
||||
if (node->Hash == hash && node->String.Len() == strlen && memcmp(&node->String[0], str, strlen) == 0)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena :: FreeAll
|
||||
//
|
||||
// In addition to moving all used blocks onto the free list, all FStrings
|
||||
// they contain will have their destructors called.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FSharedStringArena::FreeAll()
|
||||
{
|
||||
for (Block *next, *block = TopBlock; block != NULL; block = next)
|
||||
{
|
||||
next = block->NextBlock;
|
||||
void *limit = block->Avail;
|
||||
block->Reset();
|
||||
for (Node *string = (Node *)block->Avail; string < limit; ++string)
|
||||
{
|
||||
string->~Node();
|
||||
}
|
||||
block->NextBlock = FreeBlocks;
|
||||
FreeBlocks = block;
|
||||
}
|
||||
memset(Buckets, 0, sizeof(Buckets));
|
||||
TopBlock = NULL;
|
||||
}
|
97
source/common/utility/memarena.h
Normal file
97
source/common/utility/memarena.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
** memarena.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __MEMARENA_H
|
||||
#define __MEMARENA_H
|
||||
|
||||
#include "zstring.h"
|
||||
|
||||
// A general purpose arena.
|
||||
class FMemArena
|
||||
{
|
||||
public:
|
||||
FMemArena(size_t blocksize = 10*1024);
|
||||
~FMemArena();
|
||||
|
||||
void *Alloc(size_t size);
|
||||
void FreeAll();
|
||||
void FreeAllBlocks();
|
||||
void DumpInfo();
|
||||
void DumpData(FILE *f);
|
||||
|
||||
protected:
|
||||
struct Block;
|
||||
|
||||
Block *AddBlock(size_t size);
|
||||
void FreeBlockChain(Block *&top);
|
||||
void *iAlloc(size_t size);
|
||||
|
||||
Block *TopBlock;
|
||||
Block *FreeBlocks;
|
||||
size_t BlockSize;
|
||||
};
|
||||
|
||||
// An arena specializing in storage of FStrings. It knows how to free them,
|
||||
// but this means it also should never be used for allocating anything else.
|
||||
// Identical strings all return the same pointer.
|
||||
class FSharedStringArena : public FMemArena
|
||||
{
|
||||
public:
|
||||
FSharedStringArena();
|
||||
~FSharedStringArena();
|
||||
void FreeAll();
|
||||
|
||||
class FString *Alloc(const FString &source);
|
||||
class FString *Alloc(const char *source);
|
||||
class FString *Alloc(const char *source, size_t strlen);
|
||||
|
||||
protected:
|
||||
struct Node
|
||||
{
|
||||
Node *Next;
|
||||
FString String;
|
||||
unsigned int Hash;
|
||||
};
|
||||
enum
|
||||
{
|
||||
Bucket_Count = 256
|
||||
};
|
||||
Node *Buckets[Bucket_Count];
|
||||
|
||||
Node *FindString(const char *str, size_t strlen, unsigned int &hash);
|
||||
private:
|
||||
void *Alloc(size_t size) { return NULL; } // No access to FMemArena::Alloc for outsiders.
|
||||
};
|
||||
|
||||
|
||||
#endif
|
82
source/common/utility/palentry.h
Normal file
82
source/common/utility/palentry.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct PalEntry
|
||||
{
|
||||
PalEntry() = default;
|
||||
PalEntry (uint32_t argb) { d = argb; }
|
||||
operator uint32_t () const { return d; }
|
||||
void SetRGB(PalEntry other)
|
||||
{
|
||||
d = other.d & 0xffffff;
|
||||
}
|
||||
PalEntry Modulate(PalEntry other) const
|
||||
{
|
||||
if (isWhite())
|
||||
{
|
||||
return other;
|
||||
}
|
||||
else if (other.isWhite())
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
else
|
||||
{
|
||||
other.r = (r * other.r) / 255;
|
||||
other.g = (g * other.g) / 255;
|
||||
other.b = (b * other.b) / 255;
|
||||
return other;
|
||||
}
|
||||
}
|
||||
int Luminance() const
|
||||
{
|
||||
return (r * 77 + g * 143 + b * 37) >> 8;
|
||||
}
|
||||
|
||||
void Decolorize() // this for 'nocoloredspritelighting' and not the same as desaturation. The normal formula results in a value that's too dark.
|
||||
{
|
||||
int v = (r + g + b);
|
||||
r = g = b = ((255*3) + v + v) / 9;
|
||||
}
|
||||
bool isBlack() const
|
||||
{
|
||||
return (d & 0xffffff) == 0;
|
||||
}
|
||||
bool isWhite() const
|
||||
{
|
||||
return (d & 0xffffff) == 0xffffff;
|
||||
}
|
||||
PalEntry &operator= (const PalEntry &other) = default;
|
||||
PalEntry &operator= (uint32_t other) { d = other; return *this; }
|
||||
PalEntry InverseColor() const { PalEntry nc; nc.a = a; nc.r = 255 - r; nc.g = 255 - g; nc.b = 255 - b; return nc; }
|
||||
#ifdef __BIG_ENDIAN__
|
||||
PalEntry (uint8_t ir, uint8_t ig, uint8_t ib) : a(0), r(ir), g(ig), b(ib) {}
|
||||
PalEntry (uint8_t ia, uint8_t ir, uint8_t ig, uint8_t ib) : a(ia), r(ir), g(ig), b(ib) {}
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t a,r,g,b;
|
||||
};
|
||||
uint32_t d;
|
||||
};
|
||||
#else
|
||||
PalEntry (uint8_t ir, uint8_t ig, uint8_t ib) : b(ib), g(ig), r(ir), a(0) {}
|
||||
PalEntry (uint8_t ia, uint8_t ir, uint8_t ig, uint8_t ib) : b(ib), g(ig), r(ir), a(ia) {}
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t b,g,r,a;
|
||||
};
|
||||
uint32_t d;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
inline int Luminance(int r, int g, int b)
|
||||
{
|
||||
return (r * 77 + g * 143 + b * 37) >> 8;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
// Windows layer-independent code
|
||||
|
||||
#include <Windows.h>
|
||||
#include "compat.h"
|
||||
#include "build.h"
|
||||
#include "baselayer.h"
|
||||
|
|
Loading…
Reference in a new issue