diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e68950fce..527ec220d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1073,6 +1073,7 @@ set (PCH_SOURCES common/textures/formats/pcxtexture.cpp common/textures/formats/pngtexture.cpp common/textures/formats/rawpagetexture.cpp + common/textures/formats/startuptexture.cpp common/textures/formats/emptytexture.cpp common/textures/formats/shadertexture.cpp common/textures/formats/tgatexture.cpp diff --git a/src/common/textures/formats/rawpagetexture.cpp b/src/common/textures/formats/rawpagetexture.cpp index 38fca7a67..c2b26ba23 100644 --- a/src/common/textures/formats/rawpagetexture.cpp +++ b/src/common/textures/formats/rawpagetexture.cpp @@ -62,9 +62,9 @@ public: // //========================================================================== -static bool CheckIfRaw(FileReader & data) +bool CheckIfRaw(FileReader & data, int desiredsize) { - if (data.GetLength() != 64000) return false; + if (data.GetLength() != desiredsize) return false; // This is probably a raw page graphic, but do some checking to be sure patch_t *foo; @@ -136,7 +136,7 @@ static bool CheckIfRaw(FileReader & data) FImageSource *RawPageImage_TryCreate(FileReader & file, int lumpnum) { - if (!CheckIfRaw(file)) return nullptr; + if (!CheckIfRaw(file, 64000)) return nullptr; return new FRawPageTexture(lumpnum); } diff --git a/src/common/textures/formats/startuptexture.cpp b/src/common/textures/formats/startuptexture.cpp new file mode 100644 index 000000000..064e7bf83 --- /dev/null +++ b/src/common/textures/formats/startuptexture.cpp @@ -0,0 +1,288 @@ + +/* +** startuptexture.cpp +** Texture class for Hexen's startup screen +** +**--------------------------------------------------------------------------- +** Copyright 2022 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "filesystem.h" +#include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" + +#define ST_NOTCH_WIDTH 16 +#define ST_NOTCH_HEIGHT 23 + +#define ST_NETNOTCH_WIDTH 4 +#define ST_NETNOTCH_HEIGHT 16 + +// there is only one palette for all these images. +static uint8_t startuppalette8[16]; +static uint32_t startuppalette32[16]; + +//========================================================================== +// +// A raw 320x200 graphic used by Heretic and Hexen fullscreen images +// +//========================================================================== + +class FStartupTexture : public FImageSource +{ +public: + FStartupTexture (int lumpnum); + TArray CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion) override; +}; + +class FNotchTexture : public FImageSource +{ +public: + FNotchTexture (int lumpnum, int width, int height); + TArray CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion) override; +}; + + +//========================================================================== +// +// Use the same function as raw textures to eliminate Doom patches +// +//========================================================================== + +bool CheckIfRaw(FileReader & data, int desiredsize); + +//========================================================================== +// +// +// +//========================================================================== + +FImageSource *StartupPageImage_TryCreate(FileReader & file, int lumpnum) +{ + if (fileSystem.CheckFileName(lumpnum, "STARTUP")) + { + if (!CheckIfRaw(file, 153648)) return nullptr; + return new FStartupTexture(lumpnum); + } + if (fileSystem.CheckFileName(lumpnum, "NOTCH")) + { + if (!CheckIfRaw(file, ST_NOTCH_WIDTH * ST_NOTCH_HEIGHT / 2)) return nullptr; + return new FNotchTexture(lumpnum, ST_NOTCH_WIDTH, ST_NOTCH_HEIGHT); + } + if (fileSystem.CheckFileName(lumpnum, "NETNOTCH")) + { + if (!CheckIfRaw(file, ST_NETNOTCH_WIDTH * ST_NETNOTCH_HEIGHT / 2)) return nullptr; + return new FNotchTexture(lumpnum, ST_NETNOTCH_WIDTH, ST_NETNOTCH_HEIGHT); + } + return nullptr; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FStartupTexture::FStartupTexture (int lumpnum) +: FImageSource(lumpnum) +{ + Width = 640; + Height = 480; + bUseGamePalette = false; + + FileData lump = fileSystem.ReadFile (SourceLump); + const uint8_t *source = (const uint8_t *)lump.GetMem(); + + // Initialize the bitmap palette. + // the palette is static so that the notches can share it. + // Note that if the STARTUP image gets replaced, the notches will be all black unless they get replaced as well! + for (int i = 0; i < 16; ++i) + { + PalEntry pe; + pe.r = source[i * 3 + 0]; + pe.g = source[i * 3 + 1]; + pe.b = source[i * 3 + 2]; + pe.a = 63; + // Convert from 6-bit per component to 8-bit per component. + pe.d= (pe.d << 2) | ((pe.d >> 4) & 0x03030303); + startuppalette8[i] = ColorMatcher.Pick(pe); + startuppalette32[i] = pe; + } +} + +//========================================================================== +// +// PlanarToChunky +// +// Convert a 4-bpp planar image to chunky pixels. +// +//========================================================================== + +template +void PlanarToChunky(T* dest, const uint8_t* src, const T* remap, int width, int height) +{ + int y, x; + const uint8_t* src1, * src2, * src3, * src4; + size_t plane_size = width / 8 * height; + + src1 = src; + src2 = src1 + plane_size; + src3 = src2 + plane_size; + src4 = src3 + plane_size; + + for (y = height; y > 0; --y) + { + for (x = width; x > 0; x -= 8) + { + dest[0] = remap[((*src4 & 0x80) | ((*src3 & 0x80) >> 1) | ((*src2 & 0x80) >> 2) | ((*src1 & 0x80) >> 3)) >> 4]; + dest[1] = remap[((*src4 & 0x40) >> 3) | ((*src3 & 0x40) >> 4) | ((*src2 & 0x40) >> 5) | ((*src1 & 0x40) >> 6)]; + dest[2] = remap[(((*src4 & 0x20) << 2) | ((*src3 & 0x20) << 1) | ((*src2 & 0x20)) | ((*src1 & 0x20) >> 1)) >> 4]; + dest[3] = remap[((*src4 & 0x10) >> 1) | ((*src3 & 0x10) >> 2) | ((*src2 & 0x10) >> 3) | ((*src1 & 0x10) >> 4)]; + dest[4] = remap[(((*src4 & 0x08) << 4) | ((*src3 & 0x08) << 3) | ((*src2 & 0x08) << 2) | ((*src1 & 0x08) << 1)) >> 4]; + dest[5] = remap[((*src4 & 0x04) << 1) | ((*src3 & 0x04)) | ((*src2 & 0x04) >> 1) | ((*src1 & 0x04) >> 2)]; + dest[6] = remap[(((*src4 & 0x02) << 6) | ((*src3 & 0x02) << 5) | ((*src2 & 0x02) << 4) | ((*src1 & 0x02) << 3)) >> 4]; + dest[7] = remap[((*src4 & 0x01) << 3) | ((*src3 & 0x01) << 2) | ((*src2 & 0x01) << 1) | ((*src1 & 0x01))]; + dest += 8; + src1 += 1; + src2 += 1; + src3 += 1; + src4 += 1; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +TArray FStartupTexture::CreatePalettedPixels(int conversion) +{ + FileData lump = fileSystem.ReadFile (SourceLump); + const uint8_t *source = (const uint8_t *)lump.GetMem(); + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); + + + TArray Work(Width*Height, true); + TArray Pixels(Width*Height, true); + PlanarToChunky(Work.Data(), source + 48, startuppalette8, Width, Height); + ImageHelpers::FlipNonSquareBlockRemap(Pixels.Data(), Work.Data(), Width, Height, Width, remap); + return Pixels; +} + +//========================================================================== +// +// +// +//========================================================================== + +int FStartupTexture::CopyPixels(FBitmap *bmp, int conversion) +{ + FileData lump = fileSystem.ReadFile (SourceLump); + const uint8_t *source = (const uint8_t *)lump.GetMem(); + uint32_t pindex[16]; + + // Initialize the bitmap palette. + for (int i = 0; i < 16; ++i) + { + PalEntry pe; + pe.r = source[i * 3 + 0]; + pe.g = source[i * 3 + 1]; + pe.b = source[i * 3 + 2]; + pe.a = 63; + // Convert from 6-bit per component to 8-bit per component. + pe.d= (pe.d << 2) | ((pe.d >> 4) & 0x03030303); + pindex[i] = pe; + } + PlanarToChunky((uint32_t*)bmp->GetPixels(), source + 48, startuppalette32, Width, Height); + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +FNotchTexture::FNotchTexture (int lumpnum, int width, int height) +: FImageSource(lumpnum) +{ + Width = width; + Height = height; + bUseGamePalette = false; +} + +//========================================================================== +// +// +// +//========================================================================== + +TArray FNotchTexture::CreatePalettedPixels(int conversion) +{ + FileData lump = fileSystem.ReadFile (SourceLump); + const uint8_t *source = (const uint8_t *)lump.GetMem(); + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); + + TArray Work(Width*Height, true); + TArray Pixels(Width*Height, true); + for(int i=0; i * Width * Height / 2; i++) + { + Work[i * 2] = startuppalette8[source[i] >> 4]; + Work[i * 2 + 1] = startuppalette8[source[i] & 15]; + } + ImageHelpers::FlipNonSquareBlockRemap(Pixels.Data(), Work.Data(), Width, Height, Width, remap); + return Pixels; +} + +//========================================================================== +// +// +// +//========================================================================== + +int FNotchTexture::CopyPixels(FBitmap *bmp, int conversion) +{ + FileData lump = fileSystem.ReadFile (SourceLump); + const uint8_t *source = (const uint8_t *)lump.GetMem(); + + auto Work = (uint32_t*)bmp->GetPixels(); + for(int i=0; i * Width * Height / 2; i++) + { + Work[i * 2] = startuppalette32[source[i] >> 4]; + Work[i * 2 + 1] = startuppalette32[source[i] & 15]; + } + return 0; +} diff --git a/src/common/textures/image.cpp b/src/common/textures/image.cpp index f8f480671..66d6ebc68 100644 --- a/src/common/textures/image.cpp +++ b/src/common/textures/image.cpp @@ -335,6 +335,7 @@ FImageSource *FlatImage_TryCreate(FileReader &, int lumpnum); FImageSource *PatchImage_TryCreate(FileReader &, int lumpnum); FImageSource *EmptyImage_TryCreate(FileReader &, int lumpnum); FImageSource *AutomapImage_TryCreate(FileReader &, int lumpnum); +FImageSource *StartupPageImage_TryCreate(FileReader &, int lumpnum); // Examines the lump contents to decide what type of texture to create, @@ -355,6 +356,7 @@ FImageSource * FImageSource::GetImage(int lumpnum, bool isflat) { PatchImage_TryCreate, false }, { EmptyImage_TryCreate, false }, { AutomapImage_TryCreate, false }, + { StartupPageImage_TryCreate, false }, }; if (lumpnum == -1) return nullptr;