diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 8405b0106..062817c44 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -753,10 +753,21 @@ set (PCH_SOURCES common/textures/bitmap.cpp common/textures/m_png.cpp common/textures/image.cpp + common/textures/formats/automaptexture.cpp + common/textures/formats/brightmaptexture.cpp + common/textures/formats/buildtexture.cpp common/textures/formats/ddstexture.cpp + common/textures/formats/flattexture.cpp + common/textures/formats/imgztexture.cpp common/textures/formats/jpegtexture.cpp + common/textures/formats/md5check.cpp + common/textures/formats/multipatchtexture.cpp + common/textures/formats/patchtexture.cpp common/textures/formats/pcxtexture.cpp common/textures/formats/pngtexture.cpp + common/textures/formats/rawpagetexture.cpp + common/textures/formats/emptytexture.cpp + common/textures/formats/shadertexture.cpp common/textures/formats/tgatexture.cpp common/textures/formats/stbtexture.cpp common/console/c_commandline.cpp @@ -969,6 +980,7 @@ include_directories( common/audio/music common/thirdparty common/textures + common/textures/formats common/filesystem common/utility common/console diff --git a/source/common/textures/formats/automaptexture.cpp b/source/common/textures/formats/automaptexture.cpp new file mode 100644 index 000000000..4135f4908 --- /dev/null +++ b/source/common/textures/formats/automaptexture.cpp @@ -0,0 +1,111 @@ +/* +** automaptexture.cpp +** Texture class for Raven's automap parchment +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** This texture type is only used as a last resort when everything else has failed for creating +** the AUTOPAGE texture. That's because Raven used a raw lump of non-standard proportions to define it. +** +*/ + +#include "files.h" +#include "filesystem.h" +#include "imagehelpers.h" +#include "image.h" + +//========================================================================== +// +// A raw 320x? graphic used by Heretic and Hexen for the automap parchment +// +//========================================================================== + +class FAutomapTexture : public FImageSource +{ +public: + FAutomapTexture(int lumpnum); + TArray CreatePalettedPixels(int conversion) override; +}; + + + +//========================================================================== +// +// This texture type will only be used for the AUTOPAGE lump if no other +// format matches. +// +//========================================================================== + +FImageSource *AutomapImage_TryCreate(FileReader &data, int lumpnum) +{ + if (data.GetLength() < 320) return nullptr; + if (!fileSystem.CheckFileName(lumpnum, "AUTOPAGE")) return nullptr; + return new FAutomapTexture(lumpnum); +} + +//========================================================================== +// +// +// +//========================================================================== + +FAutomapTexture::FAutomapTexture (int lumpnum) +: FImageSource(lumpnum) +{ + Width = 320; + Height = uint16_t(fileSystem.FileLength(lumpnum) / 320); + bUseGamePalette = true; +} + +//========================================================================== +// +// +// +//========================================================================== + +TArray FAutomapTexture::CreatePalettedPixels(int conversion) +{ + int x, y; + FileData data = fileSystem.ReadFile (SourceLump); + const uint8_t *indata = (const uint8_t *)data.GetMem(); + + TArray Pixels(Width * Height, true); + + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); + for (x = 0; x < Width; ++x) + { + for (y = 0; y < Height; ++y) + { + auto p = indata[x + 320 * y]; + Pixels[x*Height + y] = remap[p]; + } + } + return Pixels; +} + diff --git a/source/common/textures/formats/brightmaptexture.cpp b/source/common/textures/formats/brightmaptexture.cpp new file mode 100644 index 000000000..cc4f950dc --- /dev/null +++ b/source/common/textures/formats/brightmaptexture.cpp @@ -0,0 +1,79 @@ +/* +** brightmaptexture.cpp +** The texture class for colormap based brightmaps. +** +**--------------------------------------------------------------------------- +** 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 "filesystem.h" +#include "palettecontainer.h" +#include "bitmap.h" +#include "image.h" + +class FBrightmapTexture : public FImageSource +{ +public: + FBrightmapTexture (FImageSource *source); + + int CopyPixels(FBitmap *bmp, int conversion) override; + +protected: + FImageSource *SourcePic; +}; + +//=========================================================================== +// +// fake brightness maps +// These are generated for textures affected by a colormap with +// fullbright entries. +// +//=========================================================================== + +FBrightmapTexture::FBrightmapTexture (FImageSource *source) +{ + SourcePic = source; + Width = source->GetWidth(); + Height = source->GetHeight(); + bMasked = false; +} + +int FBrightmapTexture::CopyPixels(FBitmap *bmp, int conversion) +{ + SourcePic->CopyTranslatedPixels(bmp, GPalette.GlobalBrightmap.Palette); + return 0; +} + +#if 0 +FTexture *CreateBrightmapTexture(FImageSource *tex) +{ + return CreateImageTexture(new FBrightmapTexture(tex)); +} +#endif diff --git a/source/common/textures/formats/buildtexture.cpp b/source/common/textures/formats/buildtexture.cpp new file mode 100644 index 000000000..83ddf5cd7 --- /dev/null +++ b/source/common/textures/formats/buildtexture.cpp @@ -0,0 +1,78 @@ +/* +** buildtexture.cpp +** Handling Build textures (now as a usable editing feature!) +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** Copyright 2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "bitmap.h" +#include "image.h" +#include "palettecontainer.h" + +#if 0 +//========================================================================== +// +// +// +//========================================================================== + +FBuildTexture::FBuildTexture(const FString &pathprefix, int tilenum, const uint8_t *pixels, FRemapTable *translation, int width, int height, int left, int top) +: RawPixels (pixels), Translation(translation) +{ + Width = width; + Height = height; + LeftOffset = left; + TopOffset = top; +} + +TArray FBuildTexture::CreatePalettedPixels(int conversion) +{ + TArray Pixels(Width * Height, true); + FRemapTable *Remap = Translation; + for (int i = 0; i < Width*Height; i++) + { + auto c = RawPixels[i]; + Pixels[i] = conversion == luminance ? Remap->Palette[c].Luminance() : Remap->Remap[c]; + } + return Pixels; +} + +int FBuildTexture::CopyPixels(FBitmap *bmp, int conversion) +{ + PalEntry *Remap = Translation->Palette; + bmp->CopyPixelData(0, 0, RawPixels, Width, Height, Height, 1, 0, Remap); + return -1; + +} + +#endif \ No newline at end of file diff --git a/source/common/textures/formats/emptytexture.cpp b/source/common/textures/formats/emptytexture.cpp new file mode 100644 index 000000000..ab4703e4e --- /dev/null +++ b/source/common/textures/formats/emptytexture.cpp @@ -0,0 +1,98 @@ +/* +** emptytexture.cpp +** Texture class for empty placeholder textures +** (essentially patches with dimensions and offsets of (0,0) ) +** These need special treatment because a texture size of 0 is illegal +** +**--------------------------------------------------------------------------- +** Copyright 2009 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 "image.h" + +//========================================================================== +// +// +// +//========================================================================== + +class FEmptyTexture : public FImageSource +{ +public: + FEmptyTexture (int lumpnum); + TArray CreatePalettedPixels(int conversion) override; +}; + +//========================================================================== +// +// +// +//========================================================================== + +FImageSource *EmptyImage_TryCreate(FileReader & file, int lumpnum) +{ + char check[8]; + if (file.GetLength() != 8) return NULL; + file.Seek(0, FileReader::SeekSet); + if (file.Read(check, 8) != 8) return NULL; + if (memcmp(check, "\0\0\0\0\0\0\0\0", 8)) return NULL; + + return new FEmptyTexture(lumpnum); +} + +//========================================================================== +// +// +// +//========================================================================== + +FEmptyTexture::FEmptyTexture (int lumpnum) +: FImageSource(lumpnum) +{ + bMasked = true; + Width = Height = 1; + bUseGamePalette = true; +} + +//========================================================================== +// +// +// +//========================================================================== + +TArray FEmptyTexture::CreatePalettedPixels(int conversion) +{ + TArray Pixel(1, true); + Pixel[0] = 0; + return Pixel; +} + diff --git a/source/common/textures/formats/flattexture.cpp b/source/common/textures/formats/flattexture.cpp new file mode 100644 index 000000000..20c5d052a --- /dev/null +++ b/source/common/textures/formats/flattexture.cpp @@ -0,0 +1,117 @@ +/* +** flattexture.cpp +** Texture class for standard Doom flats +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "filesystem.h" +#include "imagehelpers.h" +#include "image.h" + +//========================================================================== +// +// A texture defined between F_START and F_END markers +// +//========================================================================== + +class FFlatTexture : public FImageSource +{ +public: + FFlatTexture (int lumpnum); + TArray CreatePalettedPixels(int conversion) override; +}; + + + +//========================================================================== +// +// Since there is no way to detect the validity of a flat +// they can't be used anywhere else but between F_START and F_END +// +//========================================================================== + +FImageSource *FlatImage_TryCreate(FileReader & file, int lumpnum) +{ + return new FFlatTexture(lumpnum); +} + +//========================================================================== +// +// +// +//========================================================================== + +FFlatTexture::FFlatTexture (int lumpnum) +: FImageSource(lumpnum) +{ + int area; + int bits; + + area = fileSystem.FileLength (lumpnum); + + switch (area) + { + default: + case 64*64: bits = 6; break; + case 8*8: bits = 3; break; + case 16*16: bits = 4; break; + case 32*32: bits = 5; break; + case 128*128: bits = 7; break; + case 256*256: bits = 8; break; + } + + bUseGamePalette = true; + bMasked = false; + bTranslucent = false; + Width = Height = 1 << bits; +} + +//========================================================================== +// +// +// +//========================================================================== + +TArray FFlatTexture::CreatePalettedPixels(int conversion) +{ + auto lump = fileSystem.OpenFileReader (SourceLump); + TArray Pixels(Width*Height, true); + auto numread = lump.Read (Pixels.Data(), Width*Height); + if (numread < Width*Height) + { + memset (Pixels.Data() + numread, 0xBB, Width*Height - numread); + } + ImageHelpers::FlipSquareBlockRemap(Pixels.Data(), Width, ImageHelpers::GetRemap(conversion == luminance)); + return Pixels; +} + diff --git a/source/common/textures/formats/imgztexture.cpp b/source/common/textures/formats/imgztexture.cpp new file mode 100644 index 000000000..5c2e041ac --- /dev/null +++ b/source/common/textures/formats/imgztexture.cpp @@ -0,0 +1,206 @@ +/* +** imgztexture.cpp +** Texture class for IMGZ style images +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "filesystem.h" +#include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" + +bool checkIMGZPalette(FileReader &file); + +//========================================================================== +// +// An IMGZ image (mostly just crosshairs) +// [RH] Just a format I invented to avoid WinTex's palette remapping +// when I wanted to insert some alpha maps. +// +//========================================================================== + +class FIMGZTexture : public FImageSource +{ + struct ImageHeader + { + uint8_t Magic[4]; + uint16_t Width; + uint16_t Height; + int16_t LeftOffset; + int16_t TopOffset; + uint8_t Compression; + uint8_t Reserved[11]; + }; + + bool isalpha = true; + +public: + FIMGZTexture (int lumpnum, uint16_t w, uint16_t h, int16_t l, int16_t t, bool isalpha); + TArray CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion) override; +}; + + +//========================================================================== +// +// +// +//========================================================================== + +FImageSource *IMGZImage_TryCreate(FileReader & file, int lumpnum) +{ + uint32_t magic = 0; + uint16_t w, h; + int16_t l, t; + bool ispalette; + + file.Seek(0, FileReader::SeekSet); + if (file.Read(&magic, 4) != 4) return NULL; + if (magic != MAKE_ID('I','M','G','Z')) return NULL; + w = file.ReadUInt16(); + h = file.ReadUInt16(); + l = file.ReadInt16(); + t = file.ReadInt16(); + ispalette = checkIMGZPalette(file); + return new FIMGZTexture(lumpnum, w, h, l, t, !ispalette); +} + +//========================================================================== +// +// +// +//========================================================================== + +FIMGZTexture::FIMGZTexture (int lumpnum, uint16_t w, uint16_t h, int16_t l, int16_t t, bool _isalpha) + : FImageSource(lumpnum) +{ + Width = w; + Height = h; + LeftOffset = l; + TopOffset = t; + isalpha = _isalpha; + bUseGamePalette = !isalpha; +} + +//========================================================================== +// +// +// +//========================================================================== + +TArray FIMGZTexture::CreatePalettedPixels(int conversion) +{ + FileData lump = fileSystem.ReadFile (SourceLump); + const ImageHeader *imgz = (const ImageHeader *)lump.GetMem(); + const uint8_t *data = (const uint8_t *)&imgz[1]; + + uint8_t *dest_p; + int dest_adv = Height; + int dest_rew = Width * Height - 1; + + TArray Pixels(Width*Height, true); + dest_p = Pixels.Data(); + + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance, isalpha); + + // Convert the source image from row-major to column-major format and remap it + if (!imgz->Compression) + { + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; --x) + { + *dest_p = remap[*data]; + dest_p += dest_adv; + data++; + } + dest_p -= dest_rew; + } + } + else + { + // IMGZ compression is the same RLE used by IFF ILBM files + int runlen = 0, setlen = 0; + uint8_t setval = 0; // Shut up, GCC + + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; ) + { + if (runlen != 0) + { + *dest_p = remap[*data]; + dest_p += dest_adv; + data++; + x--; + runlen--; + } + else if (setlen != 0) + { + *dest_p = setval; + dest_p += dest_adv; + x--; + setlen--; + } + else + { + int8_t code = *data++; + if (code >= 0) + { + runlen = code + 1; + } + else if (code != -128) + { + setlen = (-code) + 1; + setval = remap[*data++]; + } + } + } + dest_p -= dest_rew; + } + } + return Pixels; +} + +//========================================================================== +// +// +// +//========================================================================== + +int FIMGZTexture::CopyPixels(FBitmap *bmp, int conversion) +{ + if (!isalpha) return FImageSource::CopyPixels(bmp, conversion); + else return CopyTranslatedPixels(bmp, GPalette.GrayscaleMap.Palette); +} + diff --git a/source/common/textures/formats/md5check.cpp b/source/common/textures/formats/md5check.cpp new file mode 100644 index 000000000..96e14b2f3 --- /dev/null +++ b/source/common/textures/formats/md5check.cpp @@ -0,0 +1,272 @@ +/* +** md5check.cpp +** Checksums for textures that need special treatment +** +**--------------------------------------------------------------------------- +** Copyright 2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + + +#include +#include "files.h" +#include "md5.h" +#include "printf.h" + +struct MD5Check +{ + int length; + const char *md5; +}; + +// If these lists grow they should maybe put in gzdoom.pk3. + +// The first list is alpha textures in patch format. +// Patches are normally paletted but for these it needs to be treated +// as a grayscale ramp. +static const MD5Check alphapatches[] = +{ +{ 18, "fb1472adb34ce1de7a40156d484dd3fc"}, // xhair5.gfx +{ 59, "7149115092f5e8f01f84dacc120aae94"}, // xhairs9.gfx +{ 62, "7a8d11c24b51e7daff2ab0ffbe3641d9"}, // xhair1.gfx +{ 75, "53ca06706de386ec440a501156dd4bc6"}, // xhair2.gfx +{ 78, "299bd69e46b4ba3632e8bf5a96f1b0cb"}, // xhair3.gfx +{ 86, "643535b5db4361db4177978152294a01"}, // xhairs14.gfx +{ 89, "773bb976dd343266bfe2fc11c1d2a2aa"}, // xhairs13.gfx +{ 100, "493dd248c2cb0d45635ef9cc995db952"}, // xhair4.gfx +{ 105, "257a140b3533713fb59d9be493ba6803"}, // chip4.gfx +{ 105, "7e4b578c7217b7f0c7120d62177dd5bc"}, // xhairs8.gfx +{ 111, "fd9fec58b188284ece38e43c823abd73"}, // chip2.gfx +{ 119, "d6fd267eb249ce01d06fe3e2361eab64"}, // chip3.gfx +{ 122, "4daba1da79b0a009b46e2949a2f8c6f8"}, // chip5.gfx +{ 128, "ed83d41bcf4a91968ffc3ca5cad6a383"}, // chip1.gfx +{ 133, "ca55c89aac30bc8f7e5722520389209e"}, // chip2(2).gfx +{ 134, "2b00983c62e69cad182a5204df163701"}, // xhairb9.gfx +{ 137, "4fb1b26ac278de9ef382e8268cc7e7bb"}, // xhairb8.gfx +{ 138, "b3b69ce27c4b57912232bf718768390a"}, // chip3(2).gfx +{ 147, "ae5625169660aaf44ddffe5553be3e28"}, // xhairs11.gfx +{ 149, "e594798cfad078a553cd21ea6544abac"}, // chip1(2).gfx +{ 152, "bd30eccd4e6afe596af8823d4f8ccf40"}, // xhairb14.gfx +{ 153, "5f2111f1b44cc8cd153e6c08eec3f68c"}, // xhairs10.gfx +{ 160, "27682ca38c949072848c186f499bf027"}, // chip4(2).gfx +{ 168, "7f3d0cf78df24473ffa98ff41d8c93ce"}, // xhairs15.gfx +{ 169, "a0df55d2aee6f72c9164127f8fc9f0dd"}, // ahit.gfx +{ 171, "08c3d1b4bcb5643ae133938778e74c6f"}, // xhairb11.gfx +{ 171, "603355244602e830a2fa9949711a7e83"}, // xhairs12.gfx +{ 177, "6dae9b9bd34805cb066309679f9aaf81"}, // bal7scr1.gfx +{ 177, "a3312ae7011faf08e7903c753e7108b0"}, // xhair6.gfx +{ 183, "142acb37f179aff6e91b430415189c5f"}, // xhair7.gfx +{ 185, "ce1428acd24ced861aa628b4fcefc761"}, // xhairb13.gfx +{ 194, "ab742500964a2298076a4e3ca5f8d8dc"}, // chip5(2).gfx +{ 196, "36e6dd0c675ceb94304954fb1d321f87"}, // xhair8(2).gfx +{ 196, "48ef0cdb8c25e6993e38ddedb0b1a69d"}, // xhairb10.gfx +{ 239, "72384cc34d4345de824e9b775e185155"}, // xhair8.gfx +{ 251, "f3ba8dc69906efee68e27bc37ad8b164"}, // bsplat08_2.gfx +{ 251, "f9138bed705dd05b7ac925751f2173c8"}, // bsplat08.gfx +{ 261, "c6325f4f79f3e36d00eced5d4a160e50"}, // xhairs17.gfx +{ 268, "319f297738ecd5b8e9c32d635c5dc781"}, // bsplat14.gfx +{ 268, "b6e71e5e2a5df85f5a1496ff322cda76"}, // bsplat14_2.gfx +{ 270, "5fe0a8e06182c155fb0508aae1e2c661"}, // xhairb1.gfx +{ 288, "ceb3a910c338fe4f7cdc6c3b49bcb986"}, // xhairb15.gfx +{ 290, "5c8810d3be4b27fdbb7660af04ef91ce"}, // xhairb12.gfx +{ 307, "53564f95e3bcd9f84f463cdb06d4c959"}, // xhairs18.gfx +{ 329, "943cda6f9fbc13bef59c02d38481c1b9"}, // xhairs19.gfx +{ 330, "397071348b313cbf4631e16e292a2816"}, // xhair8(3).gfx +{ 334, "a7efbab516ae51271d7dece02ee7a3da"}, // xhairs16.gfx +{ 341, "ae1f343cbea6ab7892bcc25bd544b149"}, // xhairs20.gfx +{ 359, "3828fb4462f3c559d6a1d5659d736d38"}, // Ascrd1.gfx +{ 397, "3a3a887506a77d812f07ddb46e13d828"}, // Ascrd2.gfx +{ 399, "80a0b9b54618a94fdbd9ff907eb69f2c"}, // Ascrd3.gfx +{ 412, "78cef7b3872c4a47bc47155e3fdc2f45"}, // Ascrd4.gfx +{ 438, "2c08ca266a7df57d609d85b774fb589f"}, // xhairb2.gfx +{ 480, "1f84994c04f4a4941ffc183bda3d9ce3"}, // xhairb17.gfx +{ 521, "833d10c6a1b0ed1cf76ce0012628415d"}, // bsplat07_2.gfx +{ 521, "8658b919b52228d740c057c50038eaac"}, // bsplat07.gfx +{ 521, "c9650cf2f9564b149fbc8c1bbd13c157"}, // Bsplat6.GFX +{ 542, "ddc08f004ee63eeec2fbb474393ec5ed"}, // xhairb19.gfx +{ 569, "3baa1f2b6c05ceb60e5a7ed5f8990263"}, // bsplat13_2.gfx +{ 569, "a1951138cfa47d4ee1033ae088f7ed04"}, // bsplat13.gfx +{ 642, "0f4320a0c53f645d2c3551eeea5ba898"}, // Bsplat5.GFX +{ 642, "968c486e2f2880a3a8d5c7df87a3d8ad"}, // bsplat06.gfx +{ 642, "c41089a518b28be1db182a9d1e7fa7de"}, // bsplat06_2.gfx +{ 653, "7bd11e17dd6672680f5325a4f5496c98"}, // bsplat11.gfx +{ 653, "b57e64f5f98b1fea132a5d6572f24724"}, // bsplat11_2.gfx +{ 653, "e53b9967ef7f93f2ea069b30d6b42444"}, // Bsplat9.GFX +{ 780, "0f95bd26c68d0f3180527aa8dc539d28"}, // Ascra2.gfx +{ 780, "3e0075c2e707083e83c0b897a20d6089"}, // Fdbal2.gfx +{ 801, "3dd3a4bb095deffd70489b9bb6636c96"}, // bsplat12_2.gfx +{ 801, "44703476a6702522047fe0ff0831cc31"}, // bsplat12.gfx +{ 801, "c4a348a488d948dcc70faa6a396b6625"}, // Fdbal1.gfx +{ 801, "f22f176a5e0e2d608c33e2572b28a841"}, // Ascra1.gfx +{ 855, "5385652621b2df49fedd6d970b1d582f"}, // bsplat10_2.gfx +{ 855, "559817e4658047519abbc58a14b2c97c"}, // Bsplat8.GFX +{ 855, "6dee11141dbedff291b9393677276b54"}, // bsplat10.gfx +{ 864, "0300a526b884a27d68d22291b926c1d1"}, // xhairb20.gfx +{ 900, "0fca1f72e22661c39ba0f4e4e9a39c87"}, // bsplat05.gfx +{ 900, "700c0e4cbf0087392e026ac8ab01283d"}, // bsplat05_2.gfx +{ 900, "f414ff86af1611bb90043ca859eb2eda"}, // Bsplat4.GFX +{ 970, "b9ebf0a5895fd2fcadb3304a8f7351b1"}, // xhairb16.gfx +{ 1020, "08d4691ac72069c5a0897650e91a34b8"}, // bsplat04_2.gfx +{ 1020, "3559fb14d0a30f5fae9705f67c9e2b83"}, // bsplat04.gfx +{ 1020, "afe88bbb055060e39e6e757aebd29a96"}, // Bsplat3.GFX +{ 1034, "8671f2be0d2be65340b7a3b819d57933"}, // xhairb18.gfx +{ 1124, "4ec6d839eb2c10a33dfa0191b2200ede"}, // splat.gfx +{ 1149, "5a0040d28c3f84ef895806a3e80d49a6"}, // bsplat01_2.gfx +{ 1149, "783e85a5195ba91667491002a80e03a3"}, // bsplat01.gfx +{ 1189, "295e144b6318abe47b14d1e6bcc7a7fa"}, // bsplat02_2.gfx +{ 1189, "78606aefd9807b51760b4e6dd9203afa"}, // Bsplat1.GFX +{ 1189, "892d3a9fc35e14fd97f526c8b6ea9a3f"}, // bsplat02.gfx +{ 1218, "3bafcd6672b95d1e4fc92367ed10732d"}, // bsplat03_2.gfx +{ 1218, "916964ed55798ebfd288a65ffb09bb02"}, // bsplat03.gfx +{ 1218, "a3f4fca1e8050d7e5d8e64f48bc16515"}, // Bsplat2.GFX +{ 1235, "7927d6dd72ff5dd3b4b0f538fe78d7b9"}, // bsplat09_2.gfx +{ 1235, "d62f324008e74bfea74efd160b668872"}, // bsplat09.gfx +{ 1235, "f6a0df424b064ed6f6744d5891936ab2"}, // Bsplat7.GFX +{ 1717, "df6d834ad357b48feaa9e9d2b0a1f449"}, // bsplat3(2).gfx +{ 1856, "9a9a2cc871a0dec902c8c91e631bc9c8"}, // Snbal2.gfx +{ 1856, "c1e539d6a93a952a5752018d65d577f4"}, // plasma1.gfx +{ 1856, "e60306eefd66bceef1c802732b9163e3"}, // Snbal4.gfx +{ 1942, "84974f010afdabd9351163175b19bb49"}, // Ascrg2.gfx +{ 1942, "a4caf2b9ade6467ea0018bd78321ff50"}, // uscrch2.gfx +{ 1952, "3ee4ddc539059b533c0e31afbf07bb7f"}, // uscrch1.gfx +{ 1952, "e868f1c2bab9752a6cd819b7a7ce6487"}, // Ascrg1.gfx +{ 2035, "36b4e593a7a60d100e4ec081a7d2f809"}, // Ascrc1.gfx +{ 2080, "ebb5c3017a9beb76258f7d374e99a339"}, // bsplat2(2).gfx +{ 2092, "5461be1e0b02d00ff2204ee457fc5d7c"}, // Ascrc2.gfx +{ 2247, "35f936c271a190e3f67aaea1f02dee57"}, // Snbal3.gfx +{ 2247, "3e237bb101d4e3236a5052a1bc5c80d2"}, // plasma2.gfx +{ 2247, "58b4e240b1c5d41e6150df6e320c1349"}, // Snbal1.gfx +{ 2280, "4e1369d2d683d757445a3d78ace82e98"}, // Ascrh2.gfx +{ 2302, "351c1d1cd32637a1d0b4e0168165b266"}, // Ascrh1.gfx +{ 2821, "8c822e94db02cc9d6c851a189c77123e"}, // xhairs51.gfx +{ 2834, "d0099d0fc5aebcdd3994a45ff2560dbc"}, // xhairs50.gfx +{ 2865, "5c0350860fcb89ed28041d6ab0d023a8"}, // xhairs52.gfx +{ 4370, "bda605422fb9144f9671c03405e7c73b"}, // bsmear2_2.gfx +{ 4370, "f3862fb4f336506542e7e9a91bc88261"}, // bsmear2.gfx +{ 4483, "d05e14fbce5864b2df4b92599c48a4c5"}, // Ascre1.gfx +{ 4506, "230ee2c1a8c5baeafbea7248659da3f4"}, // bsplat1(2).gfx +{ 4855, "d27a510aa0285f1c74cb12c7f8ac6d25"}, // bsplat4(2).gfx +{ 6232, "9e7f0b2c6ca50aa8335929c959ba8c51"}, // Ascrf1.gfx +{ 6858, "876c130f90700587b1a71d1aab095746"}, // bsmear1_2.gfx +{ 6858, "c72d6f4c3a0ff3a2d2db1082aea1c884"}, // bsmear1.gfx +{ 7444, "81e4a147ce264394fad80cfd04965d5d"}, // xhairb50.gfx +{ 7452, "aa3f72a47fe2b7c3e353ea62c75d6b42"}, // xhairb51.gfx +{ 7576, "ac2b9c1b53e91bbb0cb260665189291b"}, // xhairb52.gfx +{10164, "3c8908619cd5b357de701a0c6b04f408"}, // splat1.gfx +{ -1, nullptr} +}; + +// These are IMGZ images that use the game palette. +// Normally IMGZ is only used for crosshairs, i.e grayscale images. +static const MD5Check palimgzs[] = +{ +{ 1728, "9ffdd749b414a1d34c74650828ad6504"}, // scodef.imgz +{64024, "bee2a3ddec08bf975353b3dc139bb956"}, // interpic.imgz +{ -1, nullptr} +}; + +//========================================================================== +// +// +// +//========================================================================== + +void makeMD5(const void *buffer, unsigned length, char *md5out) +{ + MD5Context md5; + uint8_t cksum[16]; + + md5.Update((uint8_t*)buffer, length); + md5.Final(cksum); + for (int i = 0; i < 16; i++) + { + mysnprintf(md5out + 2*i, 3, "%02x", cksum[i]); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +bool checkPatchForAlpha(const void *buffer, uint32_t length) +{ + if (length > 10164) return false; // shortcut for anything too large + + char md5[33]; + bool done = false; + + for(int i=0; alphapatches[i].length > 0; i++) + { + if (alphapatches[i].length == (int)length) // length check + { + if (!done) makeMD5(buffer, length, md5); + done = true; + if (!memcmp(md5, alphapatches[i].md5, 32)) + { + return true; + } + } + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + +bool checkIMGZPalette(FileReader &file) +{ + uint32_t length = (uint32_t)file.GetLength(); + char md5[33]; + bool done = false; + for(int i=0; palimgzs[i].length > 0; i++) + { + if (palimgzs[i].length ==(int) length) + { + if (!done) + { + uint8_t *buffer = new uint8_t[length]; + file.Seek(0, FileReader::SeekSet); + file.Read(buffer, length); + makeMD5(buffer, length, md5); + done = true; + delete[] buffer; + } + if (!memcmp(md5, palimgzs[i].md5, 32)) + { + return true; + } + } + } + return false; +} diff --git a/source/common/textures/formats/multipatchtexture.cpp b/source/common/textures/formats/multipatchtexture.cpp new file mode 100644 index 000000000..86c9f8d77 --- /dev/null +++ b/source/common/textures/formats/multipatchtexture.cpp @@ -0,0 +1,339 @@ +/* +** multipatchtexture.cpp +** Texture class for standard Doom multipatch textures +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include "files.h" +#include "filesystem.h" +#include "image.h" +#include "multipatchtexture.h" +#include "imagehelpers.h" + +//========================================================================== +// +// FMultiPatchTexture :: FMultiPatchTexture +// +//========================================================================== + +FMultiPatchTexture::FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual) +{ + Width = w; + Height = h; + bComplex = complex; + bTextual = textual; + Parts = (TexPart*)ImageArena.Alloc(sizeof(TexPart) * parts.Size()); + NumParts = parts.Size(); + memcpy(Parts, parts.Data(), sizeof(TexPart) * parts.Size()); + + bUseGamePalette = false; + if (!bComplex) + { + for (int i = 0; i < NumParts; i++) + { + if (!Parts[i].Image->UseGamePalette()) return; + } + bUseGamePalette = true; // only if all patches use the game palette. + } +} + +//========================================================================== +// +// GetBlendMap +// +//========================================================================== + +static uint8_t *GetBlendMap(PalEntry blend, uint8_t *blendwork) +{ + switch (blend.a==0 ? int(blend) : -1) + { + case BLEND_ICEMAP: + return GPalette.IceMap.Remap; + + default: + if (blend >= BLEND_SPECIALCOLORMAP1 && blend < BLEND_SPECIALCOLORMAP1 + SpecialColormaps.Size()) + { + return SpecialColormaps[blend - BLEND_SPECIALCOLORMAP1].Colormap; + } + else if (blend >= BLEND_DESATURATE1 && blend <= BLEND_DESATURATE31) + { + return DesaturateColormap[blend - BLEND_DESATURATE1]; + } + else + { + blendwork[0]=0; + if (blend.a == 255) + { + for(int i=1;i<256;i++) + { + int rr = (blend.r * GPalette.BaseColors[i].r) / 255; + int gg = (blend.g * GPalette.BaseColors[i].g) / 255; + int bb = (blend.b * GPalette.BaseColors[i].b) / 255; + + blendwork[i] = ColorMatcher.Pick(rr, gg, bb); + } + return blendwork; + } + else if (blend.a != 0) + { + for(int i=1;i<256;i++) + { + int rr = (blend.r * blend.a + GPalette.BaseColors[i].r * (255-blend.a)) / 255; + int gg = (blend.g * blend.a + GPalette.BaseColors[i].g * (255-blend.a)) / 255; + int bb = (blend.b * blend.a + GPalette.BaseColors[i].b * (255-blend.a)) / 255; + + blendwork[i] = ColorMatcher.Pick(rr, gg, bb); + } + return blendwork; + } + } + } + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FMultiPatchTexture::CopyToBlock(uint8_t *dest, int dwidth, int dheight, FImageSource *source, int xpos, int ypos, int rotate, const uint8_t *translation, int style) +{ + auto cimage = source->GetCachedPalettedPixels(style); // should use composition cache + auto &image = cimage.Pixels; + const uint8_t *pixels = image.Data(); + int srcwidth = source->GetWidth(); + int srcheight = source->GetHeight(); + int step_x = source->GetHeight(); + int step_y = 1; + FClipRect cr = { 0, 0, dwidth, dheight }; + if (style) translation = nullptr; // do not apply translations to alpha textures. + + if (ClipCopyPixelRect(&cr, xpos, ypos, pixels, srcwidth, srcheight, step_x, step_y, rotate)) + { + dest += ypos + dheight * xpos; + if (translation == NULL) + { + for (int x = 0; x < srcwidth; x++) + { + int pos = x * dheight; + for (int y = 0; y < srcheight; y++, pos++) + { + // the optimizer is doing a good enough job here so there's no need to optimize this by hand + uint8_t v = pixels[y * step_y + x * step_x]; + if (v != 0) dest[pos] = v; + } + } + } + else + { + for (int x = 0; x < srcwidth; x++) + { + int pos = x * dheight; + for (int y = 0; y < srcheight; y++, pos++) + { + uint8_t v = pixels[y * step_y + x * step_x]; + if (v != 0) dest[pos] = translation[v]; + } + } + } + } +} + +//========================================================================== +// +// FMultiPatchTexture :: MakeTexture +// +//========================================================================== + +TArray FMultiPatchTexture::CreatePalettedPixels(int conversion) +{ + int numpix = Width * Height; + uint8_t blendwork[256]; + bool buildrgb = bComplex; + + TArray Pixels(numpix, true); + memset (Pixels.Data(), 0, numpix); + + if (conversion == luminance) + { + // For alpha textures, downconversion to the palette would lose too much precision if not all patches use the palette. + buildrgb = !UseGamePalette(); + } + else + { + // For regular textures we can use paletted compositing if all patches are just being copied because they all can create a paletted buffer. + if (!buildrgb) for (int i = 0; i < NumParts; ++i) + { + if (Parts[i].op != OP_COPY) + { + buildrgb = true; + } + } + } + if (conversion == noremap0) + { + // sky remapping will only happen if + // - the texture was defined through a TEXTUREx lump (this implies only trivial copies) + // - all patches use the base palette. + // All other cases would not be able to properly deal with this special case. + // For textual definitions this hack isn't necessary. + if (bTextual || !UseGamePalette()) conversion = normal; + } + + if (!buildrgb) + { + for (int i = 0; i < NumParts; ++i) + { + uint8_t *trans = Parts[i].Translation? Parts[i].Translation->Remap : nullptr; + { + if (Parts[i].Blend != 0) + { + trans = GetBlendMap(Parts[i].Blend, blendwork); + } + CopyToBlock (Pixels.Data(), Width, Height, Parts[i].Image, Parts[i].OriginX, Parts[i].OriginY, Parts[i].Rotate, trans, conversion); + } + } + } + else + { + // In case there are translucent patches let's do the composition in + // True color to keep as much precision as possible before downconverting to the palette. + FBitmap PixelsIn; + PixelsIn.Create(Width, Height); + CopyPixels(&PixelsIn, normal); + for(int y = 0; y < Height; y++) + { + uint8_t *in = PixelsIn.GetPixels() + Width * y * 4; + uint8_t *out = Pixels.Data() + y; + for (int x = 0; x < Width; x++) + { + if (*out == 0 && in[3] != 0) + { + *out = ImageHelpers::RGBToPalette(conversion == luminance, in[2], in[1], in[0]); + } + out += Height; + in += 4; + } + } + } + return Pixels; +} + +//=========================================================================== +// +// FMultipatchTexture::CopyTrueColorPixels +// +// Preserves the palettes of each individual patch +// +//=========================================================================== + +int FMultiPatchTexture::CopyPixels(FBitmap *bmp, int conversion) +{ + int retv = -1; + + if (conversion == noremap0) + { + if (bTextual || !UseGamePalette()) conversion = normal; + } + + for(int i = 0; i < NumParts; i++) + { + int ret = -1; + FCopyInfo info; + + memset (&info, 0, sizeof(info)); + info.alpha = Parts[i].Alpha; + info.invalpha = BLENDUNIT - info.alpha; + info.op = ECopyOp(Parts[i].op); + PalEntry b = Parts[i].Blend; + if (b.a == 0 && b != BLEND_NONE) + { + info.blend = EBlend(b.d); + } + else if (b.a != 0) + { + if (b.a == 255) + { + info.blendcolor[0] = b.r * BLENDUNIT / 255; + info.blendcolor[1] = b.g * BLENDUNIT / 255; + info.blendcolor[2] = b.b * BLENDUNIT / 255; + info.blend = BLEND_MODULATE; + } + else + { + blend_t blendalpha = b.a * BLENDUNIT / 255; + info.blendcolor[0] = b.r * blendalpha; + info.blendcolor[1] = b.g * blendalpha; + info.blendcolor[2] = b.b * blendalpha; + info.blendcolor[3] = FRACUNIT - blendalpha; + info.blend = BLEND_OVERLAY; + } + } + + auto trans = Parts[i].Translation ? Parts[i].Translation->Palette : nullptr; + FBitmap Pixels = Parts[i].Image->GetCachedBitmap(trans, conversion, &ret); + bmp->Blit(Parts[i].OriginX, Parts[i].OriginY, Pixels, Pixels.GetWidth(), Pixels.GetHeight(), Parts[i].Rotate, &info); + // treat -1 (i.e. unknown) as absolute. We have no idea if this may have overwritten previous info so a real check needs to be done. + if (ret == -1) retv = ret; + else if (retv != -1 && ret > retv) retv = ret; + } + return retv; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FMultiPatchTexture::CollectForPrecache(PrecacheInfo &info, bool requiretruecolor) +{ + FImageSource::CollectForPrecache(info, requiretruecolor); + + if (!requiretruecolor) + { + requiretruecolor = bComplex; + + if (!requiretruecolor) for (int i = 0; i < NumParts; ++i) + { + if (Parts[i].op != OP_COPY) requiretruecolor = true; + } + } + for (int i = 0; i < NumParts; ++i) + { + Parts[i].Image->CollectForPrecache(info, requiretruecolor); + } +} + + diff --git a/source/common/textures/formats/multipatchtexture.h b/source/common/textures/formats/multipatchtexture.h new file mode 100644 index 000000000..9211eb951 --- /dev/null +++ b/source/common/textures/formats/multipatchtexture.h @@ -0,0 +1,120 @@ +#pragma once +#include "sc_man.h" +#include "palettecontainer.h" +#include "textureid.h" +#include "vectors.h" +#include "bitmap.h" +#include "image.h" + +class FImageTexture; +//========================================================================== +// +// TexPart is the data that will get passed to the final texture. +// +//========================================================================== + +struct TexPart +{ + FRemapTable *Translation = nullptr; + FImageSource *Image = nullptr; + PalEntry Blend = 0; + blend_t Alpha = FRACUNIT; + int16_t OriginX = 0; + int16_t OriginY = 0; + uint8_t Rotate = 0; + uint8_t op = OP_COPY; +}; + + + +//========================================================================== +// +// A texture defined in a TEXTURE1 or TEXTURE2 lump +// +//========================================================================== + +class FMultiPatchTexture : public FImageSource +{ + friend class FTexture; +public: + FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual); + +protected: + int NumParts; + bool bComplex; + bool bTextual; + TexPart *Parts; + + // The getters must optionally redirect if it's a simple one-patch texture. + int CopyPixels(FBitmap *bmp, int conversion) override; + TArray CreatePalettedPixels(int conversion) override; + void CopyToBlock(uint8_t *dest, int dwidth, int dheight, FImageSource *source, int xpos, int ypos, int rotate, const uint8_t *translation, int style); + void CollectForPrecache(PrecacheInfo &info, bool requiretruecolor); + +}; + + +//========================================================================== +// +// Additional data per patch which is needed for initialization +// +//========================================================================== + +struct TexInit +{ + FString TexName; + //ETextureType UseType = ETextureType::Null; + FTexture *Texture = nullptr; + bool Silent = false; + bool HasLine = false; + bool UseOffsets = false; + FScriptPosition sc; +}; + +//========================================================================== +// +// All build info only needed to construct the multipatch textures +// +//========================================================================== + +struct FPatchLookup; + +struct BuildInfo +{ + FString Name; + TArray Parts; + TArray Inits; + int Width = 0; + int Height = 0; + DVector2 Scale = { 1, 1 }; + bool bWorldPanning = false; // This sucks! + int DefinitionLump = 0; + bool bComplex = false; + bool textual = false; + bool bNoDecals = false; + int LeftOffset[2] = {}; + int TopOffset[2] = {}; + FImageTexture *tex = nullptr; + + void swap(BuildInfo &other) + { + Name.Swap(other.Name); + Parts.Swap(other.Parts); + Inits.Swap(other.Inits); + std::swap(Width, other.Width); + std::swap(Height, other.Height); + std::swap(Scale, other.Scale); + std::swap(bWorldPanning, other.bWorldPanning); + std::swap(DefinitionLump, other.DefinitionLump); + std::swap(bComplex, other.bComplex); + std::swap(textual, other.textual); + std::swap(bNoDecals, other.bNoDecals); + std::swap(LeftOffset[0], other.LeftOffset[0]); + std::swap(LeftOffset[1], other.LeftOffset[1]); + std::swap(TopOffset[0], other.TopOffset[0]); + std::swap(TopOffset[1], other.TopOffset[1]); + std::swap(tex, other.tex); + } +}; + + diff --git a/source/common/textures/formats/patchtexture.cpp b/source/common/textures/formats/patchtexture.cpp new file mode 100644 index 000000000..960994b5c --- /dev/null +++ b/source/common/textures/formats/patchtexture.cpp @@ -0,0 +1,304 @@ +/* +** patchtexture.cpp +** Texture class for single Doom patches +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "filesystem.h" +#include "bitmap.h" +#include "image.h" +#include "imagehelpers.h" + + +// posts are runs of non masked source pixels +struct column_t +{ + uint8_t topdelta; // -1 is the last post in a column + uint8_t length; // length data bytes follows +}; + +bool checkPatchForAlpha(const void *buffer, uint32_t length); + +//========================================================================== +// +// A texture that is just a single Doom format patch +// +//========================================================================== + +class FPatchTexture : public FImageSource +{ + bool badflag = false; + bool isalpha = false; +public: + FPatchTexture (int lumpnum, int w, int h, int lo, int to, bool isalphatex); + TArray CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion) override; + void DetectBadPatches(); +}; + +//========================================================================== +// +// Checks if the currently open lump can be a Doom patch +// +//========================================================================== + +static bool CheckIfPatch(FileReader & file, bool &isalpha) +{ + if (file.GetLength() < 13) return false; // minimum length of a valid Doom patch + + file.Seek(0, FileReader::SeekSet); + auto data = file.Read(file.GetLength()); + + const patch_t *foo = (const patch_t *)data.Data(); + + int height = LittleShort(foo->height); + int width = LittleShort(foo->width); + + if (height > 0 && height <= 2048 && width > 0 && width <= 2048 && width < file.GetLength()/4) + { + // The dimensions seem like they might be valid for a patch, so + // check the column directory for extra security. At least one + // column must begin exactly at the end of the column directory, + // and none of them must point past the end of the patch. + bool gapAtStart = true; + int x; + + for (x = 0; x < width; ++x) + { + uint32_t ofs = LittleLong(foo->columnofs[x]); + if (ofs == (uint32_t)width * 4 + 8) + { + gapAtStart = false; + } + else if (ofs >= (uint32_t)(file.GetLength())) // Need one byte for an empty column (but there's patches that don't know that!) + { + return false; + } + } + if (!gapAtStart) + { + // only check this if the texture passed validation. + // Here is a good point because we already have a valid buffer of the lump's data. + isalpha = checkPatchForAlpha(data.Data(), (uint32_t)file.GetLength()); + } + return !gapAtStart; + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + +FImageSource *PatchImage_TryCreate(FileReader & file, int lumpnum) +{ + bool isalpha; + + if (!CheckIfPatch(file, isalpha)) return NULL; + file.Seek(0, FileReader::SeekSet); + int width = file.ReadUInt16(); + int height = file.ReadUInt16(); + int leftoffset = file.ReadInt16(); + int topoffset = file.ReadInt16(); + return new FPatchTexture(lumpnum, width, height, leftoffset, topoffset, isalpha); +} + +//========================================================================== +// +// +// +//========================================================================== + +FPatchTexture::FPatchTexture (int lumpnum, int w, int h, int lo, int to, bool isalphatex) +: FImageSource(lumpnum) +{ + bUseGamePalette = !isalphatex; + isalpha = isalphatex; + Width = w; + Height = h; + LeftOffset = lo; + TopOffset = to; + DetectBadPatches(); +} + +//========================================================================== +// +// +// +//========================================================================== + +TArray FPatchTexture::CreatePalettedPixels(int conversion) +{ + uint8_t *remap, remaptable[256]; + int numspans; + const column_t *maxcol; + int x; + + FileData lump = fileSystem.ReadFile (SourceLump); + const patch_t *patch = (const patch_t *)lump.GetMem(); + + maxcol = (const column_t *)((const uint8_t *)patch + fileSystem.FileLength (SourceLump) - 3); + + remap = ImageHelpers::GetRemap(conversion == luminance, isalpha); + // Special case for skies + if (conversion == noremap0 && remap == GPalette.Remap) + { + memcpy(remaptable, GPalette.Remap, 256); + remaptable[0] = 0; + remap = remaptable; + } + + if (badflag) + { + TArray Pixels(Width * Height, true); + uint8_t *out; + + // Draw the image to the buffer + for (x = 0, out = Pixels.Data(); x < Width; ++x) + { + const uint8_t *in = (const uint8_t *)patch + LittleLong(patch->columnofs[x]) + 3; + + for (int y = Height; y > 0; --y) + { + *out = remap[*in]; + out++, in++; + } + } + return Pixels; + } + + int numpix = Width * Height; + + numspans = Width; + + TArray Pixels(numpix, true); + memset (Pixels.Data(), 0, numpix); + + // Draw the image to the buffer + for (x = 0; x < Width; ++x) + { + uint8_t *outtop = Pixels.Data() + x*Height; + const column_t *column = (const column_t *)((const uint8_t *)patch + LittleLong(patch->columnofs[x])); + int top = -1; + + while (column < maxcol && column->topdelta != 0xFF) + { + if (column->topdelta <= top) + { + top += column->topdelta; + } + else + { + top = column->topdelta; + } + + int len = column->length; + uint8_t *out = outtop + top; + + if (len != 0) + { + if (top + len > Height) // Clip posts that extend past the bottom + { + len = Height - top; + } + if (len > 0) + { + numspans++; + + const uint8_t *in = (const uint8_t *)column + 3; + for (int i = 0; i < len; ++i) + { + out[i] = remap[in[i]]; + } + } + } + column = (const column_t *)((const uint8_t *)column + column->length + 4); + } + } + return Pixels; +} + +//========================================================================== +// +// +// +//========================================================================== + +int FPatchTexture::CopyPixels(FBitmap *bmp, int conversion) +{ + if (!isalpha) return FImageSource::CopyPixels(bmp, conversion); + else return CopyTranslatedPixels(bmp, GPalette.GrayscaleMap.Palette); +} + +//========================================================================== +// +// Fix for certain special patches on single-patch textures. +// +//========================================================================== + +void FPatchTexture::DetectBadPatches () +{ + // The patch must look like it is large enough for the rules to apply to avoid using this on truly empty patches. + if (fileSystem.FileLength(SourceLump) < Width * Height / 2) return; + + // Check if this patch is likely to be a problem. + // It must be 256 pixels tall, and all its columns must have exactly + // one post, where each post has a supposed length of 0. + FileData lump = fileSystem.ReadFile (SourceLump); + const patch_t *realpatch = (patch_t *)lump.GetMem(); + const uint32_t *cofs = realpatch->columnofs; + int x, x2 = LittleShort(realpatch->width); + + if (LittleShort(realpatch->height) == 256) + { + for (x = 0; x < x2; ++x) + { + const column_t *col = (column_t*)((uint8_t*)realpatch+LittleLong(cofs[x])); + if (col->topdelta != 0 || col->length != 0) + { + return; // It's not bad! + } + col = (column_t *)((uint8_t *)col + 256 + 4); + if (col->topdelta != 0xFF) + { + return; // More than one post in a column! + } + } + LeftOffset = 0; + TopOffset = 0; + badflag = true; + bMasked = false; // Hacked textures don't have transparent parts. + } +} diff --git a/source/common/textures/formats/rawpagetexture.cpp b/source/common/textures/formats/rawpagetexture.cpp new file mode 100644 index 000000000..38fca7a67 --- /dev/null +++ b/source/common/textures/formats/rawpagetexture.cpp @@ -0,0 +1,222 @@ +/* +** rawpagetexture.cpp +** Texture class for Raven's raw fullscreen pages +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "filesystem.h" +#include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" + + +//========================================================================== +// +// A raw 320x200 graphic used by Heretic and Hexen fullscreen images +// +//========================================================================== + +class FRawPageTexture : public FImageSource +{ + int mPaletteLump = -1; +public: + FRawPageTexture (int lumpnum); + TArray CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion) override; +}; + +//========================================================================== +// +// RAW textures must be exactly 64000 bytes long and not be identifiable +// as Doom patch +// +//========================================================================== + +static bool CheckIfRaw(FileReader & data) +{ + if (data.GetLength() != 64000) return false; + + // This is probably a raw page graphic, but do some checking to be sure + patch_t *foo; + int height; + int width; + + data.Seek(0, FileReader::SeekSet); + auto bits = data.Read(data.GetLength()); + foo = (patch_t *)bits.Data();; + + height = LittleShort(foo->height); + width = LittleShort(foo->width); + + if (height > 0 && height < 510 && width > 0 && width < 15997) + { + // The dimensions seem like they might be valid for a patch, so + // check the column directory for extra security. At least one + // column must begin exactly at the end of the column directory, + // and none of them must point past the end of the patch. + bool gapAtStart = true; + int x; + + for (x = 0; x < width; ++x) + { + uint32_t ofs = LittleLong(foo->columnofs[x]); + if (ofs == (uint32_t)width * 4 + 8) + { + gapAtStart = false; + } + else if (ofs >= 64000-1) // Need one byte for an empty column + { + return true; + } + else + { + // Ensure this column does not extend beyond the end of the patch + const uint8_t *foo2 = (const uint8_t *)foo; + while (ofs < 64000) + { + if (foo2[ofs] == 255) + { + return true; + } + ofs += foo2[ofs+1] + 4; + } + if (ofs >= 64000) + { + return true; + } + } + } + if (gapAtStart || (x != width)) + { + return true; + } + return false; + } + else + { + return true; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FImageSource *RawPageImage_TryCreate(FileReader & file, int lumpnum) +{ + if (!CheckIfRaw(file)) return nullptr; + return new FRawPageTexture(lumpnum); +} + + +//========================================================================== +// +// +// +//========================================================================== + +FRawPageTexture::FRawPageTexture (int lumpnum) +: FImageSource(lumpnum) +{ + Width = 320; + Height = 200; + + // Special case hack for Heretic's E2 end pic. This is not going to be exposed as an editing feature because the implications would be horrible. + FString Name; + fileSystem.GetFileShortName(Name, lumpnum); + if (Name.CompareNoCase("E2END") == 0) + { + mPaletteLump = fileSystem.CheckNumForName("E2PAL"); + if (fileSystem.FileLength(mPaletteLump) < 768) mPaletteLump = -1; + } + else bUseGamePalette = true; +} + +//========================================================================== +// +// +// +//========================================================================== + +TArray FRawPageTexture::CreatePalettedPixels(int conversion) +{ + FileData lump = fileSystem.ReadFile (SourceLump); + const uint8_t *source = (const uint8_t *)lump.GetMem(); + const uint8_t *source_p = source; + uint8_t *dest_p; + + TArray Pixels(Width*Height, true); + dest_p = Pixels.Data(); + + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); + + // This does not handle the custom palette. + // User maps are encouraged to use a real image format when replacing E2END and the original could never be used anywhere else. + + // Convert the source image from row-major to column-major format + for (int y = 200; y != 0; --y) + { + for (int x = 320; x != 0; --x) + { + *dest_p = remap[*source_p]; + dest_p += 200; + source_p++; + } + dest_p -= 200 * 320 - 1; + } + return Pixels; +} + +int FRawPageTexture::CopyPixels(FBitmap *bmp, int conversion) +{ + if (mPaletteLump < 0) return FImageSource::CopyPixels(bmp, conversion); + else + { + FileData lump = fileSystem.ReadFile(SourceLump); + FileData plump = fileSystem.ReadFile(mPaletteLump); + const uint8_t *source = (const uint8_t *)lump.GetMem(); + const uint8_t *psource = (const uint8_t *)plump.GetMem(); + PalEntry paldata[256]; + for (auto & pe : paldata) + { + pe.r = *psource++; + pe.g = *psource++; + pe.b = *psource++; + pe.a = 255; + } + bmp->CopyPixelData(0, 0, source, 320, 200, 1, 320, 0, paldata); + } + return 0; +} diff --git a/source/common/textures/formats/shadertexture.cpp b/source/common/textures/formats/shadertexture.cpp new file mode 100644 index 000000000..a6160b884 --- /dev/null +++ b/source/common/textures/formats/shadertexture.cpp @@ -0,0 +1,138 @@ +/* +** shadertexture.cpp +** +** simple shader gradient textures, used by the status bars. +** +**--------------------------------------------------------------------------- +** Copyright 2008 Braden Obrzut +** Copyright 2017 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 "filesystem.h" +#include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" + + +class FBarShader : public FImageSource +{ +public: + FBarShader(bool vertical, bool reverse) + { + int i; + + Width = vertical ? 2 : 256; + Height = vertical ? 256 : 2; + bMasked = false; + bTranslucent = false; + + // Fill the column/row with shading values. + // Vertical shaders have have minimum alpha at the top + // and maximum alpha at the bottom, unless flipped by + // setting reverse to true. Horizontal shaders are just + // the opposite. + if (vertical) + { + if (!reverse) + { + for (i = 0; i < 256; ++i) + { + Pixels[i] = i; + Pixels[256+i] = i; + } + } + else + { + for (i = 0; i < 256; ++i) + { + Pixels[i] = 255 - i; + Pixels[256+i] = 255 -i; + } + } + } + else + { + if (!reverse) + { + for (i = 0; i < 256; ++i) + { + Pixels[i*2] = 255 - i; + Pixels[i*2+1] = 255 - i; + } + } + else + { + for (i = 0; i < 256; ++i) + { + Pixels[i*2] = i; + Pixels[i*2+1] = i; + } + } + } + } + + TArray CreatePalettedPixels(int conversion) override + { + TArray Pix(512, true); + if (conversion == luminance) + { + memcpy(Pix.Data(), Pixels, 512); + } + else + { + // Since this presents itself to the game as a regular named texture + // it can easily be used on walls and flats and should work as such, + // even if it makes little sense. + for (int i = 0; i < 512; i++) + { + Pix[i] = GPalette.GrayMap[Pixels[i]]; + } + } + return Pix; + } + + int CopyPixels(FBitmap *bmp, int conversion) override + { + bmp->CopyPixelData(0, 0, Pixels, Width, Height, Height, 1, 0, GPalette.GrayRamp.Palette); + return 0; + } + +private: + uint8_t Pixels[512]; +}; + + +#if 0 +FTexture *CreateShaderTexture(bool vertical, bool reverse) +{ + FStringf name("BarShader%c%c", vertical ? 'v' : 'h', reverse ? 'r' : 'f'); + return CreateImageTexture(new FBarShader(vertical, reverse), name.GetChars()); + +} +#endif diff --git a/source/common/textures/image.cpp b/source/common/textures/image.cpp index 76b0cc267..ef40efd19 100644 --- a/source/common/textures/image.cpp +++ b/source/common/textures/image.cpp @@ -326,12 +326,18 @@ struct TexCreateInfo bool checkflat; }; +FImageSource *IMGZImage_TryCreate(FileReader &, int lumpnum); FImageSource *PNGImage_TryCreate(FileReader &, int lumpnum); FImageSource *JPEGImage_TryCreate(FileReader &, int lumpnum); FImageSource *DDSImage_TryCreate(FileReader &, int lumpnum); FImageSource *PCXImage_TryCreate(FileReader &, int lumpnum); FImageSource *TGAImage_TryCreate(FileReader &, int lumpnum); FImageSource *StbImage_TryCreate(FileReader &, int lumpnum); +FImageSource *RawPageImage_TryCreate(FileReader &, int lumpnum); +FImageSource *FlatImage_TryCreate(FileReader &, int lumpnum); +FImageSource *PatchImage_TryCreate(FileReader &, int lumpnum); +FImageSource *EmptyImage_TryCreate(FileReader &, int lumpnum); +FImageSource *AutomapImage_TryCreate(FileReader &, int lumpnum); // Examines the lump contents to decide what type of texture to create, @@ -339,12 +345,18 @@ FImageSource *StbImage_TryCreate(FileReader &, int lumpnum); FImageSource * FImageSource::GetImage(int lumpnum, bool isflat) { static TexCreateInfo CreateInfo[] = { + { IMGZImage_TryCreate, false }, { PNGImage_TryCreate, false }, { JPEGImage_TryCreate, false }, { DDSImage_TryCreate, false }, { PCXImage_TryCreate, false }, { StbImage_TryCreate, false }, { TGAImage_TryCreate, false }, + { RawPageImage_TryCreate, false }, + { FlatImage_TryCreate, true }, // flat detection is not reliable, so only consider this for real flats. + { PatchImage_TryCreate, false }, + { EmptyImage_TryCreate, false }, + { AutomapImage_TryCreate, false }, }; if (lumpnum == -1) return nullptr;