mirror of
https://github.com/brian8544/turtle-wow.git
synced 2024-12-31 20:04:35 +00:00
335 lines
8.2 KiB
C++
335 lines
8.2 KiB
C++
// Aseprite TGA Library
|
|
// Copyright (C) 2020-2021 Igara Studio S.A.
|
|
//
|
|
// This file is released under the terms of the MIT license.
|
|
// Read LICENSE.txt for more information.
|
|
|
|
#ifndef TGA_TGA_H_INCLUDED
|
|
#define TGA_TGA_H_INCLUDED
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <cstdio>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace tga {
|
|
|
|
enum ImageType {
|
|
NoImage = 0,
|
|
UncompressedIndexed = 1,
|
|
UncompressedRgb = 2,
|
|
UncompressedGray = 3,
|
|
RleIndexed = 9,
|
|
RleRgb = 10,
|
|
RleGray = 11,
|
|
};
|
|
|
|
typedef uint32_t color_t;
|
|
|
|
const color_t color_r_shift = 0;
|
|
const color_t color_g_shift = 8;
|
|
const color_t color_b_shift = 16;
|
|
const color_t color_a_shift = 24;
|
|
const color_t color_r_mask = 0x000000ff;
|
|
const color_t color_g_mask = 0x0000ff00;
|
|
const color_t color_b_mask = 0x00ff0000;
|
|
const color_t color_rgb_mask = 0x00ffffff;
|
|
const color_t color_a_mask = 0xff000000;
|
|
|
|
inline uint8_t getr(color_t c) { return (c >> color_r_shift) & 0xff; }
|
|
inline uint8_t getg(color_t c) { return (c >> color_g_shift) & 0xff; }
|
|
inline uint8_t getb(color_t c) { return (c >> color_b_shift) & 0xff; }
|
|
inline uint8_t geta(color_t c) { return (c >> color_a_shift) & 0xff; }
|
|
inline color_t rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255) {
|
|
return ((r << color_r_shift) |
|
|
(g << color_g_shift) |
|
|
(b << color_b_shift) |
|
|
(a << color_a_shift));
|
|
}
|
|
|
|
class Colormap {
|
|
public:
|
|
Colormap() { }
|
|
Colormap(const int n) : m_color(n) { }
|
|
|
|
int size() const { return int(m_color.size()); }
|
|
|
|
const color_t& operator[](int i) const {
|
|
return m_color[i];
|
|
}
|
|
|
|
color_t& operator[](int i) {
|
|
return m_color[i];
|
|
}
|
|
|
|
bool operator==(const Colormap& o) const {
|
|
for (int i=0; i<int(m_color.size()); ++i) {
|
|
if (m_color[i] != o[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool operator!=(const Colormap& o) const {
|
|
return !operator==(o);
|
|
}
|
|
|
|
private:
|
|
std::vector<color_t> m_color;
|
|
};
|
|
|
|
struct Image {
|
|
uint8_t* pixels;
|
|
uint32_t bytesPerPixel;
|
|
uint32_t rowstride;
|
|
};
|
|
|
|
struct Header {
|
|
uint8_t idLength;
|
|
uint8_t colormapType;
|
|
uint8_t imageType;
|
|
uint16_t colormapOrigin;
|
|
uint16_t colormapLength;
|
|
uint8_t colormapDepth;
|
|
uint16_t xOrigin;
|
|
uint16_t yOrigin;
|
|
uint16_t width;
|
|
uint16_t height;
|
|
uint8_t bitsPerPixel;
|
|
uint8_t imageDescriptor;
|
|
std::string imageId;
|
|
Colormap colormap;
|
|
|
|
bool leftToRight() const { return !(imageDescriptor & 0x10); }
|
|
bool topToBottom() const { return (imageDescriptor & 0x20); }
|
|
|
|
bool hasColormap() const {
|
|
return (colormapLength > 0);
|
|
}
|
|
|
|
bool isRgb() const {
|
|
return (imageType == UncompressedRgb ||
|
|
imageType == RleRgb);
|
|
}
|
|
|
|
bool isIndexed() const {
|
|
return (imageType == UncompressedIndexed ||
|
|
imageType == RleIndexed);
|
|
}
|
|
|
|
bool isGray() const {
|
|
return (imageType == UncompressedGray ||
|
|
imageType == RleGray);
|
|
}
|
|
|
|
bool isUncompressed() const {
|
|
return (imageType == UncompressedIndexed ||
|
|
imageType == UncompressedRgb ||
|
|
imageType == UncompressedGray);
|
|
}
|
|
|
|
bool isRle() const {
|
|
return (imageType == RleIndexed ||
|
|
imageType == RleRgb ||
|
|
imageType == RleGray);
|
|
}
|
|
|
|
bool validColormapType() const {
|
|
return
|
|
// Indexed with palette
|
|
(isIndexed() && bitsPerPixel == 8 && colormapType == 1) ||
|
|
// Grayscale without palette
|
|
(isGray() && bitsPerPixel == 8 && colormapType == 0) ||
|
|
// Non-indexed without palette
|
|
(bitsPerPixel > 8 && colormapType == 0);
|
|
}
|
|
|
|
bool valid() const {
|
|
switch (imageType) {
|
|
case UncompressedIndexed:
|
|
case RleIndexed:
|
|
return (bitsPerPixel == 8);
|
|
case UncompressedRgb:
|
|
case RleRgb:
|
|
return (bitsPerPixel == 15 ||
|
|
bitsPerPixel == 16 ||
|
|
bitsPerPixel == 24 ||
|
|
bitsPerPixel == 32);
|
|
case UncompressedGray:
|
|
case RleGray:
|
|
return (bitsPerPixel == 8);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Returns the number of bytes per pixel needed in an image
|
|
// created with this Header information.
|
|
int bytesPerPixel() const {
|
|
if (isRgb())
|
|
return 4;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
};
|
|
|
|
namespace details {
|
|
|
|
class ImageIterator {
|
|
public:
|
|
ImageIterator();
|
|
ImageIterator(const Header& header, Image& image);
|
|
|
|
// Put a pixel value into the image and advance the iterator.
|
|
template<typename T>
|
|
bool putPixel(const T value) {
|
|
*((T*)m_ptr) = value;
|
|
return advance();
|
|
}
|
|
|
|
// Get one pixel from the image and advance the iterator.
|
|
template<typename T>
|
|
T getPixel() {
|
|
T value = *((T*)m_ptr);
|
|
advance();
|
|
return value;
|
|
}
|
|
|
|
public:
|
|
bool advance();
|
|
void calcPtr();
|
|
|
|
Image* m_image;
|
|
int m_x, m_y;
|
|
int m_w, m_h;
|
|
int m_dx, m_dy;
|
|
uint8_t* m_ptr;
|
|
};
|
|
|
|
} // namespace details
|
|
|
|
class FileInterface {
|
|
public:
|
|
virtual ~FileInterface() { }
|
|
|
|
// Returns true if we can read/write bytes from/into the file
|
|
virtual bool ok() const = 0;
|
|
|
|
// Current position in the file
|
|
virtual size_t tell() = 0;
|
|
|
|
// Jump to the given position in the file
|
|
virtual void seek(size_t absPos) = 0;
|
|
|
|
// Returns the next byte in the file or 0 if ok() = false
|
|
virtual uint8_t read8() = 0;
|
|
|
|
// Writes one byte in the file (or do nothing if ok() = false)
|
|
virtual void write8(uint8_t value) = 0;
|
|
};
|
|
|
|
class StdioFileInterface : public tga::FileInterface {
|
|
public:
|
|
StdioFileInterface(FILE* file);
|
|
bool ok() const override;
|
|
size_t tell() override;
|
|
void seek(size_t absPos) override;
|
|
uint8_t read8() override;
|
|
void write8(uint8_t value) override;
|
|
|
|
private:
|
|
FILE* m_file;
|
|
bool m_ok;
|
|
};
|
|
|
|
class Delegate {
|
|
public:
|
|
virtual ~Delegate() {}
|
|
// Must return true if we should continue the decoding process.
|
|
virtual bool notifyProgress(double progress) = 0;
|
|
};
|
|
|
|
class Decoder {
|
|
public:
|
|
Decoder(FileInterface* file);
|
|
|
|
bool hasAlpha() const { return m_hasAlpha; }
|
|
|
|
// Reads the header + colormap (if the file has a
|
|
// colormap). Returns true if the header is valid.
|
|
bool readHeader(Header& header);
|
|
|
|
// Reads the image.
|
|
bool readImage(const Header& header,
|
|
Image& image,
|
|
Delegate* delegate = nullptr);
|
|
|
|
// Fixes alpha channel for images with invalid alpha values (this
|
|
// is optional, in case you want to preserve the original data
|
|
// from the file, don't use it).
|
|
void postProcessImage(const Header& header,
|
|
Image& image);
|
|
|
|
private:
|
|
void readColormap(Header& header);
|
|
|
|
template<typename T>
|
|
bool readUncompressedData(const int w, uint32_t (Decoder::*readPixel)());
|
|
|
|
template<typename T>
|
|
bool readRleData(const int w, uint32_t (Decoder::*readPixel)());
|
|
|
|
uint8_t read8();
|
|
uint16_t read16();
|
|
uint32_t read32();
|
|
|
|
color_t read32AsRgb();
|
|
color_t read24AsRgb();
|
|
color_t read16AsRgb();
|
|
color_t read8Color() { return (color_t)read8(); }
|
|
|
|
FileInterface* m_file;
|
|
bool m_hasAlpha = false;
|
|
details::ImageIterator m_iterator;
|
|
};
|
|
|
|
class Encoder {
|
|
public:
|
|
Encoder(FileInterface* file);
|
|
|
|
// Writes the header + colormap
|
|
void writeHeader(const Header& header);
|
|
void writeImage(const Header& header,
|
|
const Image& image,
|
|
Delegate* delegate = nullptr);
|
|
void writeFooter();
|
|
|
|
private:
|
|
template<typename T>
|
|
void writeRleScanline(const int w, const Image& image,
|
|
void (Encoder::*writePixel)(color_t));
|
|
|
|
template<typename T>
|
|
void countRepeatedPixels(const int w, const Image& image,
|
|
int x0, int& offset, int& count);
|
|
|
|
void write8(uint8_t value);
|
|
void write16(uint16_t value);
|
|
void write32(uint32_t value);
|
|
|
|
void write8Color(color_t c) { write8(uint8_t(c)); }
|
|
void write16Rgb(color_t c);
|
|
void write24Rgb(color_t c);
|
|
void write32Rgb(color_t c);
|
|
|
|
FileInterface* m_file;
|
|
bool m_hasAlpha = false;
|
|
details::ImageIterator m_iterator;
|
|
};
|
|
|
|
} // namespace tga
|
|
|
|
#endif
|