mirror of
https://github.com/DrBeef/Raze.git
synced 2025-01-18 23:21:43 +00:00
- transitioned FTexture.
Mostly working. Note: Brightmaps must be per-translation!
This commit is contained in:
parent
71ab8c0b10
commit
7a84887fc4
18 changed files with 1425 additions and 395 deletions
|
@ -753,6 +753,7 @@ set (PCH_SOURCES
|
|||
common/textures/m_png.cpp
|
||||
common/textures/image.cpp
|
||||
common/textures/texturemanager.cpp
|
||||
common/textures/hw_ihwtexture.cpp
|
||||
common/textures/formats/fontchars.cpp
|
||||
common/textures/formats/automaptexture.cpp
|
||||
common/textures/formats/brightmaptexture.cpp
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#ifdef USE_OPENGL
|
||||
#include "hightile.h"
|
||||
#include "glbackend/gl_hwtexture.h"
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_AMD64) || defined(__i386) || defined(__x86_64)
|
||||
#define SHIFTMOD32(a) (a)
|
||||
|
|
|
@ -42,15 +42,15 @@
|
|||
|
||||
void AnimTexture::SetSize(int width, int height)
|
||||
{
|
||||
Size.x = width;
|
||||
Size.y = height;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Image.Resize(width*height);
|
||||
}
|
||||
|
||||
void AnimTexture::SetFrame(const uint8_t *palette, const void *data_)
|
||||
{
|
||||
memcpy(Palette, palette, 768);
|
||||
memcpy(Image.Data(), data_, Size.x * Size.y);
|
||||
memcpy(Image.Data(), data_, Width*Height);
|
||||
DeleteHardwareTextures();
|
||||
}
|
||||
|
||||
|
@ -64,11 +64,11 @@ FBitmap AnimTexture::GetBgraBitmap(const PalEntry* remap, int* trans)
|
|||
{
|
||||
FBitmap bmp;
|
||||
|
||||
bmp.Create(Size.x, Size.y);
|
||||
bmp.Create(Width, Height);
|
||||
|
||||
auto spix = Image.Data();
|
||||
auto dpix = bmp.GetPixels();
|
||||
for (int i = 0; i < Size.x * Size.y; i++)
|
||||
for (int i = 0; i < Width * Height; i++)
|
||||
{
|
||||
int p = i * 4;
|
||||
int index = spix[i];
|
||||
|
|
|
@ -622,8 +622,8 @@ FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename)
|
|||
FPNGFileTexture::FPNGFileTexture (FileReader &lump, int width, int height, uint8_t colortype)
|
||||
: ColorType(colortype)
|
||||
{
|
||||
Size.x = width;
|
||||
Size.y = height;
|
||||
Width = width;
|
||||
Height = height;
|
||||
fr = std::move(lump);
|
||||
}
|
||||
|
||||
|
@ -639,11 +639,11 @@ FBitmap FPNGFileTexture::GetBgraBitmap(const PalEntry *remap, int *trans)
|
|||
// Parse pre-IDAT chunks. I skip the CRCs. Is that bad?
|
||||
PalEntry pe[256];
|
||||
uint32_t len, id;
|
||||
int pixwidth = Size.x * (ColorType == 2? 3:1);
|
||||
int pixwidth = Width * (ColorType == 2? 3:1);
|
||||
|
||||
FileReader *lump = &fr;
|
||||
|
||||
bmp.Create(Size.x, Size.y);
|
||||
bmp.Create(Width, Height);
|
||||
lump->Seek(33, FileReader::SeekSet);
|
||||
lump->Read(&len, 4);
|
||||
lump->Read(&id, 4);
|
||||
|
@ -670,20 +670,20 @@ FBitmap FPNGFileTexture::GetBgraBitmap(const PalEntry *remap, int *trans)
|
|||
}
|
||||
auto StartOfIDAT = (uint32_t)lump->Tell() - 8;
|
||||
|
||||
TArray<uint8_t> Pixels(pixwidth * Size.y);
|
||||
TArray<uint8_t> Pixels(pixwidth * Height);
|
||||
|
||||
lump->Seek (StartOfIDAT, FileReader::SeekSet);
|
||||
lump->Read(&len, 4);
|
||||
lump->Read(&id, 4);
|
||||
M_ReadIDAT (*lump, Pixels.Data(), Size.x, Size.y, pixwidth, 8, ColorType, 0, BigLong((unsigned int)len));
|
||||
M_ReadIDAT (*lump, Pixels.Data(), Width, Height, pixwidth, 8, ColorType, 0, BigLong((unsigned int)len));
|
||||
|
||||
if (ColorType == 3)
|
||||
{
|
||||
bmp.CopyPixelData(0, 0, Pixels.Data(), Size.x, Size.y, 1, Size.x, 0, pe);
|
||||
bmp.CopyPixelData(0, 0, Pixels.Data(), Width, Height, 1, Width, 0, pe);
|
||||
}
|
||||
else
|
||||
{
|
||||
bmp.CopyPixelDataRGB(0, 0, Pixels.Data(), Size.x, Size.y, 3, pixwidth, 0, CF_RGB);
|
||||
bmp.CopyPixelDataRGB(0, 0, Pixels.Data(), Width, Height, 3, pixwidth, 0, CF_RGB);
|
||||
}
|
||||
return bmp;
|
||||
}
|
137
source/common/textures/hw_ihwtexture.cpp
Normal file
137
source/common/textures/hw_ihwtexture.cpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
** ihwtexture.cpp
|
||||
** Interface for hardware textures
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2006-2020 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 "hw_ihwtexture.h"
|
||||
#include "templates.h"
|
||||
#include "tarray.h"
|
||||
#include "xs_Float.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Quick'n dirty image rescaling.
|
||||
//
|
||||
// This will only be used when the source texture is larger than
|
||||
// what the hardware can manage (extremely rare in Doom)
|
||||
//
|
||||
// Code taken from wxWidgets
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
struct BoxPrecalc
|
||||
{
|
||||
int boxStart;
|
||||
int boxEnd;
|
||||
};
|
||||
|
||||
static void ResampleBoxPrecalc(TArray<BoxPrecalc>& boxes, int oldDim)
|
||||
{
|
||||
int newDim = boxes.Size();
|
||||
const double scale_factor_1 = double(oldDim) / newDim;
|
||||
const int scale_factor_2 = (int)(scale_factor_1 / 2);
|
||||
|
||||
for (int dst = 0; dst < newDim; ++dst)
|
||||
{
|
||||
// Source pixel in the Y direction
|
||||
const int src_p = int(dst * scale_factor_1);
|
||||
|
||||
BoxPrecalc& precalc = boxes[dst];
|
||||
precalc.boxStart = clamp<int>(int(src_p - scale_factor_1 / 2.0 + 1), 0, oldDim - 1);
|
||||
precalc.boxEnd = clamp<int>(MAX<int>(precalc.boxStart + 1, int(src_p + scale_factor_2)), 0, oldDim - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void IHardwareTexture::Resize(int swidth, int sheight, int width, int height, unsigned char *src_data, unsigned char *dst_data)
|
||||
{
|
||||
|
||||
// This function implements a simple pre-blur/box averaging method for
|
||||
// downsampling that gives reasonably smooth results To scale the image
|
||||
// down we will need to gather a grid of pixels of the size of the scale
|
||||
// factor in each direction and then do an averaging of the pixels.
|
||||
|
||||
TArray<BoxPrecalc> vPrecalcs(height, true);
|
||||
TArray<BoxPrecalc> hPrecalcs(width, true);
|
||||
|
||||
ResampleBoxPrecalc(vPrecalcs, sheight);
|
||||
ResampleBoxPrecalc(hPrecalcs, swidth);
|
||||
|
||||
int averaged_pixels, averaged_alpha, src_pixel_index;
|
||||
double sum_r, sum_g, sum_b, sum_a;
|
||||
|
||||
for (int y = 0; y < height; y++) // Destination image - Y direction
|
||||
{
|
||||
// Source pixel in the Y direction
|
||||
const BoxPrecalc& vPrecalc = vPrecalcs[y];
|
||||
|
||||
for (int x = 0; x < width; x++) // Destination image - X direction
|
||||
{
|
||||
// Source pixel in the X direction
|
||||
const BoxPrecalc& hPrecalc = hPrecalcs[x];
|
||||
|
||||
// Box of pixels to average
|
||||
averaged_pixels = 0;
|
||||
averaged_alpha = 0;
|
||||
sum_r = sum_g = sum_b = sum_a = 0.0;
|
||||
|
||||
for (int j = vPrecalc.boxStart; j <= vPrecalc.boxEnd; ++j)
|
||||
{
|
||||
for (int i = hPrecalc.boxStart; i <= hPrecalc.boxEnd; ++i)
|
||||
{
|
||||
// Calculate the actual index in our source pixels
|
||||
src_pixel_index = j * swidth + i;
|
||||
|
||||
int a = src_data[src_pixel_index * 4 + 3];
|
||||
if (a > 0) // do not use color from fully transparent pixels
|
||||
{
|
||||
sum_r += src_data[src_pixel_index * 4 + 0];
|
||||
sum_g += src_data[src_pixel_index * 4 + 1];
|
||||
sum_b += src_data[src_pixel_index * 4 + 2];
|
||||
sum_a += a;
|
||||
averaged_pixels++;
|
||||
}
|
||||
averaged_alpha++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the average from the sum and number of averaged pixels
|
||||
dst_data[0] = (unsigned char)xs_CRoundToInt(sum_r / averaged_pixels);
|
||||
dst_data[1] = (unsigned char)xs_CRoundToInt(sum_g / averaged_pixels);
|
||||
dst_data[2] = (unsigned char)xs_CRoundToInt(sum_b / averaged_pixels);
|
||||
dst_data[3] = (unsigned char)xs_CRoundToInt(sum_a / averaged_alpha);
|
||||
dst_data += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
32
source/common/textures/hw_ihwtexture.h
Normal file
32
source/common/textures/hw_ihwtexture.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "tarray.h"
|
||||
|
||||
typedef TMap<int, bool> SpriteHits;
|
||||
class FTexture;
|
||||
|
||||
class IHardwareTexture
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
MAX_TEXTURES = 16
|
||||
};
|
||||
|
||||
IHardwareTexture() {}
|
||||
virtual ~IHardwareTexture() {}
|
||||
|
||||
virtual void DeleteDescriptors() { }
|
||||
|
||||
virtual void AllocateBuffer(int w, int h, int texelsize) = 0;
|
||||
virtual uint8_t *MapBuffer() = 0;
|
||||
virtual unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) = 0;
|
||||
|
||||
void Resize(int swidth, int sheight, int width, int height, unsigned char *src_data, unsigned char *dst_data);
|
||||
|
||||
int GetBufferPitch() const { return bufferpitch; }
|
||||
|
||||
protected:
|
||||
int bufferpitch = -1;
|
||||
};
|
139
source/common/textures/hw_texcontainer.h
Normal file
139
source/common/textures/hw_texcontainer.h
Normal file
|
@ -0,0 +1,139 @@
|
|||
#pragma once
|
||||
|
||||
#include "tarray.h"
|
||||
#include "hw_ihwtexture.h"
|
||||
#include "palettecontainer.h"
|
||||
|
||||
struct FTextureBuffer;
|
||||
class IHardwareTexture;
|
||||
|
||||
class FHardwareTextureContainer
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
MAX_TEXTURES = 16
|
||||
};
|
||||
|
||||
private:
|
||||
struct TranslatedTexture
|
||||
{
|
||||
IHardwareTexture *hwTexture = nullptr;
|
||||
int translation = 0;
|
||||
|
||||
void Delete()
|
||||
{
|
||||
if (hwTexture) delete hwTexture;
|
||||
hwTexture = nullptr;
|
||||
}
|
||||
|
||||
void DeleteDescriptors()
|
||||
{
|
||||
if (hwTexture) hwTexture->DeleteDescriptors();
|
||||
}
|
||||
|
||||
~TranslatedTexture()
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
TranslatedTexture hwDefTex[2];
|
||||
TArray<TranslatedTexture> hwTex_Translated;
|
||||
|
||||
TranslatedTexture * GetTexID(int translation, bool expanded)
|
||||
{
|
||||
#if 0
|
||||
auto remap = GPalette.TranslationToTable(translation);
|
||||
translation = remap == nullptr ? 0 : remap->Index;
|
||||
#endif
|
||||
|
||||
if (translation == 0)
|
||||
{
|
||||
return &hwDefTex[expanded];
|
||||
}
|
||||
|
||||
if (expanded) translation = -translation;
|
||||
// normally there aren't more than very few different
|
||||
// translations here so this isn't performance critical.
|
||||
unsigned index = hwTex_Translated.FindEx([=](auto &element)
|
||||
{
|
||||
return element.translation == translation;
|
||||
});
|
||||
if (index < hwTex_Translated.Size())
|
||||
{
|
||||
return &hwTex_Translated[index];
|
||||
}
|
||||
|
||||
int add = hwTex_Translated.Reserve(1);
|
||||
auto item = &hwTex_Translated[add];
|
||||
item->translation = translation;
|
||||
return item;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void Clean(bool cleannormal, bool cleanexpanded)
|
||||
{
|
||||
if (cleannormal) hwDefTex[0].Delete();
|
||||
if (cleanexpanded) hwDefTex[1].Delete();
|
||||
hwDefTex[0].DeleteDescriptors();
|
||||
hwDefTex[1].DeleteDescriptors();
|
||||
for (int i = hwTex_Translated.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
if (cleannormal && hwTex_Translated[i].translation > 0) hwTex_Translated.Delete(i);
|
||||
else if (cleanexpanded && hwTex_Translated[i].translation < 0) hwTex_Translated.Delete(i);
|
||||
|
||||
for (unsigned int j = 0; j < hwTex_Translated.Size(); j++)
|
||||
hwTex_Translated[j].DeleteDescriptors();
|
||||
}
|
||||
}
|
||||
|
||||
IHardwareTexture * GetHardwareTexture(int translation, bool expanded)
|
||||
{
|
||||
auto tt = GetTexID(translation, expanded);
|
||||
return tt->hwTexture;
|
||||
}
|
||||
|
||||
void AddHardwareTexture(int translation, bool expanded, IHardwareTexture *tex)
|
||||
{
|
||||
auto tt = GetTexID(translation, expanded);
|
||||
tt->Delete();
|
||||
tt->hwTexture =tex;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Deletes all allocated resources and considers translations
|
||||
// This will only be called for sprites
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void CleanUnused(SpriteHits &usedtranslations, bool expanded)
|
||||
{
|
||||
if (usedtranslations.CheckKey(0) == nullptr)
|
||||
{
|
||||
hwDefTex[expanded].Delete();
|
||||
}
|
||||
int fac = expanded ? -1 : 1;
|
||||
for (int i = hwTex_Translated.Size()-1; i>= 0; i--)
|
||||
{
|
||||
if (usedtranslations.CheckKey(hwTex_Translated[i].translation * fac) == nullptr)
|
||||
{
|
||||
hwTex_Translated.Delete(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Iterate(T callback)
|
||||
{
|
||||
for (auto & t : hwDefTex) if (t.hwTexture) callback(t.hwTexture);
|
||||
for (auto & t : hwTex_Translated) if (t.hwTexture) callback(t.hwTexture);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -169,26 +169,4 @@ protected:
|
|||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// a TGA texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FImageTexture : public FTexture
|
||||
{
|
||||
FImageSource *mImage;
|
||||
public:
|
||||
FImageTexture (FImageSource *image, const char *name = nullptr);
|
||||
~FImageTexture()
|
||||
{
|
||||
if (mImage) delete mImage;
|
||||
}
|
||||
void Create8BitPixels(uint8_t* buffer) override;
|
||||
|
||||
FImageSource *GetImage() const override { return mImage; }
|
||||
FBitmap GetBgraBitmap(const PalEntry *p, int *trans) override;
|
||||
|
||||
};
|
||||
|
||||
FTexture* CreateImageTexture(FImageSource* img, const char *name = nullptr) noexcept;
|
||||
|
|
|
@ -171,15 +171,15 @@ void FGLRenderer::EndOffscreen()
|
|||
|
||||
void FGLRenderer::BindToFrameBuffer(FTexture *mat)
|
||||
{
|
||||
auto pBaseLayer = mat->GetHardwareTexture(0);
|
||||
auto BaseLayer = pBaseLayer ? *pBaseLayer : nullptr;
|
||||
auto pBaseLayer = mat->SystemTextures.GetHardwareTexture(0, false);
|
||||
auto BaseLayer = pBaseLayer ? (::FHardwareTexture*)pBaseLayer : nullptr;
|
||||
|
||||
if (BaseLayer == nullptr)
|
||||
{
|
||||
// must create the hardware texture first
|
||||
BaseLayer = new ::FHardwareTexture();
|
||||
BaseLayer->CreateTexture(mat->GetTexelWidth()*4, mat->GetTexelHeight()*4, ::FHardwareTexture::TrueColor, false);
|
||||
mat->SetHardwareTexture(0, BaseLayer);
|
||||
mat->SystemTextures.AddHardwareTexture(0, false, BaseLayer);
|
||||
}
|
||||
BaseLayer->BindToFrameBuffer(mat->GetTexelWidth()*4, mat->GetTexelHeight()*4);
|
||||
}
|
||||
|
|
|
@ -396,3 +396,8 @@ void DFrameBuffer::FinishScene()
|
|||
GLInterface.DoDraw();
|
||||
}
|
||||
}
|
||||
|
||||
IHardwareTexture* CreateHardwareTexture()
|
||||
{
|
||||
return screen->CreateHardwareTexture();
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "build.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "palettecontainer.h"
|
||||
#include "texturemanager.h"
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -84,37 +85,34 @@ FBitmap FTileTexture::GetBgraBitmap(const PalEntry* remap, int* ptrans)
|
|||
{
|
||||
FBitmap bmp;
|
||||
TArray<uint8_t> buffer;
|
||||
bmp.Create(Size.x, Size.y);
|
||||
const uint8_t* ppix = Get8BitPixels();
|
||||
if (!remap)
|
||||
remap = GPalette.BaseColors; // no remap was passed but this code needs a color table, so use the base.
|
||||
if (!ppix)
|
||||
bmp.Create(Width, Height);
|
||||
auto ppix = GetRawData();
|
||||
if (ppix)
|
||||
{
|
||||
// This is needed for tiles with a palette remap.
|
||||
buffer.Resize(Size.x * Size.y);
|
||||
Create8BitPixels(buffer.Data());
|
||||
ppix = buffer.Data();
|
||||
if (remap == nullptr) remap = GPalette.BaseColors;
|
||||
bmp.CopyPixelData(0, 0, ppix, Width, Height, Height, 1, 0, remap);
|
||||
}
|
||||
if (ppix) bmp.CopyPixelData(0, 0, ppix, Size.x, Size.y, Size.y, 1, 0, remap);
|
||||
return bmp;
|
||||
}
|
||||
|
||||
void FTileTexture::Create8BitPixels(uint8_t* buffer)
|
||||
TArray<uint8_t> FTileTexture::Get8BitPixels(bool alphatex)
|
||||
{
|
||||
auto pix = Get8BitPixels();
|
||||
if (pix) memcpy(buffer, pix, Size.x * Size.y);
|
||||
TArray<uint8_t> buffer(Width * Height, true);
|
||||
auto p = GetRawData();
|
||||
if (p) memcpy(buffer.Data(), p, buffer.Size());
|
||||
else memset(buffer.Data(), 0, buffer.Size());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Tile textures are owned by their containing file object.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FArtTile* GetTileTexture(const char* name, const TArray<uint8_t>& backingstore, uint32_t offset, int width, int height, int picanm)
|
||||
FArtTile* GetTileTexture(const char* name, const TArray<uint8_t>& backingstore, uint32_t offset, int width, int height)
|
||||
{
|
||||
auto tex = new FArtTile(backingstore, offset, width, height, picanm);
|
||||
auto tex = new FArtTile(backingstore, offset, width, height);
|
||||
|
||||
if (tex)
|
||||
{
|
||||
|
@ -175,7 +173,7 @@ void BuildTiles::AddTiles (int firsttile, TArray<uint8_t>& RawData, bool permap)
|
|||
|
||||
if (width <= 0 || height <= 0) continue;
|
||||
|
||||
auto tex = GetTileTexture("", RawData, uint32_t(tiledata - tiles), width, height, anm);
|
||||
auto tex = GetTileTexture("", RawData, uint32_t(tiledata - tiles), width, height);
|
||||
AddTile(i, tex);
|
||||
int leftoffset, topoffset;
|
||||
this->tiledata[i].picanm = tileConvertAnimFormat(anm, &leftoffset, &topoffset);
|
||||
|
@ -346,8 +344,7 @@ void BuildTiles::InvalidateTile(int num)
|
|||
void BuildTiles::MakeCanvas(int tilenum, int width, int height)
|
||||
{
|
||||
auto canvas = ValidateCustomTile(tilenum, ReplacementType::Canvas);
|
||||
canvas->Size.x = width;
|
||||
canvas->Size.y = height;
|
||||
canvas->SetSize(width, height);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -463,7 +460,7 @@ FTexture* BuildTiles::ValidateCustomTile(int tilenum, ReplacementType type)
|
|||
// B) the pin display in Redneck Rampage's bowling lanes.
|
||||
// C) Exhumed's menu plus one special effect tile.
|
||||
// All of these effects should probably be redone without actual texture hacking...
|
||||
if (tile->GetWidth() == 0 || tile->GetHeight() == 0) return nullptr; // The base must have a size for this to work.
|
||||
if (tile->GetTexelWidth() == 0 || tile->GetTexelHeight() == 0) return nullptr; // The base must have a size for this to work.
|
||||
// todo: invalidate hardware textures for tile.
|
||||
replacement = new FRestorableTile(tile);
|
||||
}
|
||||
|
@ -502,7 +499,7 @@ uint8_t* BuildTiles::tileCreate(int tilenum, int width, int height)
|
|||
if (tex == nullptr) return nullptr;
|
||||
auto wtex = static_cast<FWritableTile*>(tex);
|
||||
if (!wtex->Resize(width, height)) return nullptr;
|
||||
return tex->GetWritableBuffer();
|
||||
return wtex->GetRawData();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -512,26 +509,11 @@ uint8_t* BuildTiles::tileCreate(int tilenum, int width, int height)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
uint8_t * BuildTiles::tileMakeWritable(int num)
|
||||
uint8_t* BuildTiles::tileMakeWritable(int num)
|
||||
{
|
||||
auto tex = ValidateCustomTile(num, ReplacementType::Restorable);
|
||||
return tex ? tex->GetWritableBuffer() : nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets user content for a tile.
|
||||
// This must copy the buffer to make sure that the renderer has the data,
|
||||
// even if processing is deferred.
|
||||
//
|
||||
// Only used by the movie players.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BuildTiles::tileSetExternal(int tilenum, int width, int height, uint8_t* data)
|
||||
{
|
||||
uint8_t* buffer = tileCreate(tilenum, width, height);
|
||||
if (buffer) memcpy(buffer, data, width * height);
|
||||
auto wtex = static_cast<FWritableTile*>(tex);
|
||||
return wtex ? wtex->GetRawData() : nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -545,11 +527,11 @@ int32_t tileGetCRC32(int tileNum)
|
|||
if ((unsigned)tileNum >= (unsigned)MAXTILES) return 0;
|
||||
auto tile = tileGetTexture(tileNum);
|
||||
if (!tile || TileFiles.tiledata[tileNum].replacement != ReplacementType::Art) return 0; // only consider original ART tiles.
|
||||
auto pixels = tile->Get8BitPixels();
|
||||
if (!pixels) return 0;
|
||||
int size = tile->GetWidth() * tile->GetHeight();
|
||||
auto pixels = tile->Get8BitPixels(false);
|
||||
if (!pixels.Size()) return 0;
|
||||
int size = tile->GetTexelWidth() * tile->GetTexelHeight();
|
||||
if (size == 0) return 0;
|
||||
return crc32(0, (const Bytef*)pixels, size);
|
||||
return crc32(0, (const Bytef*)pixels.Data(), size);
|
||||
}
|
||||
|
||||
|
||||
|
@ -562,11 +544,12 @@ int32_t tileGetCRC32(int tileNum)
|
|||
|
||||
int tileImportFromTexture(const char* fn, int tilenum, int alphacut, int istexture)
|
||||
{
|
||||
FTexture* tex = TileFiles.GetTexture(fn);
|
||||
if (tex == nullptr) return -1;
|
||||
tex->alphaThreshold = 255 - alphacut;
|
||||
FTextureID texid = TexMan.CheckForTexture(fn, ETextureType::Any);
|
||||
if (!texid.isValid()) return -1;
|
||||
auto tex = TexMan.GetTexture(texid);
|
||||
//tex->alphaThreshold = 255 - alphacut;
|
||||
|
||||
int32_t xsiz = tex->GetWidth(), ysiz = tex->GetHeight();
|
||||
int32_t xsiz = tex->GetTexelWidth(), ysiz = tex->GetTexelHeight();
|
||||
|
||||
if (xsiz <= 0 || ysiz <= 0)
|
||||
return -2;
|
||||
|
@ -604,8 +587,8 @@ void tileCopy(int tile, int source, int pal, int xoffset, int yoffset, int flags
|
|||
if (!tex) return;
|
||||
picanm = &TileFiles.tiledata[tile].picanm;
|
||||
sourceanm = picanm;
|
||||
srcxo = tex->GetLeftOffset();
|
||||
srcyo = tex->GetTopOffset();
|
||||
srcxo = tex->GetTexelLeftOffset(0);
|
||||
srcyo = tex->GetTexelTopOffset(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -613,11 +596,10 @@ void tileCopy(int tile, int source, int pal, int xoffset, int yoffset, int flags
|
|||
tex = tileGetTexture(source);
|
||||
if (!tex) return;
|
||||
sourceanm = &TileFiles.tiledata[source].picanm;
|
||||
srcxo = tex->GetLeftOffset();
|
||||
srcyo = tex->GetTopOffset();
|
||||
srcxo = tex->GetTexelLeftOffset(0);
|
||||
srcyo = tex->GetTexelTopOffset(0);
|
||||
|
||||
TArray<uint8_t> buffer(tex->GetWidth() * tex->GetHeight(), true);
|
||||
tex->Create8BitPixels(buffer.Data());
|
||||
TArray<uint8_t> buffer = tex->Get8BitPixels(false);
|
||||
|
||||
if (pal != -1)
|
||||
{
|
||||
|
@ -627,7 +609,7 @@ void tileCopy(int tile, int source, int pal, int xoffset, int yoffset, int flags
|
|||
pixel = remap[pixel];
|
||||
}
|
||||
}
|
||||
tex = new FLooseTile(buffer, tex->GetWidth(), tex->GetHeight());
|
||||
tex = new FLooseTile(buffer, tex->GetTexelWidth(), tex->GetTexelHeight());
|
||||
picanm = &TileFiles.tiledata[tile].picanm;
|
||||
TileFiles.AddTile(tile, tex);
|
||||
}
|
||||
|
@ -729,29 +711,6 @@ void tileSetDummy(int tile, int width, int height)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool tileLoad(int tileNum)
|
||||
{
|
||||
if ((unsigned)tileNum >= MAXTILES) return false;
|
||||
auto tex = tileGetTexture(tileNum);
|
||||
if (!tex || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return false;
|
||||
if (tex->Get8BitPixels()) return true;
|
||||
|
||||
if (!tex->CachedPixels.Size())
|
||||
{
|
||||
// Allocate storage if necessary.
|
||||
tex->CachedPixels.Resize(tex->GetWidth() * tex->GetHeight());
|
||||
tex->Create8BitPixels(tex->CachedPixels.Data());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -765,7 +724,7 @@ int BuildTiles::findUnusedTile(void)
|
|||
for (; lastUnusedTile >= 0; --lastUnusedTile)
|
||||
{
|
||||
auto tex = tileGetTexture(lastUnusedTile);
|
||||
if (!tex || tex->GetWidth() <= 0 || tex->GetHeight() <= 0) return lastUnusedTile;
|
||||
if (!tex || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return lastUnusedTile;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -774,25 +733,25 @@ int BuildTiles::tileCreateRotated(int tileNum)
|
|||
{
|
||||
if ((unsigned)tileNum >= MAXTILES) return tileNum;
|
||||
auto tex = tileGetTexture(tileNum);
|
||||
if (!tex || tex->GetWidth() <= 0 || tex->GetHeight() <= 0) return tileNum;
|
||||
TArray<uint8_t> buffer(tex->GetWidth() * tex->GetHeight(), true);
|
||||
tex->Create8BitPixels(buffer.Data());
|
||||
TArray<uint8_t> dbuffer(tex->GetWidth() * tex->GetHeight(), true);
|
||||
if (!tex || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return tileNum;
|
||||
TArray<uint8_t> buffer = tex->Get8BitPixels(false);
|
||||
TArray<uint8_t> dbuffer(tex->GetTexelWidth() * tex->GetTexelHeight(), true);
|
||||
|
||||
auto src = buffer.Data();
|
||||
auto dst = dbuffer.Data();
|
||||
|
||||
auto siz = tex->GetSize();
|
||||
for (int x = 0; x < siz.x; ++x)
|
||||
auto width = tex->GetTexelWidth();
|
||||
auto height = tex->GetTexelHeight();
|
||||
for (int x = 0; x < width; ++x)
|
||||
{
|
||||
int xofs = siz.x - x - 1;
|
||||
int yofs = siz.y * x;
|
||||
int xofs = width - x - 1;
|
||||
int yofs = height * x;
|
||||
|
||||
for (int y = 0; y < siz.y; ++y)
|
||||
*(dst + y * siz.x + xofs) = *(src + y + yofs);
|
||||
for (int y = 0; y < height; ++y)
|
||||
*(dst + y * width + xofs) = *(src + y + yofs);
|
||||
}
|
||||
|
||||
auto dtex = new FLooseTile(dbuffer, tex->GetHeight(), tex->GetWidth());
|
||||
auto dtex = new FLooseTile(dbuffer, tex->GetTexelHeight(), tex->GetTexelWidth());
|
||||
int index = findUnusedTile();
|
||||
bool mapart = TileFiles.tiledata[tileNum].texture != TileFiles.tiledata[tileNum].backup;
|
||||
TileFiles.AddTile(index, dtex, mapart);
|
||||
|
@ -845,33 +804,36 @@ void BuildTiles::CloseAll()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int tileSetHightileReplacement(int picnum, int palnum, const char *filename, float alphacut, float xscale, float yscale, float specpower, float specfactor, uint8_t flags)
|
||||
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor, uint8_t flags)
|
||||
{
|
||||
if ((uint32_t)picnum >= (uint32_t)MAXTILES) return -1;
|
||||
if ((uint32_t)palnum >= (uint32_t)MAXPALOOKUPS) return -1;
|
||||
if ((uint32_t)picnum >= (uint32_t)MAXTILES) return -1;
|
||||
if ((uint32_t)palnum >= (uint32_t)MAXPALOOKUPS) return -1;
|
||||
|
||||
auto tex = tileGetTexture(picnum);
|
||||
if (tex->GetWidth() <= 0 || tex->GetHeight() <= 0)
|
||||
if (tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0)
|
||||
{
|
||||
Printf("Warning: defined hightile replacement for empty tile %d.", picnum);
|
||||
return -1; // cannot add replacements to empty tiles, must create one beforehand
|
||||
}
|
||||
HightileReplacement replace = {};
|
||||
|
||||
replace.faces[0] = TileFiles.GetTexture(filename);
|
||||
if (replace.faces[0] == nullptr)
|
||||
FTextureID texid = TexMan.CheckForTexture(filename, ETextureType::Any);
|
||||
if (!texid.isValid())
|
||||
{
|
||||
Printf("%s: Replacement for tile %d does not exist or is invalid\n", filename, picnum);
|
||||
return -1;
|
||||
}
|
||||
replace.alphacut = min(alphacut,1.f);
|
||||
|
||||
replace.faces[0] = TexMan.GetTexture(texid);
|
||||
if (replace.faces[0] == nullptr)
|
||||
replace.alphacut = min(alphacut, 1.f);
|
||||
replace.scale = { xscale, yscale };
|
||||
replace.specpower = specpower; // currently unused
|
||||
replace.specfactor = specfactor; // currently unused
|
||||
replace.flags = flags;
|
||||
replace.specpower = specpower; // currently unused
|
||||
replace.specfactor = specfactor; // currently unused
|
||||
replace.flags = flags;
|
||||
replace.palnum = (uint16_t)palnum;
|
||||
TileFiles.AddReplacement(picnum, replace);
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -887,7 +849,7 @@ int tileSetSkybox(int picnum, int palnum, const char **facenames, int flags )
|
|||
if ((uint32_t)palnum >= (uint32_t)MAXPALOOKUPS) return -1;
|
||||
|
||||
auto tex = tileGetTexture(picnum);
|
||||
if (tex->GetWidth() <= 0 || tex->GetHeight() <= 0)
|
||||
if (tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0)
|
||||
{
|
||||
Printf("Warning: defined skybox replacement for empty tile %d.", picnum);
|
||||
return -1; // cannot add replacements to empty tiles, must create one beforehand
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "textures.h"
|
||||
|
||||
#include "i_time.h"
|
||||
#include "compat.h"
|
||||
|
||||
// picanm[].sf:
|
||||
// |bit(1<<7)
|
||||
|
@ -69,10 +70,13 @@ struct HightileReplacement
|
|||
class FTileTexture : public FTexture
|
||||
{
|
||||
public:
|
||||
FTileTexture() = default;
|
||||
FTileTexture()
|
||||
{}
|
||||
virtual uint8_t* GetRawData() = 0;
|
||||
void SetName(const char* name) { Name = name; }
|
||||
FBitmap GetBgraBitmap(const PalEntry* remap, int* ptrans) override;
|
||||
void Create8BitPixels(uint8_t* buffer) override;
|
||||
TArray<uint8_t> Get8BitPixels(bool alphatex) override;
|
||||
FBitmap GetBgraBitmap(const PalEntry* remap, int* trans = nullptr) override;
|
||||
//bool GetTranslucency() override { return false; }
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
@ -86,15 +90,14 @@ class FArtTile : public FTileTexture
|
|||
const TArray<uint8_t>& RawPixels;
|
||||
const uint32_t Offset;
|
||||
public:
|
||||
FArtTile(const TArray<uint8_t>& backingstore, uint32_t offset, int width, int height, int picanm)
|
||||
FArtTile(const TArray<uint8_t>& backingstore, uint32_t offset, int width, int height)
|
||||
: RawPixels(backingstore), Offset(offset)
|
||||
{
|
||||
SetSize(width, height);
|
||||
}
|
||||
|
||||
const uint8_t* Get8BitPixels() override
|
||||
uint8_t* GetRawData() override final
|
||||
{
|
||||
return RawPixels.Data() ? RawPixels.Data() + Offset : nullptr;
|
||||
return &RawPixels[Offset];
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -108,16 +111,17 @@ class FLooseTile : public FTileTexture
|
|||
{
|
||||
TArray<uint8_t> RawPixels;
|
||||
public:
|
||||
FLooseTile(TArray<uint8_t> &store, int width, int height)
|
||||
FLooseTile(TArray<uint8_t>& store, int width, int height)
|
||||
{
|
||||
RawPixels = std::move(store);
|
||||
SetSize(width, height);
|
||||
}
|
||||
|
||||
const uint8_t* Get8BitPixels() override
|
||||
uint8_t* GetRawData() override
|
||||
{
|
||||
return RawPixels.Data();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
@ -134,9 +138,9 @@ public:
|
|||
SetSize(width, height);
|
||||
}
|
||||
|
||||
const uint8_t* Get8BitPixels() override
|
||||
uint8_t* GetRawData() override
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -152,20 +156,19 @@ protected:
|
|||
TArray<uint8_t> buffer;
|
||||
|
||||
public:
|
||||
const uint8_t* Get8BitPixels() override
|
||||
FWritableTile()
|
||||
{
|
||||
return buffer.Data();
|
||||
//useType = Writable;
|
||||
}
|
||||
|
||||
uint8_t* GetWritableBuffer() override
|
||||
uint8_t* GetRawData() override
|
||||
{
|
||||
// Todo: Invalidate all hardware textures depending on this.
|
||||
return buffer.Data();
|
||||
}
|
||||
|
||||
bool Resize(int w, int h)
|
||||
{
|
||||
if (w <= 0 || h <= 0)
|
||||
if (w <= 0 || h <= 0)
|
||||
{
|
||||
buffer.Reset();
|
||||
return false;
|
||||
|
@ -195,13 +198,13 @@ public:
|
|||
{
|
||||
Base = base;
|
||||
CopySize(base);
|
||||
Resize(GetWidth(), GetHeight());
|
||||
Resize(GetTexelWidth(), GetTexelHeight());
|
||||
Reload();
|
||||
}
|
||||
|
||||
void Reload() override
|
||||
void Reload()
|
||||
{
|
||||
Base->Create8BitPixels(buffer.Data());
|
||||
buffer = std::move(Base->Get8BitPixels(false));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -364,21 +367,31 @@ extern BuildTiles TileFiles;
|
|||
inline bool tileCheck(int num)
|
||||
{
|
||||
auto tex = TileFiles.tiledata[num].texture;
|
||||
return tex->GetWidth() > 0 && tex->GetHeight() > 0;
|
||||
return tex && tex->GetTexelWidth() > 0 && tex->GetTexelHeight() > 0;
|
||||
}
|
||||
|
||||
inline const uint8_t* tilePtr(int num)
|
||||
{
|
||||
auto tex = TileFiles.tiledata[num].texture;
|
||||
auto p = tex->Get8BitPixels();
|
||||
if (p) return p;
|
||||
return tex->CachedPixels.Data();
|
||||
if (TileFiles.tiledata[num].rawCache.data.Size() == 0)
|
||||
{
|
||||
auto tex = TileFiles.tiledata[num].texture;
|
||||
if (!tex || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return nullptr;
|
||||
TileFiles.tiledata[num].rawCache.data = std::move(tex->Get8BitPixels(false));
|
||||
}
|
||||
TileFiles.tiledata[num].rawCache.lastUseTime = I_nsTime();
|
||||
return TileFiles.tiledata[num].rawCache.data.Data();
|
||||
}
|
||||
|
||||
inline bool tileLoad(int tileNum)
|
||||
{
|
||||
return !!tilePtr(tileNum);
|
||||
}
|
||||
|
||||
inline uint8_t* tileData(int num)
|
||||
{
|
||||
auto tex = TileFiles.tiledata[num].texture;
|
||||
return tex->GetWritableBuffer();
|
||||
auto p = dynamic_cast<FWritableTile*>(tex);
|
||||
return p ? p->GetRawData() : nullptr;
|
||||
}
|
||||
|
||||
// Some hacks to allow accessing the no longer existing arrays as if they still were arrays to avoid changing hundreds of lines of code.
|
||||
|
|
|
@ -34,10 +34,11 @@
|
|||
*/
|
||||
|
||||
#include "files.h"
|
||||
#include "filesystem.h"
|
||||
#include "templates.h"
|
||||
#include "bitmap.h"
|
||||
#include "image.h"
|
||||
#include "imagehelpers.h"
|
||||
#include "textures.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
|
@ -46,17 +47,19 @@
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FImageTexture::FImageTexture(FImageSource *img, const char *name)
|
||||
: FTexture(name)
|
||||
FImageTexture::FImageTexture(FImageSource* img, const char* name) noexcept
|
||||
: FTexture(name, img ? img->LumpNum() : 0)
|
||||
{
|
||||
mImage = img;
|
||||
if (img != nullptr)
|
||||
{
|
||||
SetSize(img->GetWidth(), img->GetHeight());
|
||||
if (name == nullptr) fileSystem.GetFileShortName(Name, img->LumpNum());
|
||||
Width = img->GetWidth();
|
||||
Height = img->GetHeight();
|
||||
|
||||
auto offsets = img->GetOffsets();
|
||||
leftoffset = offsets.first;
|
||||
topoffset = offsets.second;
|
||||
_LeftOffset[1] = _LeftOffset[0] = offsets.first;
|
||||
_TopOffset[1] = _TopOffset[0] = offsets.second;
|
||||
|
||||
bMasked = img->bMasked;
|
||||
bTranslucent = img->bTranslucent;
|
||||
|
@ -69,9 +72,9 @@ FImageTexture::FImageTexture(FImageSource *img, const char *name)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
FBitmap FImageTexture::GetBgraBitmap(const PalEntry *p, int *trans)
|
||||
FBitmap FImageTexture::GetBgraBitmap(const PalEntry* p, int* trans)
|
||||
{
|
||||
return mImage->GetCachedBitmap(p, FImageSource::normal, trans);
|
||||
return mImage->GetCachedBitmap(p, bNoRemap0 ? FImageSource::noremap0 : FImageSource::normal, trans);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -80,15 +83,14 @@ FBitmap FImageTexture::GetBgraBitmap(const PalEntry *p, int *trans)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
void FImageTexture::Create8BitPixels(uint8_t* buffer)
|
||||
TArray<uint8_t> FImageTexture::Get8BitPixels(bool alpha)
|
||||
{
|
||||
//ImageHelpers::alphaThreshold = alphaThreshold;
|
||||
auto buf = mImage->GetPalettedPixels(FImageSource::normal);
|
||||
memcpy(buffer, buf.Data(), buf.Size());
|
||||
return mImage->GetPalettedPixels(alpha ? alpha : bNoRemap0 ? FImageSource::noremap0 : FImageSource::normal);
|
||||
}
|
||||
|
||||
FTexture* CreateImageTexture(FImageSource* img, const char *name) noexcept
|
||||
|
||||
FTexture* CreateImageTexture(FImageSource* img, const char* name) noexcept
|
||||
{
|
||||
return new FImageTexture(img, name);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,16 +34,30 @@
|
|||
**
|
||||
*/
|
||||
|
||||
#include "printf.h"
|
||||
#include "files.h"
|
||||
#include "filesystem.h"
|
||||
#include "templates.h"
|
||||
|
||||
#include "textures.h"
|
||||
#include "bitmap.h"
|
||||
#include "colormatcher.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "m_fixed.h"
|
||||
#include "imagehelpers.h"
|
||||
#include "image.h"
|
||||
#include "palette.h"
|
||||
#include "../glbackend/gl_hwtexture.h"
|
||||
#include "build.h"
|
||||
#include "formats/multipatchtexture.h"
|
||||
#include "texturemanager.h"
|
||||
|
||||
FTexture *CreateBrightmapTexture(FImageSource*);
|
||||
// Wrappers to keep the definitions of these classes out of here.
|
||||
void DeleteMaterial(FMaterial* mat) {}
|
||||
void DeleteSoftwareTexture(FSoftwareTexture* swtex) {}
|
||||
IHardwareTexture* CreateHardwareTexture();
|
||||
|
||||
|
||||
FTexture* CreateBrightmapTexture(FImageSource*);
|
||||
|
||||
// Make sprite offset adjustment user-configurable per renderer.
|
||||
int r_spriteadjustSW, r_spriteadjustHW;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -54,20 +68,38 @@ 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, int lump, ETextureType useType)
|
||||
FTexture* FTexture::CreateTexture(const char* name, int lumpnum, ETextureType usetype)
|
||||
{
|
||||
if (lump < 0)
|
||||
{
|
||||
lump = fileSystem.FindFile(name);
|
||||
if (lump < 0) return nullptr;
|
||||
}
|
||||
auto image = FImageSource::GetImage(lump, false);
|
||||
if (lumpnum == -1) return nullptr;
|
||||
|
||||
auto image = FImageSource::GetImage(lumpnum, usetype == ETextureType::Flat);
|
||||
if (image != nullptr)
|
||||
{
|
||||
FTexture *tex = new FImageTexture(image);
|
||||
if (tex != nullptr)
|
||||
FTexture* tex = new FImageTexture(image);
|
||||
if (tex != nullptr)
|
||||
{
|
||||
tex->UseType = usetype;
|
||||
if (usetype == ETextureType::Flat)
|
||||
{
|
||||
int w = tex->GetTexelWidth();
|
||||
int h = tex->GetTexelHeight();
|
||||
|
||||
// Auto-scale flats with dimensions 128x128 and 256x256.
|
||||
// In hindsight, a bad idea, but RandomLag made it sound better than it really is.
|
||||
// Now we're stuck with this stupid behaviour.
|
||||
if (w == 128 && h == 128)
|
||||
{
|
||||
tex->Scale.X = tex->Scale.Y = 2;
|
||||
tex->bWorldPanning = true;
|
||||
}
|
||||
else if (w == 256 && h == 256)
|
||||
{
|
||||
tex->Scale.X = tex->Scale.Y = 4;
|
||||
tex->bWorldPanning = true;
|
||||
}
|
||||
}
|
||||
tex->Name = name;
|
||||
tex->Name.ToUpper();
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
|
@ -80,13 +112,58 @@ FTexture * FTexture::CreateTexture(const char *name, int lump, ETextureType useT
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FTexture::FTexture (const char *name)
|
||||
FTexture::FTexture(const char* name, int lumpnum)
|
||||
:
|
||||
Scale(1, 1), SourceLump(lumpnum),
|
||||
UseType(ETextureType::Any), bNoDecals(false), bNoRemap0(false), bWorldPanning(false),
|
||||
bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(0), bComplex(false), bMultiPatch(false), bFullNameTexture(false),
|
||||
Rotations(0xFFFF), SkyOffset(0), Width(0), Height(0)
|
||||
{
|
||||
Name = name;
|
||||
bBrightmapChecked = false;
|
||||
bGlowing = false;
|
||||
bAutoGlowing = false;
|
||||
bFullbright = false;
|
||||
bDisableFullbright = false;
|
||||
bSkybox = false;
|
||||
bNoCompress = false;
|
||||
bNoExpand = false;
|
||||
bTranslucent = -1;
|
||||
|
||||
|
||||
_LeftOffset[0] = _LeftOffset[1] = _TopOffset[0] = _TopOffset[1] = 0;
|
||||
id.SetInvalid();
|
||||
if (name != NULL)
|
||||
{
|
||||
Name = name;
|
||||
Name.ToUpper();
|
||||
}
|
||||
else if (lumpnum < 0)
|
||||
{
|
||||
Name = FString();
|
||||
}
|
||||
else
|
||||
{
|
||||
fileSystem.GetFileShortName(Name, lumpnum);
|
||||
}
|
||||
}
|
||||
|
||||
FTexture::~FTexture ()
|
||||
FTexture::~FTexture()
|
||||
{
|
||||
FTexture* link = fileSystem.GetLinkedTexture(SourceLump);
|
||||
if (link == this) fileSystem.SetLinkedTexture(SourceLump, nullptr);
|
||||
if (areas != nullptr) delete[] areas;
|
||||
areas = nullptr;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (Material[i] != nullptr) DeleteMaterial(Material[i]);
|
||||
Material[i] = nullptr;
|
||||
}
|
||||
if (SoftwareTexture != nullptr)
|
||||
{
|
||||
DeleteSoftwareTexture(SoftwareTexture);
|
||||
SoftwareTexture = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -98,20 +175,62 @@ FTexture::~FTexture ()
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
FBitmap FTexture::GetBgraBitmap(const PalEntry *remap, int *ptrans)
|
||||
FBitmap FTexture::GetBgraBitmap(const PalEntry* remap, int* ptrans)
|
||||
{
|
||||
FBitmap bmp;
|
||||
bmp.Create(Size.x, Size.y);
|
||||
bmp.Create(Width, Height);
|
||||
return bmp;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FTexture* FTexture::GetRawTexture()
|
||||
{
|
||||
if (OffsetLess) return OffsetLess;
|
||||
// Reject anything that cannot have been a single-patch multipatch texture in vanilla.
|
||||
auto image = static_cast<FMultiPatchTexture*>(GetImage());
|
||||
if (bMultiPatch != 1 || UseType != ETextureType::Wall || Scale.X != 1 || Scale.Y != 1 || bWorldPanning || image == nullptr || image->NumParts != 1 || _TopOffset[0] == 0)
|
||||
{
|
||||
OffsetLess = this;
|
||||
return this;
|
||||
}
|
||||
// Set up a new texture that directly references the underlying patch.
|
||||
// From here we cannot retrieve the original texture made for it, so just create a new one.
|
||||
FImageSource* source = image->Parts[0].Image;
|
||||
|
||||
// Size must match for this to work as intended
|
||||
if (source->GetWidth() != Width || source->GetHeight() != Height)
|
||||
{
|
||||
OffsetLess = this;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
OffsetLess = new FImageTexture(source, "");
|
||||
TexMan.AddTexture(OffsetLess);
|
||||
return OffsetLess;
|
||||
}
|
||||
|
||||
void FTexture::SetDisplaySize(int fitwidth, int fitheight)
|
||||
{
|
||||
Scale.X = double(Width) / fitwidth;
|
||||
Scale.Y = double(Height) / fitheight;
|
||||
// compensate for roundoff errors
|
||||
if (int(Scale.X * fitwidth) != Width) Scale.X += (1 / 65536.);
|
||||
if (int(Scale.Y * fitheight) != Height) Scale.Y += (1 / 65536.);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Gets the average color of a texture for use as a sky cap color
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
PalEntry FTexture::averageColor(const uint32_t *data, int size, int maxout)
|
||||
PalEntry FTexture::averageColor(const uint32_t* data, int size, int maxout)
|
||||
{
|
||||
int i;
|
||||
unsigned int r, g, b;
|
||||
|
@ -133,34 +252,34 @@ PalEntry FTexture::averageColor(const uint32_t *data, int size, int maxout)
|
|||
g = g / size;
|
||||
b = b / size;
|
||||
|
||||
int maxv = std::max(std::max(r, g), b);
|
||||
int maxv = MAX(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;
|
||||
r = ::Scale(r, maxout, maxv);
|
||||
g = ::Scale(g, maxout, maxv);
|
||||
b = ::Scale(b, maxout, maxv);
|
||||
}
|
||||
return PalEntry(255, r, g, b);
|
||||
}
|
||||
|
||||
PalEntry FTexture::GetSkyCapColor(bool bottom)
|
||||
{
|
||||
if (!skyColorDone)
|
||||
if (!bSWSkyColorDone)
|
||||
{
|
||||
skyColorDone = true;
|
||||
bSWSkyColorDone = true;
|
||||
|
||||
FBitmap bitmap = GetBgraBitmap(nullptr);
|
||||
int w = bitmap.GetWidth();
|
||||
int h = bitmap.GetHeight();
|
||||
|
||||
const uint32_t *buffer = (const uint32_t *)bitmap.GetPixels();
|
||||
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)
|
||||
CeilingSkyColor = averageColor((uint32_t*)buffer, w * MIN(30, h), 0);
|
||||
if (h > 30)
|
||||
{
|
||||
FloorSkyColor = averageColor(((uint32_t *)buffer) + (h - 30)*w, w * 30, 0);
|
||||
FloorSkyColor = averageColor(((uint32_t*)buffer) + (h - 30) * w, w * 30, 0);
|
||||
}
|
||||
else FloorSkyColor = CeilingSkyColor;
|
||||
}
|
||||
|
@ -168,6 +287,245 @@ PalEntry FTexture::GetSkyCapColor(bool bottom)
|
|||
return bottom ? FloorSkyColor : CeilingSkyColor;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// CheckRealHeight
|
||||
//
|
||||
// Checks the posts in a texture and returns the lowest row (plus one)
|
||||
// of the texture that is actually used.
|
||||
//
|
||||
//====================================================================
|
||||
|
||||
int FTexture::CheckRealHeight()
|
||||
{
|
||||
auto pixels = Get8BitPixels(false);
|
||||
|
||||
for (int h = GetTexelHeight() - 1; h >= 0; h--)
|
||||
{
|
||||
for (int w = 0; w < GetTexelWidth(); w++)
|
||||
{
|
||||
if (pixels[h + w * GetTexelHeight()] != 0)
|
||||
{
|
||||
// Scale maxy before returning it
|
||||
h = int((h * 2) / Scale.Y);
|
||||
h = (h >> 1) + (h & 1);
|
||||
return h;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Search auto paths for extra material textures
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FTexture::AddAutoMaterials()
|
||||
{
|
||||
struct AutoTextureSearchPath
|
||||
{
|
||||
const char* path;
|
||||
FTexture* FTexture::* pointer;
|
||||
};
|
||||
|
||||
static AutoTextureSearchPath autosearchpaths[] =
|
||||
{
|
||||
{ "brightmaps/", &FTexture::Brightmap }, // For backwards compatibility, only for short names
|
||||
{ "materials/brightmaps/", &FTexture::Brightmap },
|
||||
{ "materials/normalmaps/", &FTexture::Normal },
|
||||
{ "materials/specular/", &FTexture::Specular },
|
||||
{ "materials/metallic/", &FTexture::Metallic },
|
||||
{ "materials/roughness/", &FTexture::Roughness },
|
||||
{ "materials/ao/", &FTexture::AmbientOcclusion }
|
||||
};
|
||||
|
||||
|
||||
int startindex = bFullNameTexture ? 1 : 0;
|
||||
FString searchname = Name;
|
||||
|
||||
if (bFullNameTexture)
|
||||
{
|
||||
auto dot = searchname.LastIndexOf('.');
|
||||
auto slash = searchname.LastIndexOf('/');
|
||||
if (dot > slash) searchname.Truncate(dot);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < countof(autosearchpaths); i++)
|
||||
{
|
||||
auto& layer = autosearchpaths[i];
|
||||
if (this->*(layer.pointer) == nullptr) // only if no explicit assignment had been done.
|
||||
{
|
||||
FStringf lookup("%s%s%s", layer.path, bFullNameTexture ? "" : "auto/", searchname.GetChars());
|
||||
auto lump = fileSystem.CheckNumForFullName(lookup, false, ns_global, true);
|
||||
if (lump != -1)
|
||||
{
|
||||
auto bmtex = TexMan.FindTexture(fileSystem.GetFileFullName(lump), ETextureType::Any, FTextureManager::TEXMAN_TryAny);
|
||||
if (bmtex != nullptr)
|
||||
{
|
||||
bmtex->bMasked = false;
|
||||
this->*(layer.pointer) = bmtex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Checks if the texture has a default brightmap and creates it if so
|
||||
//
|
||||
//===========================================================================
|
||||
void FTexture::CreateDefaultBrightmap()
|
||||
{
|
||||
if (!bBrightmapChecked)
|
||||
{
|
||||
// Check for brightmaps
|
||||
if (GetImage() && GetImage()->UseGamePalette() && GPalette.HasGlobalBrightmap &&
|
||||
UseType != ETextureType::Decal && UseType != ETextureType::MiscPatch && UseType != ETextureType::FontChar &&
|
||||
Brightmap == NULL && bWarped == 0)
|
||||
{
|
||||
// May have one - let's check when we use this texture
|
||||
auto texbuf = Get8BitPixels(false);
|
||||
const int white = ColorMatcher.Pick(255, 255, 255);
|
||||
|
||||
int size = GetTexelWidth() * GetTexelHeight();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (GPalette.GlobalBrightmap.Remap[texbuf[i]] == white)
|
||||
{
|
||||
// Create a brightmap
|
||||
DPrintf(DMSG_NOTIFY, "brightmap created for texture '%s'\n", Name.GetChars());
|
||||
Brightmap = CreateBrightmapTexture(static_cast<FImageTexture*>(this)->GetImage());
|
||||
bBrightmapChecked = true;
|
||||
TexMan.AddTexture(Brightmap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// No bright pixels found
|
||||
DPrintf(DMSG_SPAMMY, "No bright pixels found in texture '%s'\n", Name.GetChars());
|
||||
bBrightmapChecked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// does not have one so set the flag to 'done'
|
||||
bBrightmapChecked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Calculates glow color for a texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FTexture::GetGlowColor(float* data)
|
||||
{
|
||||
if (bGlowing && GlowColor == 0)
|
||||
{
|
||||
auto buffer = GetBgraBitmap(nullptr);
|
||||
GlowColor = averageColor((uint32_t*)buffer.GetPixels(), buffer.GetWidth() * buffer.GetHeight(), 153);
|
||||
|
||||
// Black glow equals nothing so switch glowing off
|
||||
if (GlowColor == 0) bGlowing = false;
|
||||
}
|
||||
data[0] = GlowColor.r / 255.0f;
|
||||
data[1] = GlowColor.g / 255.0f;
|
||||
data[2] = GlowColor.b / 255.0f;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Finds gaps in the texture which can be skipped by the renderer
|
||||
// This was mainly added to speed up one area in E4M6 of 007LTSD
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FTexture::FindHoles(const unsigned char* buffer, int w, int h)
|
||||
{
|
||||
const unsigned char* li;
|
||||
int y, x;
|
||||
int startdraw, lendraw;
|
||||
int gaps[5][2];
|
||||
int gapc = 0;
|
||||
|
||||
|
||||
// already done!
|
||||
if (areacount) return false;
|
||||
if (UseType == ETextureType::Flat) return false; // flats don't have transparent parts
|
||||
areacount = -1; //whatever happens next, it shouldn't be done twice!
|
||||
|
||||
// large textures are excluded for performance reasons
|
||||
if (h > 512) return false;
|
||||
|
||||
startdraw = -1;
|
||||
lendraw = 0;
|
||||
for (y = 0; y < h; y++)
|
||||
{
|
||||
li = buffer + w * y * 4 + 3;
|
||||
|
||||
for (x = 0; x < w; x++, li += 4)
|
||||
{
|
||||
if (*li != 0) break;
|
||||
}
|
||||
|
||||
if (x != w)
|
||||
{
|
||||
// non - transparent
|
||||
if (startdraw == -1)
|
||||
{
|
||||
startdraw = y;
|
||||
// merge transparent gaps of less than 16 pixels into the last drawing block
|
||||
if (gapc && y <= gaps[gapc - 1][0] + gaps[gapc - 1][1] + 16)
|
||||
{
|
||||
gapc--;
|
||||
startdraw = gaps[gapc][0];
|
||||
lendraw = y - startdraw;
|
||||
}
|
||||
if (gapc == 4) return false; // too many splits - this isn't worth it
|
||||
}
|
||||
lendraw++;
|
||||
}
|
||||
else if (startdraw != -1)
|
||||
{
|
||||
if (lendraw == 1) lendraw = 2;
|
||||
gaps[gapc][0] = startdraw;
|
||||
gaps[gapc][1] = lendraw;
|
||||
gapc++;
|
||||
|
||||
startdraw = -1;
|
||||
lendraw = 0;
|
||||
}
|
||||
}
|
||||
if (startdraw != -1)
|
||||
{
|
||||
gaps[gapc][0] = startdraw;
|
||||
gaps[gapc][1] = lendraw;
|
||||
gapc++;
|
||||
}
|
||||
if (startdraw == 0 && lendraw == h) return false; // nothing saved so don't create a split list
|
||||
|
||||
if (gapc > 0)
|
||||
{
|
||||
FloatRect* rcs = new FloatRect[gapc];
|
||||
|
||||
for (x = 0; x < gapc; x++)
|
||||
{
|
||||
// gaps are stored as texture (u/v) coordinates
|
||||
rcs[x].width = rcs[x].left = -1.0f;
|
||||
rcs[x].top = (float)gaps[x][0] / (float)h;
|
||||
rcs[x].height = (float)gaps[x][1] / (float)h;
|
||||
}
|
||||
areas = rcs;
|
||||
}
|
||||
else areas = nullptr;
|
||||
areacount = gapc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -175,15 +533,15 @@ PalEntry FTexture::GetSkyCapColor(bool bottom)
|
|||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void FTexture::CheckTrans(unsigned char * buffer, int size, int trans)
|
||||
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* dwbuf = (uint32_t*)buffer;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
uint32_t alpha = dwbuf[i] >> 24;
|
||||
|
||||
|
@ -213,15 +571,15 @@ void FTexture::CheckTrans(unsigned char * buffer, int size, int trans)
|
|||
#define SOME_MASK 0x00ffffff
|
||||
#endif
|
||||
|
||||
#define CHKPIX(ofs) (l1[(ofs)*4+MSB]==TRANSPARENT_INDEX ? (( ((uint32_t*)l1)[0] = ((uint32_t*)l1)[ofs]&SOME_MASK), trans=true ) : false)
|
||||
#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)
|
||||
bool 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
|
||||
bool 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;
|
||||
bool semitrans = false;
|
||||
unsigned char* l1;
|
||||
|
||||
if (h <= 1 || w <= 1) return false; // makes (a) no sense and (b) doesn't work with this code!
|
||||
|
||||
|
@ -229,44 +587,44 @@ int FTexture::SmoothEdges(unsigned char * buffer, int w, int h)
|
|||
|
||||
|
||||
if (l1[MSB] == 0 && !CHKPIX(1)) CHKPIX(w);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
else if (l1[MSB] < 255) semitrans = true;
|
||||
l1 += 4;
|
||||
for (x = 1; x<w - 1; x++, 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;
|
||||
else if (l1[MSB] < 255) semitrans = true;
|
||||
}
|
||||
if (l1[MSB] == 0 && !CHKPIX(-1)) CHKPIX(w);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
else if (l1[MSB] < 255) semitrans = true;
|
||||
l1 += 4;
|
||||
|
||||
for (y = 1; y<h - 1; y++)
|
||||
for (y = 1; y < h - 1; y++)
|
||||
{
|
||||
if (l1[MSB] == 0 && !CHKPIX(-w) && !CHKPIX(1)) CHKPIX(w);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
else if (l1[MSB] < 255) semitrans = true;
|
||||
l1 += 4;
|
||||
for (x = 1; x<w - 1; x++, 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;
|
||||
else if (l1[MSB] < 255) semitrans = true;
|
||||
}
|
||||
if (l1[MSB] == 0 && !CHKPIX(-w) && !CHKPIX(-1)) CHKPIX(w);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
else if (l1[MSB] < 255) semitrans = true;
|
||||
l1 += 4;
|
||||
}
|
||||
|
||||
if (l1[MSB] == 0 && !CHKPIX(-w)) CHKPIX(1);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
else if (l1[MSB] < 255) semitrans = true;
|
||||
l1 += 4;
|
||||
for (x = 1; x<w - 1; x++, 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;
|
||||
else if (l1[MSB] < 255) semitrans = true;
|
||||
}
|
||||
if (l1[MSB] == 0 && !CHKPIX(-w)) CHKPIX(-1);
|
||||
else if (l1[MSB]<255) semitrans = true;
|
||||
else if (l1[MSB] < 255) semitrans = true;
|
||||
|
||||
return trans || (semitrans << 1);
|
||||
return trans || semitrans;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -275,12 +633,12 @@ int FTexture::SmoothEdges(unsigned char * buffer, int w, int h)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FTexture::ProcessData(unsigned char * buffer, int w, int h, bool ispatch)
|
||||
bool FTexture::ProcessData(unsigned char* buffer, int w, int h, bool ispatch)
|
||||
{
|
||||
if (bMasked)
|
||||
{
|
||||
int res = SmoothEdges(buffer, w, h);
|
||||
bMasked = !!(res & 1);
|
||||
bMasked = SmoothEdges(buffer, w, h);
|
||||
if (bMasked && !ispatch) FindHoles(buffer, w, h);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -291,21 +649,246 @@ bool FTexture::ProcessData(unsigned char * buffer, int w, int h, bool ispatch)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
FTextureBuffer FTexture::CreateTexBuffer(const PalEntry * remap, int flags)
|
||||
FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
|
||||
{
|
||||
FTextureBuffer result;
|
||||
|
||||
unsigned char * buffer = nullptr;
|
||||
unsigned char* buffer = nullptr;
|
||||
int W, H;
|
||||
int isTransparent = -1;
|
||||
bool checkonly = !!(flags & CTF_CheckOnly);
|
||||
|
||||
W = GetWidth();
|
||||
H = GetHeight();
|
||||
int exx = !!(flags & CTF_Expand);
|
||||
|
||||
W = GetTexelWidth() + 2 * exx;
|
||||
H = GetTexelHeight() + 2 * exx;
|
||||
|
||||
if (!checkonly)
|
||||
{
|
||||
buffer = new unsigned char[W*(H + 1) * 4];
|
||||
buffer = new unsigned char[W * (H + 1) * 4];
|
||||
memset(buffer, 0, W * (H + 1) * 4);
|
||||
|
||||
auto remap = translation <= 0 ? nullptr : GPalette.TranslationToTable(translation);
|
||||
FBitmap bmp(buffer, W * 4, W, H);
|
||||
|
||||
int trans;
|
||||
auto Pixels = GetBgraBitmap(remap ? remap->Palette : nullptr, &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 = 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)
|
||||
{
|
||||
#pragma message("Activate me")
|
||||
#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 (!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;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Coordinate helper.
|
||||
// The only reason this is even needed is that many years ago someone
|
||||
// was convinced that having per-texel panning on walls was a good idea.
|
||||
// If it wasn't for this relatively useless feature the entire positioning
|
||||
// code for wall textures could be a lot simpler.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
float FTexCoordInfo::RowOffset(float rowoffset) const
|
||||
{
|
||||
float scale = fabs(mScale.Y);
|
||||
if (scale == 1.f || mWorldPanning) return rowoffset;
|
||||
else return rowoffset / scale;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
float FTexCoordInfo::TextureOffset(float textureoffset) const
|
||||
{
|
||||
float scale = fabs(mScale.X);
|
||||
if (scale == 1.f || mWorldPanning) return textureoffset;
|
||||
else return textureoffset / scale;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Returns the size for which texture offset coordinates are used.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
float FTexCoordInfo::TextureAdjustWidth() const
|
||||
{
|
||||
if (mWorldPanning)
|
||||
{
|
||||
float tscale = fabs(mTempScale.X);
|
||||
if (tscale == 1.f) return (float)mRenderWidth;
|
||||
else return mWidth / fabs(tscale);
|
||||
}
|
||||
else return (float)mWidth;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Retrieve texture coordinate info for per-wall scaling
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FTexCoordInfo::GetFromTexture(FTexture* tex, float x, float y, bool forceworldpanning)
|
||||
{
|
||||
if (x == 1.f)
|
||||
{
|
||||
mRenderWidth = tex->GetScaledWidth();
|
||||
mScale.X = (float)tex->Scale.X;
|
||||
mTempScale.X = 1.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
float scale_x = x * (float)tex->Scale.X;
|
||||
mRenderWidth = xs_CeilToInt(tex->GetTexelWidth() / scale_x);
|
||||
mScale.X = scale_x;
|
||||
mTempScale.X = x;
|
||||
}
|
||||
|
||||
if (y == 1.f)
|
||||
{
|
||||
mRenderHeight = tex->GetScaledHeight();
|
||||
mScale.Y = (float)tex->Scale.Y;
|
||||
mTempScale.Y = 1.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
float scale_y = y * (float)tex->Scale.Y;
|
||||
mRenderHeight = xs_CeilToInt(tex->GetTexelHeight() / scale_y);
|
||||
mScale.Y = scale_y;
|
||||
mTempScale.Y = y;
|
||||
}
|
||||
if (tex->bHasCanvas)
|
||||
{
|
||||
mScale.Y = -mScale.Y;
|
||||
mRenderHeight = -mRenderHeight;
|
||||
}
|
||||
mWorldPanning = tex->bWorldPanning || forceworldpanning;
|
||||
mWidth = tex->GetTexelWidth();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// this must be copied back to textures.cpp later.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FWrapperTexture::FWrapperTexture(int w, int h, int bits)
|
||||
{
|
||||
Width = w;
|
||||
Height = h;
|
||||
Format = bits;
|
||||
UseType = ETextureType::SWCanvas;
|
||||
bNoCompress = true;
|
||||
auto hwtex = CreateHardwareTexture();
|
||||
// todo: Initialize here.
|
||||
SystemTextures.AddHardwareTexture(0, false, hwtex);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Initializes the buffer for the texture data
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FTextureBuffer FTexture::CreateTexBuffer(const PalEntry* remap, int flags)
|
||||
{
|
||||
FTextureBuffer result;
|
||||
|
||||
unsigned char* buffer = nullptr;
|
||||
int W, H;
|
||||
int isTransparent = -1;
|
||||
bool checkonly = !!(flags & CTF_CheckOnly);
|
||||
|
||||
W = GetTexelWidth();
|
||||
H = GetTexelHeight();
|
||||
|
||||
if (!checkonly)
|
||||
{
|
||||
buffer = new unsigned char[W * (H + 1) * 4];
|
||||
memset(buffer, 0, W * (H + 1) * 4);
|
||||
|
||||
FBitmap bmp(buffer, W * 4, W, H);
|
||||
|
@ -316,7 +899,7 @@ FTextureBuffer FTexture::CreateTexBuffer(const PalEntry * remap, int flags)
|
|||
|
||||
if (remap == nullptr)
|
||||
{
|
||||
CheckTrans(buffer, W*H, trans);
|
||||
CheckTrans(buffer, W * H, trans);
|
||||
isTransparent = bTranslucent;
|
||||
}
|
||||
else
|
||||
|
@ -339,59 +922,4 @@ FTextureBuffer FTexture::CreateTexBuffer(const PalEntry * remap, int flags)
|
|||
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.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
const uint8_t* FTexture::Get8BitPixels()
|
||||
{
|
||||
return nullptr; // most textures do not provide a static buffer.
|
||||
}
|
||||
|
||||
void FTexture::Create8BitPixels(uint8_t *buffer)
|
||||
{
|
||||
// The base class does not fill the texture.
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FTexture::DeleteHardwareTextures()
|
||||
{
|
||||
decltype(HardwareTextures)::Iterator it(HardwareTextures);
|
||||
decltype(HardwareTextures)::Pair *pair;
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
delete pair->Value;
|
||||
}
|
||||
HardwareTextures.Clear();
|
||||
}
|
||||
|
|
|
@ -35,13 +35,18 @@
|
|||
#ifndef __TEXTURES_H
|
||||
#define __TEXTURES_H
|
||||
|
||||
#include "compat.h"
|
||||
#include "basics.h"
|
||||
#include "vectors.h"
|
||||
#include "colormatcher.h"
|
||||
#include "renderstyle.h"
|
||||
#include "textureid.h"
|
||||
#include "zstring.h"
|
||||
#include "tarray.h"
|
||||
#include "palentry.h"
|
||||
#include <vector>
|
||||
#include "hw_texcontainer.h"
|
||||
|
||||
class FHardwareTexture;
|
||||
// 15 because 0th texture is our texture
|
||||
#define MAX_CUSTOM_HW_SHADER_TEXTURES 15
|
||||
|
||||
typedef TMap<int, bool> SpriteHits;
|
||||
class FImageSource;
|
||||
|
||||
enum MaterialShaderIndex
|
||||
|
@ -199,116 +204,288 @@ struct FTextureBuffer
|
|||
// Base texture class
|
||||
class FTexture
|
||||
{
|
||||
friend struct BuildTiles;
|
||||
friend class FTextureManager;
|
||||
friend bool tileLoad(int tileNum);
|
||||
friend const uint8_t* tilePtr(int num);
|
||||
friend class GLDefsParser;
|
||||
friend class FMultipatchTextureBuilder;
|
||||
|
||||
// The serializer also needs access to more specific info that shouldn't be accessible through the interface.
|
||||
friend FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval);
|
||||
|
||||
// For now only give access to classes which cannot be reworked yet. None of these should remain here when all is done.
|
||||
friend class FSoftwareTexture;
|
||||
friend class FWarpTexture;
|
||||
friend class FMaterial;
|
||||
friend class OpenGLRenderer::FGLRenderState; // For now this needs access to some fields in ApplyMaterial. This should be rerouted through the Material class
|
||||
friend class VkRenderState;
|
||||
friend class PolyRenderState;
|
||||
friend struct FTexCoordInfo;
|
||||
friend class OpenGLRenderer::FHardwareTexture;
|
||||
friend class VkHardwareTexture;
|
||||
friend class PolyHardwareTexture;
|
||||
friend class FMultiPatchTexture;
|
||||
friend class FSkyBox;
|
||||
friend class FBrightmapTexture;
|
||||
friend class FFont;
|
||||
|
||||
|
||||
public:
|
||||
static FTexture* CreateTexture(const char* name, int lumpnum, ETextureType useType);
|
||||
|
||||
static FTexture *CreateTexture(const char *name, int lumpnum, ETextureType usetype);
|
||||
virtual ~FTexture ();
|
||||
virtual FImageSource *GetImage() const { return nullptr; }
|
||||
void AddAutoMaterials();
|
||||
void CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly);
|
||||
|
||||
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 void Create8BitPixels(uint8_t* buffer);
|
||||
virtual const uint8_t* Get8BitPixels();
|
||||
virtual uint8_t* GetWritableBuffer() { return nullptr; } // For dynamic tiles. Requesting this must also invalidate the texture.
|
||||
virtual FBitmap GetBgraBitmap(const 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() const { return Size.x; }
|
||||
int GetHeight() const { return Size.y; }
|
||||
int GetTexelWidth() const { return Size.x; }
|
||||
int GetTexelHeight() const { return Size.y; }
|
||||
int GetDisplayWidth() const { return Size.x; }
|
||||
int GetDisplayHeight() const { return Size.y; }
|
||||
const vec2_16_t &GetSize() const { return Size; }
|
||||
int GetLeftOffset() const { return leftoffset; }
|
||||
int GetTopOffset() const { return topoffset; }
|
||||
int GetDisplayLeftOffset() const { return leftoffset; }
|
||||
int GetDisplayTopOffset() const { return topoffset; }
|
||||
void SetOffsets(int x, int y) { leftoffset = x; topoffset = y; }
|
||||
FTextureBuffer CreateTexBuffer(const PalEntry *palette, 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);
|
||||
virtual void Reload() {}
|
||||
ETextureType GetUseType() const { return UseType; }
|
||||
void DeleteHardwareTextures();
|
||||
int GetSourceLump() { return SourceLump; }
|
||||
void SetUseType(ETextureType use) { UseType = use; }
|
||||
|
||||
void SetHardwareTexture(int palid, FHardwareTexture* htex)
|
||||
// These are mainly meant for 2D code which only needs logical information about the texture to position it properly.
|
||||
int GetDisplayWidth() { int foo = int((Width * 2) / Scale.X); return (foo >> 1) + (foo & 1); }
|
||||
int GetDisplayHeight() { int foo = int((Height * 2) / Scale.Y); return (foo >> 1) + (foo & 1); }
|
||||
double GetDisplayWidthDouble() { return Width / Scale.X; }
|
||||
double GetDisplayHeightDouble() { return Height / Scale.Y; }
|
||||
int GetDisplayLeftOffset() { return GetScaledLeftOffset(0); }
|
||||
int GetDisplayTopOffset() { return GetScaledTopOffset(0); }
|
||||
double GetDisplayLeftOffsetDouble() { return GetScaledLeftOffsetDouble(0); }
|
||||
double GetDisplayTopOffsetDouble() { return GetScaledTopOffsetDouble(0); }
|
||||
void SetOffsets(int l, int t)
|
||||
{
|
||||
HardwareTextures.Insert(palid, htex);
|
||||
_LeftOffset[0] = _LeftOffset[1] = l;
|
||||
_TopOffset[0] = _TopOffset[1] = l;
|
||||
}
|
||||
FHardwareTexture** GetHardwareTexture(int palid)
|
||||
{
|
||||
return HardwareTextures.CheckKey(palid);
|
||||
}
|
||||
|
||||
int alphaThreshold = 128;
|
||||
FixedBitArray<256> NoBrightmapFlag{ 0 };
|
||||
|
||||
protected:
|
||||
|
||||
void CopySize(FTexture *BaseTexture)
|
||||
int GetTexelWidth() { return Width; }
|
||||
int GetTexelHeight() { return Height; }
|
||||
int GetTexelLeftOffset(int adjusted) { return _LeftOffset[adjusted]; }
|
||||
int GetTexelTopOffset(int adjusted) { return _TopOffset[adjusted]; }
|
||||
|
||||
|
||||
bool isValid() const { return UseType != ETextureType::Null; }
|
||||
bool isSWCanvas() const { return UseType == ETextureType::SWCanvas; }
|
||||
bool isSkybox() const { return bSkybox; }
|
||||
bool isFullbrightDisabled() const { return bDisableFullbright; }
|
||||
bool isHardwareCanvas() const { return bHasCanvas; } // There's two here so that this can deal with software canvases in the hardware renderer later.
|
||||
bool isCanvas() const { return bHasCanvas; }
|
||||
bool isMiscPatch() const { return UseType == ETextureType::MiscPatch; } // only used by the intermission screen to decide whether to tile the background image or not.
|
||||
int isWarped() const { return bWarped; }
|
||||
int GetRotations() const { return Rotations; }
|
||||
void SetRotations(int rot) { Rotations = int16_t(rot); }
|
||||
bool isSprite() const { return UseType == ETextureType::Sprite || UseType == ETextureType::SkinSprite || UseType == ETextureType::Decal; }
|
||||
|
||||
const FString &GetName() const { return Name; }
|
||||
void SetNoDecals(bool on) { bNoDecals = on; }
|
||||
void SetWarpStyle(int style) { bWarped = style; }
|
||||
bool allowNoDecals() const { return bNoDecals; }
|
||||
bool isScaled() const { return Scale.X != 1 || Scale.Y != 1; }
|
||||
bool isMasked() const { return bMasked; }
|
||||
void SetSkyOffset(int offs) { SkyOffset = offs; }
|
||||
int GetSkyOffset() const { return SkyOffset; }
|
||||
FTextureID GetID() const { return id; }
|
||||
PalEntry GetSkyCapColor(bool bottom);
|
||||
FTexture *GetRawTexture();
|
||||
virtual int GetSourceLump() { return SourceLump; } // needed by the scripted GetName method.
|
||||
void GetGlowColor(float *data);
|
||||
bool isGlowing() const { return bGlowing; }
|
||||
bool isAutoGlowing() const { return bAutoGlowing; }
|
||||
int GetGlowHeight() const { return GlowHeight; }
|
||||
bool isFullbright() const { return bFullbright; }
|
||||
void CreateDefaultBrightmap();
|
||||
bool FindHoles(const unsigned char * buffer, int w, int h);
|
||||
void SetUseType(ETextureType type) { UseType = type; }
|
||||
int GetSourceLump() const { return SourceLump; }
|
||||
ETextureType GetUseType() const { return UseType; }
|
||||
void SetSpeed(float fac) { shaderspeed = fac; }
|
||||
void SetWorldPanning(bool on) { bWorldPanning = on; }
|
||||
void SetDisplaySize(int fitwidth, int fitheight);
|
||||
void SetFrontSkyLayer(bool on = true) { bNoRemap0 = on; }
|
||||
bool IsFrontSkyLayer() { return bNoRemap0; }
|
||||
|
||||
FTexture* GetBrightmap()
|
||||
{
|
||||
Size.x = BaseTexture->GetWidth();
|
||||
Size.y = BaseTexture->GetHeight();
|
||||
leftoffset = BaseTexture->leftoffset;
|
||||
topoffset = BaseTexture->topoffset;
|
||||
if (!bBrightmapChecked)
|
||||
CreateDefaultBrightmap();
|
||||
return Brightmap;
|
||||
}
|
||||
|
||||
void CopySize(FTexture* BaseTexture)
|
||||
{
|
||||
Width = BaseTexture->GetTexelWidth();
|
||||
Height = BaseTexture->GetTexelHeight();
|
||||
_TopOffset[0] = BaseTexture->_TopOffset[0];
|
||||
_TopOffset[1] = BaseTexture->_TopOffset[1];
|
||||
_LeftOffset[0] = BaseTexture->_LeftOffset[0];
|
||||
_LeftOffset[1] = BaseTexture->_LeftOffset[1];
|
||||
Scale = BaseTexture->Scale;
|
||||
}
|
||||
|
||||
// This is only used for the null texture and for Heretic's skies.
|
||||
void SetSize(int w, int h)
|
||||
{
|
||||
Size = { int16_t(w), int16_t(h) };
|
||||
Width = w;
|
||||
Height = h;
|
||||
}
|
||||
|
||||
|
||||
// Returns the whole texture, stored in column-major order
|
||||
virtual TArray<uint8_t> Get8BitPixels(bool alphatex);
|
||||
virtual FBitmap GetBgraBitmap(const PalEntry *remap, int *trans = nullptr);
|
||||
|
||||
static bool SmoothEdges(unsigned char * buffer,int w, int h);
|
||||
static PalEntry averageColor(const uint32_t *data, int size, int maxout);
|
||||
|
||||
|
||||
FSoftwareTexture *GetSoftwareTexture();
|
||||
|
||||
protected:
|
||||
|
||||
DVector2 Scale;
|
||||
|
||||
int SourceLump;
|
||||
FTextureID id;
|
||||
|
||||
FMaterial *Material[2] = { nullptr, nullptr };
|
||||
public:
|
||||
FHardwareTextureContainer SystemTextures;
|
||||
int alphaThreshold = 0.5;
|
||||
FixedBitArray<256> NoBrightmapFlag = false;
|
||||
protected:
|
||||
FSoftwareTexture *SoftwareTexture = nullptr;
|
||||
|
||||
// None of the following pointers are owned by this texture, they are all controlled by the texture manager.
|
||||
|
||||
// Offset-less version for COMPATF_MASKEDMIDTEX
|
||||
FTexture *OffsetLess = nullptr;
|
||||
// Paletted variant
|
||||
FTexture *PalVersion = nullptr;
|
||||
// Material layers
|
||||
FTexture *Brightmap = nullptr;
|
||||
FTexture *Normal = nullptr; // Normal map texture
|
||||
FTexture *Specular = nullptr; // Specular light texture for the diffuse+normal+specular light model
|
||||
FTexture *Metallic = nullptr; // Metalness texture for the physically based rendering (PBR) light model
|
||||
FTexture *Roughness = nullptr; // Roughness texture for PBR
|
||||
FTexture *AmbientOcclusion = nullptr; // Ambient occlusion texture for PBR
|
||||
|
||||
FTexture *CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES] = { nullptr }; // Custom texture maps for custom hardware shaders
|
||||
|
||||
FString Name;
|
||||
union
|
||||
ETextureType UseType; // This texture's primary purpose
|
||||
|
||||
uint8_t bNoDecals:1; // Decals should not stick to texture
|
||||
uint8_t bNoRemap0:1; // Do not remap color 0 (used by front layer of parallax skies)
|
||||
uint8_t bWorldPanning:1; // Texture is panned in world units rather than texels
|
||||
uint8_t bMasked:1; // Texture (might) have holes
|
||||
uint8_t bAlphaTexture:1; // Texture is an alpha channel without color information
|
||||
uint8_t bHasCanvas:1; // Texture is based off FCanvasTexture
|
||||
uint8_t bWarped:2; // This is a warped texture. Used to avoid multiple warps on one texture
|
||||
uint8_t bComplex:1; // Will be used to mark extended MultipatchTextures that have to be
|
||||
// fully composited before subjected to any kind of postprocessing instead of
|
||||
// doing it per patch.
|
||||
uint8_t bMultiPatch:2; // This is a multipatch texture (we really could use real type info for textures...)
|
||||
uint8_t bFullNameTexture : 1;
|
||||
uint8_t bBrightmapChecked : 1; // Set to 1 if brightmap has been checked
|
||||
uint8_t bGlowing : 1; // Texture glow color
|
||||
uint8_t bAutoGlowing : 1; // Glow info is determined from texture image.
|
||||
uint8_t bFullbright : 1; // always draw fullbright
|
||||
uint8_t bDisableFullbright : 1; // This texture will not be displayed as fullbright sprite
|
||||
uint8_t bSkybox : 1; // is a cubic skybox
|
||||
uint8_t bNoCompress : 1;
|
||||
uint8_t bNoExpand : 1;
|
||||
int8_t bTranslucent : 2;
|
||||
bool bHiresHasColorKey = false; // Support for old color-keyed Doomsday textures
|
||||
|
||||
uint16_t Rotations;
|
||||
int16_t SkyOffset;
|
||||
FloatRect *areas = nullptr;
|
||||
int areacount = 0;
|
||||
int GlowHeight = 128;
|
||||
PalEntry GlowColor = 0;
|
||||
int HiresLump = -1; // For external hires textures.
|
||||
float Glossiness = 10.f;
|
||||
float SpecularLevel = 0.1f;
|
||||
float shaderspeed = 1.f;
|
||||
int shaderindex = 0;
|
||||
|
||||
int GetScaledWidth () { int foo = int((Width * 2) / Scale.X); return (foo >> 1) + (foo & 1); }
|
||||
int GetScaledHeight () { int foo = int((Height * 2) / Scale.Y); return (foo >> 1) + (foo & 1); }
|
||||
double GetScaledWidthDouble () { return Width / Scale.X; }
|
||||
double GetScaledHeightDouble () { return Height / Scale.Y; }
|
||||
double GetScaleY() const { return Scale.Y; }
|
||||
|
||||
|
||||
// Now with improved offset adjustment.
|
||||
int GetLeftOffset(int adjusted) { return _LeftOffset[adjusted]; }
|
||||
int GetTopOffset(int adjusted) { return _TopOffset[adjusted]; }
|
||||
int GetScaledLeftOffset (int adjusted) { int foo = int((_LeftOffset[adjusted] * 2) / Scale.X); return (foo >> 1) + (foo & 1); }
|
||||
int GetScaledTopOffset (int adjusted) { int foo = int((_TopOffset[adjusted] * 2) / Scale.Y); return (foo >> 1) + (foo & 1); }
|
||||
double GetScaledLeftOffsetDouble(int adjusted) { return _LeftOffset[adjusted] / Scale.X; }
|
||||
double GetScaledTopOffsetDouble(int adjusted) { return _TopOffset[adjusted] / Scale.Y; }
|
||||
|
||||
// Interfaces for the different renderers. Everything that needs to check renderer-dependent offsets
|
||||
// should use these, so that if changes are needed, this is the only place to edit.
|
||||
|
||||
// For the hardware renderer. The software renderer's have been offloaded to FSoftwareTexture
|
||||
int GetLeftOffsetHW() { return _LeftOffset[r_spriteadjustHW]; }
|
||||
int GetTopOffsetHW() { return _TopOffset[r_spriteadjustHW]; }
|
||||
|
||||
virtual void ResolvePatches() {}
|
||||
|
||||
void SetScale(const DVector2 &scale)
|
||||
{
|
||||
vec2_16_t Size = { 0,0 }; // Keep this in the native format so that we can use it without copying it around.
|
||||
struct { uint16_t Width, Height; };
|
||||
};
|
||||
int leftoffset = 0, topoffset = 0;
|
||||
uint8_t bMasked = true; // Texture (might) have holes
|
||||
int8_t bTranslucent = -1; // Does this texture have an active alpha channel?
|
||||
bool skyColorDone = false;
|
||||
ETextureType UseType = ETextureType::Any;
|
||||
Scale = scale;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint16_t Width, Height;
|
||||
int16_t _LeftOffset[2], _TopOffset[2];
|
||||
|
||||
FTexture (const char *name = NULL, int lumpnum = -1);
|
||||
|
||||
public:
|
||||
FTextureBuffer CreateTexBuffer(int translation, int flags = 0);
|
||||
FTextureBuffer CreateTexBuffer(const PalEntry* translation, int flags = 0);
|
||||
bool GetTranslucency();
|
||||
FMaterial* GetMaterial(int num)
|
||||
{
|
||||
return Material[num];
|
||||
}
|
||||
FTexture* GetPalVersion()
|
||||
{
|
||||
return PalVersion;
|
||||
}
|
||||
|
||||
void DeleteHardwareTextures()
|
||||
{
|
||||
SystemTextures.Clean(true, true);
|
||||
}
|
||||
|
||||
private:
|
||||
int CheckDDPK3();
|
||||
int CheckExternalFile(bool & hascolorkey);
|
||||
|
||||
bool bSWSkyColorDone = false;
|
||||
PalEntry FloorSkyColor;
|
||||
PalEntry CeilingSkyColor;
|
||||
TArray<uint8_t> CachedPixels;
|
||||
// Don't waste too much effort on efficient storage here. Polymost performs so many calculations on a single draw call that the minor map lookup hardly matters.
|
||||
TMap<int, FHardwareTexture*> HardwareTextures; // Note: These must be deleted by the backend. When the texture manager is taken down it may already be too late to delete them.
|
||||
bool bFullNameTexture = false;
|
||||
FTextureID id = FSetTextureID(-1);
|
||||
int SourceLump = -1;
|
||||
|
||||
FTexture (const char *name = NULL);
|
||||
friend struct BuildTiles;
|
||||
public:
|
||||
|
||||
void CheckTrans(unsigned char * buffer, int size, int trans);
|
||||
bool ProcessData(unsigned char * buffer, int w, int h, bool ispatch);
|
||||
int CheckRealHeight();
|
||||
|
||||
friend class FTextureManager;
|
||||
};
|
||||
|
||||
|
||||
// A texture that can be drawn to.
|
||||
|
||||
class FCanvasTexture : public FTexture
|
||||
{
|
||||
public:
|
||||
FCanvasTexture(const char* name, int width, int height)
|
||||
{
|
||||
Name = name;
|
||||
Size.x = width;
|
||||
Size.y = height;
|
||||
Width = width;
|
||||
Height = height;
|
||||
|
||||
bMasked = false;
|
||||
bHasCanvas = true;
|
||||
bTranslucent = false;
|
||||
//bNoExpand = true;
|
||||
bNoExpand = true;
|
||||
UseType = ETextureType::Wall;
|
||||
}
|
||||
|
||||
|
@ -325,6 +502,60 @@ public:
|
|||
friend struct FCanvasTextureInfo;
|
||||
};
|
||||
|
||||
|
||||
// A wrapper around a hardware texture, to allow using it in the 2D drawing interface.
|
||||
class FWrapperTexture : public FTexture
|
||||
{
|
||||
int Format;
|
||||
public:
|
||||
FWrapperTexture(int w, int h, int bits = 1);
|
||||
IHardwareTexture *GetSystemTexture()
|
||||
{
|
||||
return SystemTextures.GetHardwareTexture(0, false);
|
||||
}
|
||||
|
||||
int GetColorFormat() const
|
||||
{
|
||||
return Format;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class FImageTexture : public FTexture
|
||||
{
|
||||
FImageSource* mImage;
|
||||
public:
|
||||
FImageTexture(FImageSource* image, const char* name = nullptr) noexcept;
|
||||
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(const PalEntry* p, int* trans) override;
|
||||
|
||||
};
|
||||
|
||||
struct FTexCoordInfo
|
||||
{
|
||||
int mRenderWidth;
|
||||
int mRenderHeight;
|
||||
int mWidth;
|
||||
FVector2 mScale;
|
||||
FVector2 mTempScale;
|
||||
bool mWorldPanning;
|
||||
|
||||
float FloatToTexU(float v) const { return v / mRenderWidth; }
|
||||
float FloatToTexV(float v) const { return v / mRenderHeight; }
|
||||
float RowOffset(float ofs) const;
|
||||
float TextureOffset(float ofs) const;
|
||||
float TextureAdjustWidth() const;
|
||||
void GetFromTexture(FTexture *tex, float x, float y, bool forceworldpanning);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -3,8 +3,9 @@ class FBitmap;
|
|||
class FTexture;
|
||||
|
||||
#include "tarray.h"
|
||||
#include "hw_ihwtexture.h"
|
||||
|
||||
class FHardwareTexture //: public IHardwareTexture
|
||||
class FHardwareTexture : public IHardwareTexture
|
||||
{
|
||||
public:
|
||||
enum
|
||||
|
@ -33,6 +34,11 @@ public:
|
|||
|
||||
~FHardwareTexture();
|
||||
|
||||
// Satisfy the virtual interface - currently this isn't being used.
|
||||
virtual void AllocateBuffer(int w, int h, int texelsize) {}
|
||||
virtual uint8_t* MapBuffer() { return nullptr; }
|
||||
virtual unsigned int CreateTexture(unsigned char* buffer, int w, int h, int texunit, bool mipmap, const char* name) { return 0; }
|
||||
|
||||
//bool BindOrCreate(FTexture *tex, int texunit, int clampmode, int translation, int flags);
|
||||
|
||||
unsigned int CreateTexture(int w, int h, bool type, bool mipmapped) = delete;
|
||||
|
|
|
@ -68,15 +68,10 @@ void FlipNonSquareBlock(T* dst, const T* src, int x, int y, int srcpitch)
|
|||
|
||||
FHardwareTexture* GLInstance::CreateIndexedTexture(FTexture* tex)
|
||||
{
|
||||
auto siz = tex->GetSize();
|
||||
vec2_t siz = { tex->GetTexelWidth(), tex->GetTexelHeight() };
|
||||
|
||||
const uint8_t* p = tex->Get8BitPixels();
|
||||
TArray<uint8_t> store(siz.x * siz.y, true);
|
||||
if (!p)
|
||||
{
|
||||
tex->Create8BitPixels(store.Data());
|
||||
p = store.Data();
|
||||
}
|
||||
auto store = tex->Get8BitPixels(false);
|
||||
const uint8_t* p = store.Data();
|
||||
|
||||
auto glpic = GLInterface.NewTexture();
|
||||
glpic->CreateTexture(siz.x, siz.y, FHardwareTexture::Indexed, false);
|
||||
|
@ -132,8 +127,8 @@ FHardwareTexture* GLInstance::CreateTrueColorTexture(FTexture* tex, int palid, b
|
|||
FHardwareTexture* GLInstance::LoadTexture(FTexture* tex, int textype, int palid)
|
||||
{
|
||||
if (textype == TT_INDEXED) palid = -1;
|
||||
auto phwtex = tex->GetHardwareTexture(palid);
|
||||
if (phwtex) return *phwtex;
|
||||
auto phwtex = tex->SystemTextures.GetHardwareTexture(palid, false);
|
||||
if (phwtex) return (FHardwareTexture*)phwtex;
|
||||
|
||||
FHardwareTexture *hwtex = nullptr;
|
||||
if (textype == TT_INDEXED)
|
||||
|
@ -143,7 +138,7 @@ FHardwareTexture* GLInstance::LoadTexture(FTexture* tex, int textype, int palid)
|
|||
else
|
||||
hwtex = nullptr;
|
||||
|
||||
if (hwtex) tex->SetHardwareTexture(palid, hwtex);
|
||||
if (hwtex) tex->SystemTextures.AddHardwareTexture(palid, false, hwtex);
|
||||
return hwtex;
|
||||
}
|
||||
|
||||
|
@ -392,7 +387,7 @@ bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int
|
|||
float al = 0.5f;
|
||||
if (TextureType == TT_HICREPLACE)
|
||||
{
|
||||
al = ((unsigned)picnum < MAXTILES && alphahackarray[picnum] != 0) ? alphahackarray[picnum] * (1.f / 255.f) :
|
||||
al = ((unsigned)picnum < MAXTILES&& alphahackarray[picnum] != 0) ? alphahackarray[picnum] * (1.f / 255.f) :
|
||||
(tex->alphaThreshold >= 0 ? tex->alphaThreshold * (1.f / 255.f) : 0.f);
|
||||
}
|
||||
GLInterface.SetAlphaThreshold(al);
|
||||
|
@ -413,7 +408,7 @@ bool GLInstance::SetNamedTexture(FTexture* tex, int palette, int sampler)
|
|||
if (!mtex) return false;
|
||||
|
||||
BindTexture(0, mtex, sampler);
|
||||
GLInterface.SetAlphaThreshold(tex->isTranslucent()? 0.f : 0.5f);
|
||||
GLInterface.SetAlphaThreshold(tex->GetTranslucency()? 0.f : 0.5f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -659,8 +659,8 @@ bool I_SetCursor(FTexture *cursorpic)
|
|||
return false;
|
||||
}
|
||||
// Fixme: This should get a raw image, not a texture. (Once raw images get implemented.)
|
||||
int lo = cursorpic->GetLeftOffset();
|
||||
int to = cursorpic->GetTopOffset();
|
||||
int lo = cursorpic->GetDisplayLeftOffset();
|
||||
int to = cursorpic->GetDisplayTopOffset();
|
||||
|
||||
cursor = CreateAlphaCursor(image, lo, to);
|
||||
if (cursor == NULL)
|
||||
|
|
Loading…
Reference in a new issue