- moved the span and swtruecolor creation code into FSoftwareTexture.

This commit is contained in:
Christoph Oelckers 2018-12-07 00:04:39 +01:00
parent 32e245f2b9
commit 4c67785c40
15 changed files with 608 additions and 630 deletions

View file

@ -681,6 +681,7 @@ file( GLOB HEADER_FILES
sound/wildmidi/*.h
xlat/*.h
swrenderer/*.h
swrenderer/textures/*.h
swrenderer/drawers/*.h
swrenderer/scene/*.h
swrenderer/segments/*.h
@ -1244,6 +1245,7 @@ set (PCH_SOURCES
sound/wildmidi/reverb.cpp
sound/wildmidi/wildmidi_lib.cpp
sound/wildmidi/wm_error.cpp
swrenderer/textures/r_swtexture.cpp
events.cpp
)

View file

@ -1,3 +1,4 @@
#include "../swrenderer/textures/r_swtexture.h"
#include "poly_renderer.cpp"
#include "poly_renderthread.cpp"
#include "drawers/poly_buffer.cpp"

View file

@ -1,3 +1,4 @@
#include "textures/r_swtexture.h"
#include "r_memory.cpp"
#include "r_renderthread.cpp"
#include "r_swrenderer.cpp"

View file

@ -84,7 +84,7 @@ void FSoftwareRenderer::PrecacheTexture(FTexture *ttex, int cache)
{
bool isbgra = V_IsTrueColor();
if (ttex != NULL)
if (ttex != NULL && ttex->isValid())
{
FSoftwareTexture *tex = ttex->GetSoftwareTexture();
if (cache & FTextureManager::HIT_Columnmode)

View file

@ -0,0 +1,453 @@
/*
** texture.cpp
** The base texture class
**
**---------------------------------------------------------------------------
** Copyright 2004-2007 Randy Heit
** Copyright 2006-2018 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
**
*/
#include "r_swtexture.h"
#include "bitmap.h"
#include "m_alloc.h"
//==========================================================================
//
//
//
//==========================================================================
const uint32_t *FSoftwareTexture::GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out)
{
const uint32_t *pixels = GetPixelsBgra();
if (pixels == nullptr) return nullptr;
column %= GetWidth();
if (spans_out != nullptr)
GetColumn(DefaultRenderStyle(), column, spans_out); // This isn't the right way to create the spans.
return pixels + column * GetHeight();
}
const uint32_t *FSoftwareTexture::GetPixelsBgra()
{
if (PixelsBgra.empty() || mTexture->CheckModified(DefaultRenderStyle()))
{
if (!GetColumn(DefaultRenderStyle(), 0, nullptr))
return nullptr;
FBitmap bitmap;
bitmap.Create(GetWidth(), GetHeight());
mTexture->CopyTrueColorPixels(&bitmap, 0, 0);
GenerateBgraFromBitmap(bitmap);
}
return PixelsBgra.data();
}
//==========================================================================
//
//
//
//==========================================================================
FSoftwareTextureSpan **FSoftwareTexture::CreateSpans (const uint8_t *pixels)
{
FSoftwareTextureSpan **spans, *span;
if (!mTexture->isMasked())
{ // Texture does not have holes, so it can use a simpler span structure
spans = (FSoftwareTextureSpan **)M_Malloc (sizeof(FSoftwareTextureSpan*)*GetWidth() + sizeof(FSoftwareTextureSpan)*2);
span = (FSoftwareTextureSpan *)&spans[GetWidth()];
for (int x = 0; x < GetWidth(); ++x)
{
spans[x] = span;
}
span[0].Length = GetHeight();
span[0].TopOffset = 0;
span[1].Length = 0;
span[1].TopOffset = 0;
}
else
{ // Texture might have holes, so build a complete span structure
int numcols = GetWidth();
int numrows = GetHeight();
int numspans = numcols; // One span to terminate each column
const uint8_t *data_p;
bool newspan;
int x, y;
data_p = pixels;
// Count the number of spans in this texture
for (x = numcols; x > 0; --x)
{
newspan = true;
for (y = numrows; y > 0; --y)
{
if (*data_p++ == 0)
{
if (!newspan)
{
newspan = true;
}
}
else if (newspan)
{
newspan = false;
numspans++;
}
}
}
// Allocate space for the spans
spans = (FSoftwareTextureSpan **)M_Malloc (sizeof(FSoftwareTextureSpan*)*numcols + sizeof(FSoftwareTextureSpan)*numspans);
// Fill in the spans
for (x = 0, span = (FSoftwareTextureSpan *)&spans[numcols], data_p = pixels; x < numcols; ++x)
{
newspan = true;
spans[x] = span;
for (y = 0; y < numrows; ++y)
{
if (*data_p++ == 0)
{
if (!newspan)
{
newspan = true;
span++;
}
}
else
{
if (newspan)
{
newspan = false;
span->TopOffset = y;
span->Length = 1;
}
else
{
span->Length++;
}
}
}
if (!newspan)
{
span++;
}
span->TopOffset = 0;
span->Length = 0;
span++;
}
}
return spans;
}
void FSoftwareTexture::FreeSpans (FSoftwareTextureSpan **spans)
{
M_Free (spans);
}
//==========================================================================
//
//
//
//==========================================================================
void FSoftwareTexture::GenerateBgraFromBitmap(const FBitmap &bitmap)
{
CreatePixelsBgraWithMipmaps();
// Transpose
const uint32_t *src = (const uint32_t *)bitmap.GetPixels();
uint32_t *dest = PixelsBgra.data();
for (int x = 0; x < GetWidth(); x++)
{
for (int y = 0; y < GetHeight(); y++)
{
dest[y + x * GetHeight()] = src[x + y * GetWidth()];
}
}
GenerateBgraMipmaps();
}
void FSoftwareTexture::CreatePixelsBgraWithMipmaps()
{
int levels = MipmapLevels();
int buffersize = 0;
for (int i = 0; i < levels; i++)
{
int w = MAX(GetWidth() >> i, 1);
int h = MAX(GetHeight() >> i, 1);
buffersize += w * h;
}
PixelsBgra.resize(buffersize, 0xffff0000);
}
int FSoftwareTexture::MipmapLevels()
{
int widthbits = 0;
while ((GetWidth() >> widthbits) != 0) widthbits++;
int heightbits = 0;
while ((GetHeight() >> heightbits) != 0) heightbits++;
return MAX(widthbits, heightbits);
}
//==========================================================================
//
//
//
//==========================================================================
void FSoftwareTexture::GenerateBgraMipmaps()
{
struct Color4f
{
float a, r, g, b;
Color4f operator*(const Color4f &v) const { return Color4f{ a * v.a, r * v.r, g * v.g, b * v.b }; }
Color4f operator/(const Color4f &v) const { return Color4f{ a / v.a, r / v.r, g / v.g, b / v.b }; }
Color4f operator+(const Color4f &v) const { return Color4f{ a + v.a, r + v.r, g + v.g, b + v.b }; }
Color4f operator-(const Color4f &v) const { return Color4f{ a - v.a, r - v.r, g - v.g, b - v.b }; }
Color4f operator*(float s) const { return Color4f{ a * s, r * s, g * s, b * s }; }
Color4f operator/(float s) const { return Color4f{ a / s, r / s, g / s, b / s }; }
Color4f operator+(float s) const { return Color4f{ a + s, r + s, g + s, b + s }; }
Color4f operator-(float s) const { return Color4f{ a - s, r - s, g - s, b - s }; }
};
int levels = MipmapLevels();
std::vector<Color4f> image(PixelsBgra.size());
// Convert to normalized linear colorspace
{
for (int x = 0; x < GetWidth(); x++)
{
for (int y = 0; y < GetHeight(); y++)
{
uint32_t c8 = PixelsBgra[x * GetHeight() + y];
Color4f c;
c.a = powf(APART(c8) * (1.0f / 255.0f), 2.2f);
c.r = powf(RPART(c8) * (1.0f / 255.0f), 2.2f);
c.g = powf(GPART(c8) * (1.0f / 255.0f), 2.2f);
c.b = powf(BPART(c8) * (1.0f / 255.0f), 2.2f);
image[x * GetHeight() + y] = c;
}
}
}
// Generate mipmaps
{
std::vector<Color4f> smoothed(GetWidth() * GetHeight());
Color4f *src = image.data();
Color4f *dest = src + GetWidth() * GetHeight();
for (int i = 1; i < levels; i++)
{
int srcw = MAX(GetWidth() >> (i - 1), 1);
int srch = MAX(GetHeight() >> (i - 1), 1);
int w = MAX(GetWidth() >> i, 1);
int h = MAX(GetHeight() >> i, 1);
// Downscale
for (int x = 0; x < w; x++)
{
int sx0 = x * 2;
int sx1 = MIN((x + 1) * 2, srcw - 1);
for (int y = 0; y < h; y++)
{
int sy0 = y * 2;
int sy1 = MIN((y + 1) * 2, srch - 1);
Color4f src00 = src[sy0 + sx0 * srch];
Color4f src01 = src[sy1 + sx0 * srch];
Color4f src10 = src[sy0 + sx1 * srch];
Color4f src11 = src[sy1 + sx1 * srch];
Color4f c = (src00 + src01 + src10 + src11) * 0.25f;
dest[y + x * h] = c;
}
}
// Sharpen filter with a 3x3 kernel:
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
Color4f c = { 0.0f, 0.0f, 0.0f, 0.0f };
for (int kx = -1; kx < 2; kx++)
{
for (int ky = -1; ky < 2; ky++)
{
int a = y + ky;
int b = x + kx;
if (a < 0) a = h - 1;
if (a == h) a = 0;
if (b < 0) b = w - 1;
if (b == w) b = 0;
c = c + dest[a + b * h];
}
}
c = c * (1.0f / 9.0f);
smoothed[y + x * h] = c;
}
}
float k = 0.08f;
for (int j = 0; j < w * h; j++)
dest[j] = dest[j] + (dest[j] - smoothed[j]) * k;
src = dest;
dest += w * h;
}
}
// Convert to bgra8 sRGB colorspace
{
Color4f *src = image.data() + GetWidth() * GetHeight();
uint32_t *dest = PixelsBgra.data() + GetWidth() * GetHeight();
for (int i = 1; i < levels; i++)
{
int w = MAX(GetWidth() >> i, 1);
int h = MAX(GetHeight() >> i, 1);
for (int j = 0; j < w * h; j++)
{
uint32_t a = (uint32_t)clamp(powf(MAX(src[j].a, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f);
uint32_t r = (uint32_t)clamp(powf(MAX(src[j].r, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f);
uint32_t g = (uint32_t)clamp(powf(MAX(src[j].g, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f);
uint32_t b = (uint32_t)clamp(powf(MAX(src[j].b, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f);
dest[j] = (a << 24) | (r << 16) | (g << 8) | b;
}
src += w * h;
dest += w * h;
}
}
}
//==========================================================================
//
//
//
//==========================================================================
void FSoftwareTexture::GenerateBgraMipmapsFast()
{
uint32_t *src = PixelsBgra.data();
uint32_t *dest = src + GetWidth() * GetHeight();
int levels = MipmapLevels();
for (int i = 1; i < levels; i++)
{
int srcw = MAX(GetWidth() >> (i - 1), 1);
int srch = MAX(GetHeight() >> (i - 1), 1);
int w = MAX(GetWidth() >> i, 1);
int h = MAX(GetHeight() >> i, 1);
for (int x = 0; x < w; x++)
{
int sx0 = x * 2;
int sx1 = MIN((x + 1) * 2, srcw - 1);
for (int y = 0; y < h; y++)
{
int sy0 = y * 2;
int sy1 = MIN((y + 1) * 2, srch - 1);
uint32_t src00 = src[sy0 + sx0 * srch];
uint32_t src01 = src[sy1 + sx0 * srch];
uint32_t src10 = src[sy0 + sx1 * srch];
uint32_t src11 = src[sy1 + sx1 * srch];
uint32_t alpha = (APART(src00) + APART(src01) + APART(src10) + APART(src11) + 2) / 4;
uint32_t red = (RPART(src00) + RPART(src01) + RPART(src10) + RPART(src11) + 2) / 4;
uint32_t green = (GPART(src00) + GPART(src01) + GPART(src10) + GPART(src11) + 2) / 4;
uint32_t blue = (BPART(src00) + BPART(src01) + BPART(src10) + BPART(src11) + 2) / 4;
dest[y + x * h] = (alpha << 24) | (red << 16) | (green << 8) | blue;
}
}
src = dest;
dest += w * h;
}
}
//==========================================================================
//
//
//
//==========================================================================
const uint8_t *FSoftwareTexture::GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out)
{
int index = !!(style.Flags & STYLEF_RedIsAlpha);
auto Pixeldata = GetPixels(style);
if ((unsigned)column >= (unsigned)GetWidth())
{
if (mTexture->WidthMask + 1 == GetWidth())
{
column &= mTexture->WidthMask;
}
else
{
column %= GetWidth();
}
}
if (spans_out != nullptr)
{
if (Spandata[index] == nullptr)
{
Spandata[index] = CreateSpans (Pixeldata);
}
*spans_out = Spandata[index][column];
}
return Pixeldata + column*GetHeight();
}
//==========================================================================
//
//
//
//==========================================================================
void FSoftwareTexture::FreeAllSpans()
{
for(int i = 0; i < 2; i++)
{
if (Spandata[i] != nullptr)
{
FreeSpans (Spandata[i]);
Spandata[i] = nullptr;
}
}
}

View file

@ -0,0 +1,129 @@
#pragma once
#include "textures/textures.h"
struct FSoftwareTextureSpan
{
uint16_t TopOffset;
uint16_t Length; // A length of 0 terminates this column
};
// For now this is just a minimal wrapper around FTexture. Once the software renderer no longer accesses FTexture directly, it is time for cleaning up.
class FSoftwareTexture
{
FTexture *mTexture;
FTexture *mSource;
std::vector<uint32_t> PixelsBgra;
FSoftwareTextureSpan **Spandata[2] = { nullptr, nullptr };
public:
FSoftwareTexture(FTexture *tex)
{
mTexture = tex;
mSource = tex;
}
virtual ~FSoftwareTexture()
{
FreeAllSpans();
}
FTexture *GetTexture() const
{
return mTexture;
}
// The feature from hell... :(
bool useWorldPanning() const
{
return mTexture->bWorldPanning;
}
bool isMasked()
{
return mTexture->bMasked;
}
bool UseBasePalette() const { return mTexture->UseBasePalette(); }
int GetSkyOffset() const { return mTexture->GetSkyOffset(); }
PalEntry GetSkyCapColor(bool bottom) const { return mTexture->GetSkyCapColor(bottom); }
int GetWidth () { return mTexture->GetWidth(); }
int GetHeight () { return mTexture->GetHeight(); }
int GetWidthBits() { return mTexture->WidthBits; }
int GetHeightBits() { return mTexture->HeightBits; }
bool Mipmapped() { return mTexture->Mipmapped(); }
int GetScaledWidth () { return mTexture->GetScaledWidth(); }
int GetScaledHeight () { return mTexture->GetScaledHeight(); }
double GetScaledWidthDouble () { return mTexture->GetScaledWidthDouble(); }
double GetScaledHeightDouble () { return mTexture->GetScaledHeightDouble(); }
double GetScaleY() const { return mTexture->GetScaleY(); }
// Now with improved offset adjustment.
int GetLeftOffset(int adjusted) { return mTexture->GetLeftOffset(adjusted); }
int GetTopOffset(int adjusted) { return mTexture->GetTopOffset(adjusted); }
int GetScaledLeftOffset (int adjusted) { return mTexture->GetScaledLeftOffset(adjusted); }
int GetScaledTopOffset (int adjusted) { return mTexture->GetScaledTopOffset(adjusted); }
double GetScaledLeftOffsetDouble(int adjusted) { return mTexture->GetScaledLeftOffsetDouble(adjusted); }
double GetScaledTopOffsetDouble(int adjusted) { return mTexture->GetScaledTopOffsetDouble(adjusted); }
// 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 original software renderer
int GetLeftOffsetSW() { return GetLeftOffset(r_spriteadjustSW); }
int GetTopOffsetSW() { return GetTopOffset(r_spriteadjustSW); }
int GetScaledLeftOffsetSW() { return GetScaledLeftOffset(r_spriteadjustSW); }
int GetScaledTopOffsetSW() { return GetScaledTopOffset(r_spriteadjustSW); }
// For the softpoly renderer, in case it wants adjustment
int GetLeftOffsetPo() { return GetLeftOffset(r_spriteadjustSW); }
int GetTopOffsetPo() { return GetTopOffset(r_spriteadjustSW); }
int GetScaledLeftOffsetPo() { return GetScaledLeftOffset(r_spriteadjustSW); }
int GetScaledTopOffsetPo() { return GetScaledTopOffset(r_spriteadjustSW); }
DVector2 GetScale() const { return mTexture->Scale; }
// Returns the whole texture, stored in column-major order
const uint8_t *GetPixels(FRenderStyle style)
{
return mTexture->GetPixels(style);
}
void Unload()
{
mTexture->Unload();
PixelsBgra = std::vector<uint32_t>();
}
void GenerateBgraFromBitmap(const FBitmap &bitmap);
void CreatePixelsBgraWithMipmaps();
void GenerateBgraMipmaps();
void GenerateBgraMipmapsFast();
int MipmapLevels();
void FreeAllSpans();
FSoftwareTextureSpan **CreateSpans (const uint8_t *pixels);
void FreeSpans (FSoftwareTextureSpan **spans);
// Returns a single column of the texture
virtual const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out);
// Returns a single column of the texture, in BGRA8 format
virtual const uint32_t *GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out);
// Returns the whole texture, stored in column-major order, in BGRA8 format
virtual const uint32_t *GetPixelsBgra();
};
inline FSoftwareTexture *FTexture::GetSoftwareTexture()
{
if (!SoftwareTexture) SoftwareTexture = new FSoftwareTexture(this);
return SoftwareTexture;
}

View file

@ -44,10 +44,12 @@ FCanvasTexture::FCanvasTexture (const char *name, int width, int height)
CalcBitSize ();
bMasked = false;
/*
DummySpans[0].TopOffset = 0;
DummySpans[0].Length = height;
DummySpans[1].TopOffset = 0;
DummySpans[1].Length = 0;
*/
UseType = ETextureType::Wall;
bNeedsUpdate = true;
bDidUpdate = false;
@ -61,6 +63,7 @@ FCanvasTexture::~FCanvasTexture ()
Unload ();
}
#if 0
const uint8_t *FCanvasTexture::GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out)
{
bNeedsUpdate = true;
@ -85,6 +88,7 @@ const uint8_t *FCanvasTexture::GetColumn(FRenderStyle style, unsigned int column
}
return Pixels + column*Height;
}
#endif
const uint8_t *FCanvasTexture::GetPixels (FRenderStyle style)
{
@ -96,6 +100,7 @@ const uint8_t *FCanvasTexture::GetPixels (FRenderStyle style)
return Pixels;
}
#if 0
const uint32_t *FCanvasTexture::GetPixelsBgra()
{
bNeedsUpdate = true;
@ -105,6 +110,7 @@ const uint32_t *FCanvasTexture::GetPixelsBgra()
}
return PixelsBgra;
}
#endif
void FCanvasTexture::MakeTexture (FRenderStyle) // This ignores the render style because making it work as alpha texture is impractical.
{

View file

@ -164,7 +164,7 @@ public:
protected:
uint8_t *Pixels;
FSoftwareTextureSpan **Spans;
//FSoftwareTextureSpan **Spans;
int DefinitionLump;
struct TexPart
@ -199,8 +199,6 @@ protected:
// The getters must optionally redirect if it's a simple one-patch texture.
const uint8_t *GetPixels(FRenderStyle style) override { return bRedirect ? Parts->Texture->GetPixels(style) : FWorldTexture::GetPixels(style); }
const uint8_t *GetColumn(FRenderStyle style, unsigned int col, const FSoftwareTextureSpan **out) override
{ return bRedirect ? Parts->Texture->GetColumn(style, col, out) : FWorldTexture::GetColumn(style, col, out); }
private:
@ -215,7 +213,7 @@ private:
//==========================================================================
FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflumpnum)
: Pixels (0), Spans(0), Parts(nullptr), Inits(nullptr), bRedirect(false), bTranslucentPatches(false)
: Pixels (0), Parts(nullptr), Inits(nullptr), bRedirect(false), bTranslucentPatches(false)
{
union
{
@ -1065,7 +1063,7 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, TexInit &init)
//==========================================================================
FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, ETextureType usetype)
: Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false)
: Pixels (0), Parts(0), bRedirect(false), bTranslucentPatches(false)
{
TArray<TexPart> parts;
TArray<TexInit> inits;

View file

@ -59,7 +59,7 @@ void FWarpTexture::Unload ()
{
SourcePic->Unload ();
FWorldTexture::Unload();
FreeAllSpans();
//FreeAllSpans();
}
bool FWarpTexture::CheckModified (FRenderStyle style)
@ -67,6 +67,7 @@ bool FWarpTexture::CheckModified (FRenderStyle style)
return screen->FrameTime != GenTime[!!(style.Flags & STYLEF_RedIsAlpha)];
}
/*
const uint32_t *FWarpTexture::GetPixelsBgra()
{
auto Pixels = GetPixels(DefaultRenderStyle());
@ -85,6 +86,7 @@ const uint32_t *FWarpTexture::GetPixelsBgra()
}
return PixelsBgra.data();
}
*/
uint8_t *FWarpTexture::MakeTexture(FRenderStyle style)
@ -93,7 +95,7 @@ uint8_t *FWarpTexture::MakeTexture(FRenderStyle style)
const uint8_t *otherpix = SourcePic->GetPixels(style);
auto Pixels = new uint8_t[Width * Height];
WarpBuffer(Pixels, otherpix, Width, Height, WidthOffsetMultiplier, HeightOffsetMultiplier, time, Speed, bWarped);
FreeAllSpans();
//FreeAllSpans();
GenTime[!!(style.Flags & STYLEF_RedIsAlpha)] = time;
return Pixels;
}

View file

@ -56,25 +56,6 @@ FWorldTexture::FWorldTexture(const char *name, int lumpnum)
FWorldTexture::~FWorldTexture()
{
Unload();
FreeAllSpans();
}
//==========================================================================
//
//
//
//==========================================================================
void FWorldTexture::FreeAllSpans()
{
for(int i = 0; i < 2; i++)
{
if (Spandata[i] != nullptr)
{
FreeSpans (Spandata[i]);
Spandata[i] = nullptr;
}
}
}
//==========================================================================
@ -102,38 +83,6 @@ void FWorldTexture::Unload ()
//
//==========================================================================
const uint8_t *FWorldTexture::GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out)
{
int index = !!(style.Flags & STYLEF_RedIsAlpha);
GetPixels(style);
if ((unsigned)column >= (unsigned)Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != nullptr)
{
if (Spandata[index] == nullptr)
{
Spandata[index] = CreateSpans (Pixeldata[index]);
}
*spans_out = Spandata[index][column];
}
return Pixeldata[index] + column*Height;
}
//==========================================================================
//
//
//
//==========================================================================
const uint8_t *FWorldTexture::GetPixels (FRenderStyle style)
{
if (CheckModified(style))

View file

@ -53,18 +53,6 @@ FSkyBox::~FSkyBox()
// The faces are only referenced but not owned so don't delete them.
}
//-----------------------------------------------------------------------------
//
// If something attempts to use this as a texture just pass the information of the first face.
//
//-----------------------------------------------------------------------------
const uint8_t *FSkyBox::GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out)
{
if (faces[0]) return faces[0]->GetColumn(style, column, spans_out);
return NULL;
}
//-----------------------------------------------------------------------------
//
//

View file

@ -17,7 +17,7 @@ public:
FSkyBox(const char *name = nullptr);
~FSkyBox();
const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out);
//const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out);
const uint8_t *GetPixels (FRenderStyle style);
int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf);
bool UseBasePalette();

View file

@ -231,40 +231,6 @@ FTexture::~FTexture ()
void FTexture::Unload()
{
PixelsBgra = std::vector<uint32_t>();
}
//==========================================================================
//
//
//
//==========================================================================
const uint32_t *FTexture::GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out)
{
const uint32_t *pixels = GetPixelsBgra();
if (pixels == nullptr) return nullptr;
column %= Width;
if (spans_out != nullptr)
GetColumn(DefaultRenderStyle(), column, spans_out); // This isn't the right way to create the spans.
return pixels + column * Height;
}
const uint32_t *FTexture::GetPixelsBgra()
{
if (PixelsBgra.empty() || CheckModified(DefaultRenderStyle()))
{
if (!GetColumn(DefaultRenderStyle(), 0, nullptr))
return nullptr;
FBitmap bitmap;
bitmap.Create(GetWidth(), GetHeight());
CopyTrueColorPixels(&bitmap, 0, 0);
GenerateBgraFromBitmap(bitmap);
}
return PixelsBgra.data();
}
//==========================================================================
@ -327,333 +293,6 @@ void FTexture::CalcBitSize ()
//
//==========================================================================
FSoftwareTextureSpan **FTexture::CreateSpans (const uint8_t *pixels) const
{
FSoftwareTextureSpan **spans, *span;
if (!bMasked)
{ // Texture does not have holes, so it can use a simpler span structure
spans = (FSoftwareTextureSpan **)M_Malloc (sizeof(FSoftwareTextureSpan*)*Width + sizeof(FSoftwareTextureSpan)*2);
span = (FSoftwareTextureSpan *)&spans[Width];
for (int x = 0; x < Width; ++x)
{
spans[x] = span;
}
span[0].Length = Height;
span[0].TopOffset = 0;
span[1].Length = 0;
span[1].TopOffset = 0;
}
else
{ // Texture might have holes, so build a complete span structure
int numcols = Width;
int numrows = Height;
int numspans = numcols; // One span to terminate each column
const uint8_t *data_p;
bool newspan;
int x, y;
data_p = pixels;
// Count the number of spans in this texture
for (x = numcols; x > 0; --x)
{
newspan = true;
for (y = numrows; y > 0; --y)
{
if (*data_p++ == 0)
{
if (!newspan)
{
newspan = true;
}
}
else if (newspan)
{
newspan = false;
numspans++;
}
}
}
// Allocate space for the spans
spans = (FSoftwareTextureSpan **)M_Malloc (sizeof(FSoftwareTextureSpan*)*numcols + sizeof(FSoftwareTextureSpan)*numspans);
// Fill in the spans
for (x = 0, span = (FSoftwareTextureSpan *)&spans[numcols], data_p = pixels; x < numcols; ++x)
{
newspan = true;
spans[x] = span;
for (y = 0; y < numrows; ++y)
{
if (*data_p++ == 0)
{
if (!newspan)
{
newspan = true;
span++;
}
}
else
{
if (newspan)
{
newspan = false;
span->TopOffset = y;
span->Length = 1;
}
else
{
span->Length++;
}
}
}
if (!newspan)
{
span++;
}
span->TopOffset = 0;
span->Length = 0;
span++;
}
}
return spans;
}
void FTexture::FreeSpans (FSoftwareTextureSpan **spans) const
{
M_Free (spans);
}
//==========================================================================
//
//
//
//==========================================================================
void FTexture::GenerateBgraFromBitmap(const FBitmap &bitmap)
{
CreatePixelsBgraWithMipmaps();
// Transpose
const uint32_t *src = (const uint32_t *)bitmap.GetPixels();
uint32_t *dest = PixelsBgra.data();
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
dest[y + x * Height] = src[x + y * Width];
}
}
GenerateBgraMipmaps();
}
void FTexture::CreatePixelsBgraWithMipmaps()
{
int levels = MipmapLevels();
int buffersize = 0;
for (int i = 0; i < levels; i++)
{
int w = MAX(Width >> i, 1);
int h = MAX(Height >> i, 1);
buffersize += w * h;
}
PixelsBgra.resize(buffersize, 0xffff0000);
}
int FTexture::MipmapLevels() const
{
int widthbits = 0;
while ((Width >> widthbits) != 0) widthbits++;
int heightbits = 0;
while ((Height >> heightbits) != 0) heightbits++;
return MAX(widthbits, heightbits);
}
//==========================================================================
//
//
//
//==========================================================================
void FTexture::GenerateBgraMipmaps()
{
struct Color4f
{
float a, r, g, b;
Color4f operator*(const Color4f &v) const { return Color4f{ a * v.a, r * v.r, g * v.g, b * v.b }; }
Color4f operator/(const Color4f &v) const { return Color4f{ a / v.a, r / v.r, g / v.g, b / v.b }; }
Color4f operator+(const Color4f &v) const { return Color4f{ a + v.a, r + v.r, g + v.g, b + v.b }; }
Color4f operator-(const Color4f &v) const { return Color4f{ a - v.a, r - v.r, g - v.g, b - v.b }; }
Color4f operator*(float s) const { return Color4f{ a * s, r * s, g * s, b * s }; }
Color4f operator/(float s) const { return Color4f{ a / s, r / s, g / s, b / s }; }
Color4f operator+(float s) const { return Color4f{ a + s, r + s, g + s, b + s }; }
Color4f operator-(float s) const { return Color4f{ a - s, r - s, g - s, b - s }; }
};
int levels = MipmapLevels();
std::vector<Color4f> image(PixelsBgra.size());
// Convert to normalized linear colorspace
{
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
uint32_t c8 = PixelsBgra[x * Height + y];
Color4f c;
c.a = powf(APART(c8) * (1.0f / 255.0f), 2.2f);
c.r = powf(RPART(c8) * (1.0f / 255.0f), 2.2f);
c.g = powf(GPART(c8) * (1.0f / 255.0f), 2.2f);
c.b = powf(BPART(c8) * (1.0f / 255.0f), 2.2f);
image[x * Height + y] = c;
}
}
}
// Generate mipmaps
{
std::vector<Color4f> smoothed(Width * Height);
Color4f *src = image.data();
Color4f *dest = src + Width * Height;
for (int i = 1; i < levels; i++)
{
int srcw = MAX(Width >> (i - 1), 1);
int srch = MAX(Height >> (i - 1), 1);
int w = MAX(Width >> i, 1);
int h = MAX(Height >> i, 1);
// Downscale
for (int x = 0; x < w; x++)
{
int sx0 = x * 2;
int sx1 = MIN((x + 1) * 2, srcw - 1);
for (int y = 0; y < h; y++)
{
int sy0 = y * 2;
int sy1 = MIN((y + 1) * 2, srch - 1);
Color4f src00 = src[sy0 + sx0 * srch];
Color4f src01 = src[sy1 + sx0 * srch];
Color4f src10 = src[sy0 + sx1 * srch];
Color4f src11 = src[sy1 + sx1 * srch];
Color4f c = (src00 + src01 + src10 + src11) * 0.25f;
dest[y + x * h] = c;
}
}
// Sharpen filter with a 3x3 kernel:
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
Color4f c = { 0.0f, 0.0f, 0.0f, 0.0f };
for (int kx = -1; kx < 2; kx++)
{
for (int ky = -1; ky < 2; ky++)
{
int a = y + ky;
int b = x + kx;
if (a < 0) a = h - 1;
if (a == h) a = 0;
if (b < 0) b = w - 1;
if (b == w) b = 0;
c = c + dest[a + b * h];
}
}
c = c * (1.0f / 9.0f);
smoothed[y + x * h] = c;
}
}
float k = 0.08f;
for (int j = 0; j < w * h; j++)
dest[j] = dest[j] + (dest[j] - smoothed[j]) * k;
src = dest;
dest += w * h;
}
}
// Convert to bgra8 sRGB colorspace
{
Color4f *src = image.data() + Width * Height;
uint32_t *dest = PixelsBgra.data() + Width * Height;
for (int i = 1; i < levels; i++)
{
int w = MAX(Width >> i, 1);
int h = MAX(Height >> i, 1);
for (int j = 0; j < w * h; j++)
{
uint32_t a = (uint32_t)clamp(powf(MAX(src[j].a, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f);
uint32_t r = (uint32_t)clamp(powf(MAX(src[j].r, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f);
uint32_t g = (uint32_t)clamp(powf(MAX(src[j].g, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f);
uint32_t b = (uint32_t)clamp(powf(MAX(src[j].b, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f);
dest[j] = (a << 24) | (r << 16) | (g << 8) | b;
}
src += w * h;
dest += w * h;
}
}
}
//==========================================================================
//
//
//
//==========================================================================
void FTexture::GenerateBgraMipmapsFast()
{
uint32_t *src = PixelsBgra.data();
uint32_t *dest = src + Width * Height;
int levels = MipmapLevels();
for (int i = 1; i < levels; i++)
{
int srcw = MAX(Width >> (i - 1), 1);
int srch = MAX(Height >> (i - 1), 1);
int w = MAX(Width >> i, 1);
int h = MAX(Height >> i, 1);
for (int x = 0; x < w; x++)
{
int sx0 = x * 2;
int sx1 = MIN((x + 1) * 2, srcw - 1);
for (int y = 0; y < h; y++)
{
int sy0 = y * 2;
int sy1 = MIN((y + 1) * 2, srch - 1);
uint32_t src00 = src[sy0 + sx0 * srch];
uint32_t src01 = src[sy1 + sx0 * srch];
uint32_t src10 = src[sy0 + sx1 * srch];
uint32_t src11 = src[sy1 + sx1 * srch];
uint32_t alpha = (APART(src00) + APART(src01) + APART(src10) + APART(src11) + 2) / 4;
uint32_t red = (RPART(src00) + RPART(src01) + RPART(src10) + RPART(src11) + 2) / 4;
uint32_t green = (GPART(src00) + GPART(src01) + GPART(src10) + GPART(src11) + 2) / 4;
uint32_t blue = (BPART(src00) + BPART(src01) + BPART(src10) + BPART(src11) + 2) / 4;
dest[y + x * h] = (alpha << 24) | (red << 16) | (green << 8) | blue;
}
}
src = dest;
dest += w * h;
}
}
//==========================================================================
//
//
//
//==========================================================================
void FTexture::CopyToBlock (uint8_t *dest, int dwidth, int dheight, int xpos, int ypos, int rotate, const uint8_t *translation, FRenderStyle style)
{
const uint8_t *pixels = GetPixels(style);
@ -1454,11 +1093,6 @@ void FTexture::SetSpriteAdjust()
//
//===========================================================================
const uint8_t *FTexture::GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out)
{
return nullptr;
}
const uint8_t *FTexture::GetPixels(FRenderStyle style)
{
return nullptr;

View file

@ -214,12 +214,6 @@ enum FTextureFormat : uint32_t
class FSoftwareTexture;
class FGLRenderState;
struct FSoftwareTextureSpan
{
uint16_t TopOffset;
uint16_t Length; // A length of 0 terminates this column
};
struct spriteframewithrotate;
class FSerializer;
namespace OpenGLRenderer
@ -388,19 +382,9 @@ protected:
int shaderindex = 0;
// Returns a single column of the texture
virtual const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out);
// Returns a single column of the texture, in BGRA8 format
virtual const uint32_t *GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out);
// Returns the whole texture, stored in column-major order
virtual const uint8_t *GetPixels(FRenderStyle style);
// Returns the whole texture, stored in column-major order, in BGRA8 format
virtual const uint32_t *GetPixelsBgra();
// Returns true if GetPixelsBgra includes mipmaps
virtual bool Mipmapped() { return true; }
@ -535,8 +519,6 @@ protected:
FTexture (const char *name = NULL, int lumpnum = -1);
FSoftwareTextureSpan **CreateSpans (const uint8_t *pixels) const;
void FreeSpans (FSoftwareTextureSpan **spans) const;
void CalcBitSize ();
void CopyInfo(FTexture *other)
{
@ -545,13 +527,6 @@ protected:
Rotations = other->Rotations;
}
std::vector<uint32_t> PixelsBgra;
void GenerateBgraFromBitmap(const FBitmap &bitmap);
void CreatePixelsBgraWithMipmaps();
void GenerateBgraMipmaps();
void GenerateBgraMipmapsFast();
int MipmapLevels() const;
public:
@ -577,112 +552,6 @@ public:
friend class FTextureManager;
};
// For now this is just a minimal wrapper around FTexture. Once the software renderer no longer accesses FTexture directly, it is time for cleaning up.
class FSoftwareTexture
{
FTexture *mTexture;
public:
FSoftwareTexture(FTexture *tex)
{
mTexture = tex;
}
FTexture *GetTexture() const
{
return mTexture;
}
// The feature from hell... :(
bool useWorldPanning() const
{
return mTexture->bWorldPanning;
}
bool isMasked()
{
return mTexture->bMasked;
}
bool UseBasePalette() const { return mTexture->UseBasePalette(); }
int GetSkyOffset() const { return mTexture->GetSkyOffset(); }
PalEntry GetSkyCapColor(bool bottom) const { return mTexture->GetSkyCapColor(bottom); }
int GetWidth () { return mTexture->GetWidth(); }
int GetHeight () { return mTexture->GetHeight(); }
int GetWidthBits() { return mTexture->WidthBits; }
int GetHeightBits() { return mTexture->HeightBits; }
bool Mipmapped() { return mTexture->Mipmapped(); }
int GetScaledWidth () { return mTexture->GetScaledWidth(); }
int GetScaledHeight () { return mTexture->GetScaledHeight(); }
double GetScaledWidthDouble () { return mTexture->GetScaledWidthDouble(); }
double GetScaledHeightDouble () { return mTexture->GetScaledHeightDouble(); }
double GetScaleY() const { return mTexture->GetScaleY(); }
// Now with improved offset adjustment.
int GetLeftOffset(int adjusted) { return mTexture->GetLeftOffset(adjusted); }
int GetTopOffset(int adjusted) { return mTexture->GetTopOffset(adjusted); }
int GetScaledLeftOffset (int adjusted) { return mTexture->GetScaledLeftOffset(adjusted); }
int GetScaledTopOffset (int adjusted) { return mTexture->GetScaledTopOffset(adjusted); }
double GetScaledLeftOffsetDouble(int adjusted) { return mTexture->GetScaledLeftOffsetDouble(adjusted); }
double GetScaledTopOffsetDouble(int adjusted) { return mTexture->GetScaledTopOffsetDouble(adjusted); }
// 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 original software renderer
int GetLeftOffsetSW() { return GetLeftOffset(r_spriteadjustSW); }
int GetTopOffsetSW() { return GetTopOffset(r_spriteadjustSW); }
int GetScaledLeftOffsetSW() { return GetScaledLeftOffset(r_spriteadjustSW); }
int GetScaledTopOffsetSW() { return GetScaledTopOffset(r_spriteadjustSW); }
// For the softpoly renderer, in case it wants adjustment
int GetLeftOffsetPo() { return GetLeftOffset(r_spriteadjustSW); }
int GetTopOffsetPo() { return GetTopOffset(r_spriteadjustSW); }
int GetScaledLeftOffsetPo() { return GetScaledLeftOffset(r_spriteadjustSW); }
int GetScaledTopOffsetPo() { return GetScaledTopOffset(r_spriteadjustSW); }
DVector2 GetScale() const { return mTexture->Scale; }
// Returns a single column of the texture
const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out)
{
return mTexture->GetColumn(style, column, spans_out);
}
// Returns a single column of the texture, in BGRA8 format
const uint32_t *GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out)
{
return mTexture->GetColumnBgra(column, spans_out);
}
// Returns the whole texture, stored in column-major order
const uint8_t *GetPixels(FRenderStyle style)
{
return mTexture->GetPixels(style);
}
// Returns the whole texture, stored in column-major order, in BGRA8 format
const uint32_t *GetPixelsBgra()
{
return mTexture->GetPixelsBgra();
}
void Unload()
{
mTexture->Unload();
}
};
inline FSoftwareTexture *FTexture::GetSoftwareTexture()
{
if (!SoftwareTexture) SoftwareTexture = new FSoftwareTexture(this);
return SoftwareTexture;
}
class FxAddSub;
// Texture manager
@ -883,17 +752,14 @@ class FWorldTexture : public FTexture
{
protected:
uint8_t *Pixeldata[2] = { nullptr, nullptr };
FSoftwareTextureSpan **Spandata[2] = { nullptr, nullptr };
uint8_t PixelsAreStatic = 0; // can be set by subclasses which provide static pixel buffers.
FWorldTexture(const char *name = nullptr, int lumpnum = -1);
~FWorldTexture();
const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out) override;
const uint8_t *GetPixels(FRenderStyle style) override;
void Unload() override;
const uint8_t *GetPixels(FRenderStyle style) override;
virtual uint8_t *MakeTexture(FRenderStyle style) = 0;
void FreeAllSpans();
};
// A texture that doesn't really exist
@ -914,7 +780,7 @@ public:
virtual int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate=0, FCopyInfo *inf = NULL) override;
virtual int CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, PalEntry *remap, FCopyInfo *inf = NULL) override;
const uint32_t *GetPixelsBgra() override;
//const uint32_t *GetPixelsBgra() override;
bool CheckModified (FRenderStyle) override;
float GetSpeed() const { return Speed; }
@ -943,9 +809,10 @@ public:
FCanvasTexture (const char *name, int width, int height);
~FCanvasTexture ();
const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out);
//const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out);
//const uint32_t *GetPixelsBgra() override;
const uint8_t *GetPixels (FRenderStyle style);
const uint32_t *GetPixelsBgra() override;
void Unload ();
bool CheckModified (FRenderStyle) override;
void NeedUpdate() { bNeedsUpdate=true; }
@ -962,7 +829,7 @@ protected:
DCanvas *CanvasBgra = nullptr;
uint8_t *Pixels = nullptr;
uint32_t *PixelsBgra = nullptr;
FSoftwareTextureSpan DummySpans[2];
//FSoftwareTextureSpan DummySpans[2];
bool bNeedsUpdate = true;
bool bDidUpdate = false;
bool bPixelsAllocated = false;

View file

@ -171,7 +171,6 @@ class FFontChar1 : public FTexture
{
public:
FFontChar1 (FTexture *sourcelump);
const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out);
const uint8_t *GetPixels (FRenderStyle style);
void SetSourceRemap(const uint8_t *sourceremap);
void Unload ();
@ -192,7 +191,6 @@ public:
FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs=0, int topofs=0);
~FFontChar2 ();
const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out);
const uint8_t *GetPixels (FRenderStyle style);
void SetSourceRemap(const uint8_t *sourceremap);
void Unload ();
@ -201,7 +199,6 @@ protected:
int SourceLump;
int SourcePos;
uint8_t *Pixels;
FSoftwareTextureSpan **Spans;
const uint8_t *SourceRemap;
void MakeTexture ();
@ -1607,23 +1604,6 @@ void FFontChar1::MakeTexture ()
}
}
//==========================================================================
//
// FFontChar1 :: GetColumn
//
//==========================================================================
const uint8_t *FFontChar1::GetColumn(FRenderStyle, unsigned int column, const FSoftwareTextureSpan **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
BaseTexture->GetColumn(DefaultRenderStyle(), column, spans_out);
return Pixels + column*Height;
}
//==========================================================================
//
// FFontChar1 :: SetSourceRemap
@ -1672,7 +1652,7 @@ FFontChar1::~FFontChar1 ()
//==========================================================================
FFontChar2::FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs, int topofs)
: SourceLump (sourcelump), SourcePos (sourcepos), Pixels (0), Spans (0), SourceRemap(NULL)
: SourceLump (sourcelump), SourcePos (sourcepos), Pixels (0), SourceRemap(NULL)
{
UseType = ETextureType::FontChar;
Width = width;
@ -1691,11 +1671,6 @@ FFontChar2::FFontChar2 (int sourcelump, int sourcepos, int width, int height, in
FFontChar2::~FFontChar2 ()
{
Unload ();
if (Spans != NULL)
{
FreeSpans (Spans);
Spans = NULL;
}
}
//==========================================================================
@ -1731,33 +1706,6 @@ const uint8_t *FFontChar2::GetPixels (FRenderStyle)
return Pixels;
}
//==========================================================================
//
// FFontChar2 :: GetColumn
//
//==========================================================================
const uint8_t *FFontChar2::GetColumn(FRenderStyle, unsigned int column, const FSoftwareTextureSpan **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
if (column >= Width)
{
column = WidthMask;
}
if (spans_out != NULL)
{
if (Spans == NULL)
{
Spans = CreateSpans (Pixels);
}
*spans_out = Spans[column];
}
return Pixels + column*Height;
}
//==========================================================================
//
// FFontChar2 :: SetSourceRemap