mirror of
https://github.com/CorsixTH/CorsixTH.git
synced 2025-07-23 04:13:01 +02:00
Add: SpriteEncoder source code, description, and a simple decoder.
This commit is contained in:
78
SpriteEncoder/32bpp_pixformat.txt
Normal file
78
SpriteEncoder/32bpp_pixformat.txt
Normal file
@@ -0,0 +1,78 @@
|
||||
Copyright (c) 2013 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
|
||||
Pixel format of 32bpp images.
|
||||
|
||||
The pixel format supports image sizes of up to 65534x65534 pixels, allows
|
||||
transparency, and up to 256 recolour layers.
|
||||
|
||||
The file starts with
|
||||
- 4 bytes header "CTHG"
|
||||
- 2 bytes version number (low endian), currently version 2
|
||||
- zero or more sprites.
|
||||
|
||||
A sprite has
|
||||
- 4 bytes length of this sprite (low endian), length excludes these 4 bytes.
|
||||
- 2 bytes sprite number (low endian).
|
||||
- 2 bytes width of the sprite (low endian).
|
||||
- 2 bytes height of the sprite (low endian).
|
||||
- (width * height) pixel data as a continuous stream.
|
||||
|
||||
The pixel data starts at the top-left pixel, and runs horizontally (and
|
||||
continues at the left of the next line when reaching the end). This continues
|
||||
until the last pixel at the bottom-right has been written.
|
||||
|
||||
Sequences of pixels with the same characteristics are taken together in blocks
|
||||
of up to 64 pixels long, and encoded. There are four types of blocks:
|
||||
|
||||
1. Fixed fully opaque 32bpp pixels (all the coloured pixels that are always the
|
||||
same).
|
||||
2. Fixed partially transparent 32bpp pixels (glow effects, or 50% transparency).
|
||||
3. Fixed fully transparent pixels (empty space around the displayed shape to
|
||||
make it a rectangular image).
|
||||
4. Recolour layer (pixels that are retrieved from an RGB table with 256 entries
|
||||
that acts like a palette). The data stored in the sprite is just the index
|
||||
to use for each pixel. Opacity is the same for the entire block.
|
||||
|
||||
Typically there are tables with ranges of colours, and the sprite contains
|
||||
the intensity as the index.
|
||||
|
||||
|
||||
Below is the encoding for each type of pixel block:
|
||||
|
||||
1. Fixed fully opaque 32bpp pixels (RGB).
|
||||
- 1 byte length (values 0-63)
|
||||
- N x 3 byte pixel colours (RGB).
|
||||
|
||||
2. Fixed partially transparent 32bpp pixels (RGB).
|
||||
- 1 byte length (values 0-63) + 64
|
||||
- 1 byte amount of opacity (0-255).
|
||||
- N x 3 byte pixel colours (RGB).
|
||||
|
||||
3. Fixed fully transparent pixels.
|
||||
- 1 byte length (values 0-63) + 128
|
||||
|
||||
4. Recolour layer.
|
||||
- 1 byte length (values 0-63) + 64 + 128
|
||||
- 1 byte layer to apply (0-255).
|
||||
- 1 byte amount of opacity (0-255).
|
||||
- N bytes table index.
|
267
SpriteEncoder/ast.cpp
Normal file
267
SpriteEncoder/ast.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
Copyright (c) 2013 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include "ast.h"
|
||||
#include "image.h"
|
||||
#include "output.h"
|
||||
|
||||
enum Opacity
|
||||
{
|
||||
OP_TRANSPARENT = 0,
|
||||
OP_OPAQUE = 255,
|
||||
};
|
||||
|
||||
const std::string sUnset = "<unset>";
|
||||
|
||||
Sprite::Sprite()
|
||||
{
|
||||
m_iLine = -1;
|
||||
m_iSprite = -1;
|
||||
m_iLeft = -1;
|
||||
m_iTop = -1;
|
||||
m_iWidth = -1;
|
||||
m_iHeight = -1;
|
||||
m_sBaseImage = sUnset;
|
||||
m_sRecolourImage = sUnset;
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
m_aNumber[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::SetRecolour(const std::string &sFilename)
|
||||
{
|
||||
m_sRecolourImage = sFilename;
|
||||
}
|
||||
|
||||
static void Report(int iNumber, int iLine, const char *pMsg)
|
||||
{
|
||||
if (iNumber < 0)
|
||||
{
|
||||
fprintf(stderr, "Sprite at line %d: Missing %s\n", iLine, pMsg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::Check() const
|
||||
{
|
||||
Report(m_iSprite, m_iLine, "sprite number");
|
||||
Report(m_iLeft, m_iLine, "left edge coordinate");
|
||||
Report(m_iTop, m_iLine, "top edge coordinate");
|
||||
Report(m_iWidth, m_iLine, "sprite width");
|
||||
Report(m_iHeight, m_iLine, "sprite height");
|
||||
|
||||
if (m_sBaseImage == sUnset)
|
||||
{
|
||||
fprintf(stderr, "Sprite at line %d: Missing image filename\n", m_iLine);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look ahead in the recolour bitmaps to check when the next recoloured pixels will occur.
|
||||
* @param iCount Current index in the image.
|
||||
* @param iEndCount End of the image.
|
||||
* @param pLayer Recolouring bitmap (if available).
|
||||
* @return Number of pixels to go before the next recoloured pixel (limited to 63 look ahead).
|
||||
*/
|
||||
static int GetDistanceToNextRecolour(const uint32 iCount, const uint32 iEndCount, const Image8bpp *pLayer)
|
||||
{
|
||||
uint32 iLength = iEndCount - iCount;
|
||||
if (iLength > 63) iLength = 63; // No need to look ahead further.
|
||||
|
||||
if (pLayer != NULL)
|
||||
{
|
||||
for (size_t i = 0; i < iLength; i++)
|
||||
{
|
||||
if (pLayer->Get(iCount + i) != 0) return i;
|
||||
}
|
||||
}
|
||||
return iLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the recolour table to use, and the number of pixels to recolour.
|
||||
* @param iCount Current index in the image.
|
||||
* @param iEndCount End of the image.
|
||||
* @param pLayer Recolouring bitmap.
|
||||
* @param pLayerNumber [out] Number of the recolouring table to use.
|
||||
* @return Number of pixels to recolour from the current position.
|
||||
*/
|
||||
static int GetRecolourInformation(const uint32 iCount, const uint32 iEndCount, const Image8bpp *pLayer, uint8 *pLayerNumber)
|
||||
{
|
||||
uint32 iLength = iEndCount - iCount;
|
||||
if (iLength > 63) iLength = 63; // No need to look ahead further.
|
||||
|
||||
*pLayerNumber = pLayer->Get(iCount);
|
||||
for (size_t i = 1; i < iLength; i++)
|
||||
{
|
||||
if (pLayer->Get(iCount + i) != *pLayerNumber) return i;
|
||||
}
|
||||
return iLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look ahead in the base image to check how many pixels from the current position have the same opacity.
|
||||
* @param iCount Current index in the image.
|
||||
* @param iEndCount End of the image.
|
||||
* @parswm oBase Base image.
|
||||
* @return Number of pixels to go before the opacity of the current pixel changes (limited to 63 look ahead).
|
||||
*/
|
||||
static int GetDistanceToNextTransparency(const uint32 iCount, const uint32 iEndCount, const Image32bpp &oBase)
|
||||
{
|
||||
uint32 iLength = iEndCount - iCount;
|
||||
if (iLength > 63) iLength = 63; // No need to look ahead further.
|
||||
|
||||
uint8 iOpacity = GetA(oBase.Get(iCount));
|
||||
for (uint i = 1; i < iLength; i++)
|
||||
{
|
||||
if (iOpacity != GetA(oBase.Get(iCount + i))) return i;
|
||||
}
|
||||
return iLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the RGB colour for the next \a iLength pixels, starting from the \a iCount offset.
|
||||
* @param oBase Base image to encode.
|
||||
* @param iCount Current index in the image.
|
||||
* @param iLength Number of pixels to process.
|
||||
* @param pDest Destination to write to.
|
||||
*/
|
||||
static void WriteColour(const Image32bpp &oBase, uint32 iCount, int iLength, Output *pDest)
|
||||
{
|
||||
while (iLength > 0)
|
||||
{
|
||||
uint32 iColour = oBase.Get(iCount);
|
||||
iCount++;
|
||||
pDest->Uint8(GetR(iColour));
|
||||
pDest->Uint8(GetG(iColour));
|
||||
pDest->Uint8(GetB(iColour));
|
||||
iLength--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the table index for the next \a iLength pixels, starting from the \a iCount offset.
|
||||
* @param oBase Base image to encode.
|
||||
* @param iCount Current index in the image.
|
||||
* @param iLength Number of pixels to process.
|
||||
* @param pDest Destination to write to.
|
||||
*/
|
||||
static void WriteTableIndex(const Image32bpp &oBase, uint32 iCount, int iLength, Output *pDest)
|
||||
{
|
||||
while (iLength > 0)
|
||||
{
|
||||
uint32 iColour = oBase.Get(iCount);
|
||||
iCount++;
|
||||
uint8 biggest = GetR(iColour);
|
||||
if (biggest < GetG(iColour)) biggest = GetG(iColour);
|
||||
if (biggest < GetB(iColour)) biggest = GetB(iColour);
|
||||
pDest->Uint8(biggest);
|
||||
iLength--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a 32bpp image from the \a oBase image, and optionally the recolouring \a pLayer bitmap.
|
||||
*/
|
||||
static void Encode32bpp(int iWidth, int iHeight, const Image32bpp &oBase, const Image8bpp *pLayer, Output *pDest, const unsigned char *pNumber)
|
||||
{
|
||||
const uint32 iPixCount = iWidth * iHeight;
|
||||
uint32 iCount = 0;
|
||||
while (iCount < iPixCount)
|
||||
{
|
||||
int iLength = GetDistanceToNextRecolour(iCount, iPixCount, pLayer);
|
||||
int length2 = GetDistanceToNextTransparency(iCount, iPixCount, oBase);
|
||||
|
||||
if (iLength > 63) iLength = 63;
|
||||
if (iLength == 0) { // Recolour layer.
|
||||
uint8 iTableNumber;
|
||||
iLength = GetRecolourInformation(iCount, iPixCount, pLayer, &iTableNumber);
|
||||
if (length2 < iLength) iLength = length2;
|
||||
assert(iLength > 0);
|
||||
|
||||
pDest->Uint8(64 + 128 + iLength);
|
||||
pDest->Uint8(pNumber[iTableNumber]);
|
||||
pDest->Uint8(GetA(oBase.Get(iCount))); // Opacity.
|
||||
WriteTableIndex(oBase, iCount, iLength, pDest);
|
||||
iCount += iLength;
|
||||
continue;
|
||||
}
|
||||
if (length2 < iLength) iLength = length2;
|
||||
assert(iLength > 0);
|
||||
|
||||
uint8 iOpacity = GetA(oBase.Get(iCount));
|
||||
if (iOpacity == OP_OPAQUE) { // Fixed non-transparent 32bpp pixels (RGB).
|
||||
pDest->Uint8(iLength);
|
||||
WriteColour(oBase, iCount, iLength, pDest);
|
||||
iCount += iLength;
|
||||
continue;
|
||||
}
|
||||
if (iOpacity == OP_TRANSPARENT) { // Fixed fully transparent pixels.
|
||||
pDest->Uint8(128 + iLength);
|
||||
iCount += iLength;
|
||||
continue;
|
||||
}
|
||||
/* Partially transparent 32bpp pixels (RGB). */
|
||||
pDest->Uint8(64 + iLength);
|
||||
pDest->Uint8(iOpacity);
|
||||
WriteColour(oBase, iCount, iLength, pDest);
|
||||
iCount += iLength;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::Write(Output *pOut) const
|
||||
{
|
||||
Image32bpp *pBase = Load32Bpp(m_sBaseImage, m_iLine, m_iLeft, m_iWidth, m_iTop, m_iHeight);
|
||||
if (pBase == NULL)
|
||||
{
|
||||
fprintf(stderr, "Warning: Skipping sprite %d at line %d: Image load failed.\n", m_iSprite, m_iLine);
|
||||
return;
|
||||
}
|
||||
|
||||
Image8bpp *pLayer = NULL;
|
||||
if (m_sRecolourImage != sUnset)
|
||||
{
|
||||
pLayer = Load8Bpp(m_sRecolourImage, m_iLine, m_iLeft, m_iWidth, m_iTop, m_iHeight);
|
||||
}
|
||||
|
||||
int iAddress = pOut->Reserve(4);
|
||||
pOut->Uint16(m_iSprite);
|
||||
pOut->Uint16(m_iWidth);
|
||||
pOut->Uint16(m_iHeight); // XXX Add length of this sprite?
|
||||
Encode32bpp(m_iWidth, m_iHeight, *pBase, pLayer, pOut, m_aNumber);
|
||||
|
||||
int iLength = pOut->Reserve(0) - (iAddress + 4); // Start counting after the length.
|
||||
pOut->Write(iAddress, iLength & 0xFF);
|
||||
pOut->Write(iAddress + 1, (iLength >> 8) & 0xFF);
|
||||
pOut->Write(iAddress + 2, (iLength >> 16) & 0xFF);
|
||||
pOut->Write(iAddress + 3, (iLength >> 24) & 0xFF);
|
||||
|
||||
delete pLayer;
|
||||
delete pBase;
|
||||
}
|
||||
|
||||
// vim: et sw=4 ts=4 sts=4
|
75
SpriteEncoder/ast.h
Normal file
75
SpriteEncoder/ast.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright (c) 2013 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef AST_H
|
||||
#define AST_H
|
||||
|
||||
#include <set>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
class Output;
|
||||
|
||||
class Sprite
|
||||
{
|
||||
public:
|
||||
Sprite();
|
||||
|
||||
void SetRecolour(const std::string &filename);
|
||||
void Check() const;
|
||||
void Write(Output *out) const;
|
||||
|
||||
int m_iLine; // Line number of the sprite.
|
||||
int m_iSprite; // Sprite number.
|
||||
int m_iLeft; // Left coordinate in the images.
|
||||
int m_iTop; // Top coordinate in the images.
|
||||
int m_iWidth; // Width of the images.
|
||||
int m_iHeight; // Height of the images.
|
||||
std::string m_sBaseImage; // Full-colour RGBA base image.
|
||||
std::string m_sRecolourImage; // Name of overlay image (if set).
|
||||
unsigned char m_aNumber[256]; // Layer number of the recolouring.
|
||||
};
|
||||
|
||||
inline static bool operator<(const Sprite &s1, const Sprite &s2)
|
||||
{
|
||||
return s1.m_iSprite < s2.m_iSprite;
|
||||
}
|
||||
|
||||
struct ScannerData
|
||||
{
|
||||
int line;
|
||||
int number;
|
||||
std::string text;
|
||||
Sprite *m_pSprite;
|
||||
};
|
||||
|
||||
#define YYSTYPE ScannerData
|
||||
extern YYSTYPE yylval;
|
||||
int yylex();
|
||||
int yyparse();
|
||||
void yyerror(const char *msg);
|
||||
void SetupScanner(const char *fname, FILE *new_file);
|
||||
|
||||
extern std::set<Sprite> g_oSprites;
|
||||
|
||||
#endif
|
||||
|
161
SpriteEncoder/decode.py
Normal file
161
SpriteEncoder/decode.py
Normal file
@@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Program to decode the first sprite of a CTHG 2 file.
|
||||
Mainly intended as a test for the checking the encoder, but also a demonstration of how to decode.
|
||||
"""
|
||||
|
||||
_license = """
|
||||
Copyright (c) 2013 Alberth "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
from PIL import Image
|
||||
|
||||
class Infile:
|
||||
def __init__(self, fname):
|
||||
self.fname = fname
|
||||
self.handle = open(self.fname, "rb")
|
||||
|
||||
# Read header
|
||||
for h in [ord('C'), ord('T'), ord('H'), ord('G'), 2, 0]:
|
||||
v = self.getByte()
|
||||
assert v == h
|
||||
|
||||
def getByte(self):
|
||||
v = self.handle.read(1)[0]
|
||||
return v
|
||||
|
||||
def getWord(self):
|
||||
b = self.getByte()
|
||||
return b | (self.getByte() << 8)
|
||||
|
||||
def getLong(self):
|
||||
w = self.getWord()
|
||||
return w | (self.getWord() << 16)
|
||||
|
||||
def getData(self, size):
|
||||
data = []
|
||||
for i in range(size):
|
||||
data.append(self.getByte())
|
||||
return data
|
||||
|
||||
def decode_xy(pix_idx, w, h):
|
||||
y = pix_idx // w
|
||||
x = pix_idx - w * y
|
||||
assert x >= 0 and x < w
|
||||
assert y >= 0 and y < h
|
||||
return x, y
|
||||
|
||||
def get_colour(table, idx):
|
||||
if table == 0:
|
||||
return (0, 0, 0, 255)
|
||||
if table == 1:
|
||||
return (idx, 0, 0, 255)
|
||||
if table == 2:
|
||||
return (0, idx, 0, 255)
|
||||
if table == 3:
|
||||
return (0, 0, idx, 255)
|
||||
if table == 4:
|
||||
return (0, idx, idx, 255)
|
||||
if table == 5:
|
||||
return (idx, 0, idx, 255)
|
||||
assert False
|
||||
|
||||
class Sprite:
|
||||
def __init__(self, infile):
|
||||
size = infile.getLong() - 2 - 2 - 2
|
||||
self.number = infile.getWord()
|
||||
self.width = infile.getWord()
|
||||
self.height = infile.getWord()
|
||||
self.data = infile.getData(size)
|
||||
|
||||
print("Sprite number {}".format(self.number))
|
||||
print("Width {}".format(self.width))
|
||||
print("Height {}".format(self.height))
|
||||
print("Size {}".format(size))
|
||||
print("Data size {}".format(len(self.data)))
|
||||
|
||||
def get_data(self, idx):
|
||||
return self.data[idx], idx + 1
|
||||
|
||||
def save(self):
|
||||
im = Image.new("RGBA", (self.width, self.height), (0,0,0,0))
|
||||
pix = im.load()
|
||||
|
||||
idx = 0
|
||||
pix_idx = 0
|
||||
while idx < len(self.data):
|
||||
length, idx = self.get_data(idx)
|
||||
|
||||
if length <= 63: # Fixed non-transparent 32bpp pixels (RGB)
|
||||
length = length & 63
|
||||
x, y = decode_xy(pix_idx, self.width, self.height)
|
||||
for i in range(length):
|
||||
d = (self.data[idx], self.data[idx+1], self.data[idx+2], 255)
|
||||
pix[x,y] = d
|
||||
idx = idx + 3
|
||||
pix_idx = pix_idx + 1
|
||||
x = x + 1
|
||||
if x == self.width:
|
||||
x = 0
|
||||
y = y + 1
|
||||
continue
|
||||
|
||||
elif length <= 64+63: # Partially transparent 32bpp pixels (RGB)
|
||||
length = length & 63
|
||||
opacity, idx = self.get_data(idx)
|
||||
x, y = decode_xy(pix_idx, self.width, self.height)
|
||||
for i in range(length):
|
||||
d = (self.data[idx], self.data[idx+1], self.data[idx+2], opacity)
|
||||
pix[x,y] = d
|
||||
idx = idx + 3
|
||||
pix_idx = pix_idx + 1
|
||||
x = x + 1
|
||||
if x == self.width:
|
||||
x = 0
|
||||
y = y + 1
|
||||
continue
|
||||
|
||||
elif length <= 128+63: # Fixed fully transparent pixels
|
||||
length = length & 63
|
||||
pix_idx = pix_idx + length
|
||||
continue
|
||||
|
||||
else: # Recolour layer.
|
||||
length = length & 63
|
||||
table, idx = self.get_data(idx)
|
||||
opacity, idx = self.get_data(idx)
|
||||
x, y = decode_xy(pix_idx, self.width, self.height)
|
||||
for i in range(length):
|
||||
col, idx = self.get_data(idx)
|
||||
pix[x, y] = get_colour(table, col)
|
||||
pix_idx = pix_idx + 1
|
||||
x = x + 1
|
||||
if x == self.width:
|
||||
x = 0
|
||||
y = y + 1
|
||||
continue
|
||||
|
||||
im.save("sprite_" + str(self.number) + ".png")
|
||||
|
||||
|
||||
inf = Infile("x.out")
|
||||
spr = Sprite(inf)
|
||||
spr.save()
|
89
SpriteEncoder/encode.cpp
Normal file
89
SpriteEncoder/encode.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright (c) 2013 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include "ast.h"
|
||||
#include "output.h"
|
||||
|
||||
int main(int iArgc, char *pArgv[])
|
||||
{
|
||||
FILE *pInfile = NULL;
|
||||
const char *pOutfname = NULL;
|
||||
if (iArgc == 1)
|
||||
{
|
||||
SetupScanner(NULL, NULL);
|
||||
}
|
||||
else if (strcmp(pArgv[1], "-h") == 0 || strcmp(pArgv[1], "--help") == 0)
|
||||
{
|
||||
printf("Usage: encode <sprite-file> [<output-file>]\n");
|
||||
exit(0);
|
||||
}
|
||||
else if (iArgc == 2)
|
||||
{
|
||||
pInfile = fopen(pArgv[1], "r");
|
||||
SetupScanner(pArgv[1], pInfile);
|
||||
}
|
||||
else if (iArgc == 3)
|
||||
{
|
||||
pInfile = fopen(pArgv[1], "r");
|
||||
SetupScanner(pArgv[1], pInfile);
|
||||
pOutfname = pArgv[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Too many arguments, try 'encode -h'\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int iRet = yyparse();
|
||||
if (pInfile != NULL) fclose(pInfile);
|
||||
|
||||
if (iRet != 0)
|
||||
{
|
||||
exit(iRet);
|
||||
}
|
||||
|
||||
for (std::set<Sprite>::iterator iter = g_oSprites.begin(); iter != g_oSprites.end(); iter++)
|
||||
{
|
||||
iter->Check();
|
||||
}
|
||||
|
||||
Output out;
|
||||
out.Uint8('C'); out.Uint8('T'); out.Uint8('H'); out.Uint8('G');
|
||||
out.Uint8(2); out.Uint8(0);
|
||||
|
||||
for (std::set<Sprite>::iterator iter = g_oSprites.begin(); iter != g_oSprites.end(); iter++)
|
||||
{
|
||||
iter->Write(&out);
|
||||
}
|
||||
|
||||
if (pOutfname != NULL)
|
||||
{
|
||||
out.Write(pOutfname);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// vim: et sw=4 ts=4 sts=4
|
||||
|
263
SpriteEncoder/image.cpp
Normal file
263
SpriteEncoder/image.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
Copyright (c) 2013 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <png.h>
|
||||
#include "image.h"
|
||||
|
||||
uint32 MakeRGBA(uint8 r, uint8 g, uint8 b, uint8 a)
|
||||
{
|
||||
assert(sizeof(uint32) == 4); // Not really the good place, but it has to be checked somewhere!
|
||||
|
||||
uint32 ret;
|
||||
uint32 x;
|
||||
x = r; ret = x;
|
||||
x = g; ret |= (x << 8);
|
||||
x = b; ret |= (x << 16);
|
||||
x = a; ret |= (x << 24);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8 GetR(uint32 rgba) { return rgba & 0xFF; }
|
||||
uint8 GetG(uint32 rgba) { return (rgba >> 8) & 0xFF; }
|
||||
uint8 GetB(uint32 rgba) { return (rgba >> 16) & 0xFF; }
|
||||
uint8 GetA(uint32 rgba) { return (rgba >> 24) & 0xFF; }
|
||||
|
||||
|
||||
Image32bpp::Image32bpp(int iWidth, int iHeight)
|
||||
{
|
||||
this->iWidth = iWidth;
|
||||
this->iHeight = iHeight;
|
||||
pData = (uint32 *)malloc(4 * iWidth * iHeight);
|
||||
}
|
||||
|
||||
Image32bpp::~Image32bpp()
|
||||
{
|
||||
free(pData);
|
||||
}
|
||||
|
||||
uint32 Image32bpp::Get(int offset) const
|
||||
{
|
||||
int x, y;
|
||||
y = offset / iWidth;
|
||||
x = offset - y * iWidth;
|
||||
assert(x >= 0 && x < iWidth && y >= 0 && y < iHeight);
|
||||
return pData[offset];
|
||||
}
|
||||
|
||||
|
||||
Image8bpp::Image8bpp(int iWidth, int iHeight)
|
||||
{
|
||||
this->iWidth = iWidth;
|
||||
this->iHeight = iHeight;
|
||||
pData = (uint8 *)malloc(iWidth * iHeight);
|
||||
}
|
||||
|
||||
Image8bpp::~Image8bpp()
|
||||
{
|
||||
free(pData);
|
||||
}
|
||||
|
||||
unsigned char Image8bpp::Get(int offset) const
|
||||
{
|
||||
int x, y;
|
||||
y = offset / iWidth;
|
||||
x = offset - y * iWidth;
|
||||
assert(x >= 0 && x < iWidth && y >= 0 && y < iHeight);
|
||||
return pData[offset];
|
||||
}
|
||||
|
||||
static void OpenFile(const std::string &sFilename, png_structp *pngPtr, png_infop *infoPtr, png_infop *endInfo, uint8 ***pRows)
|
||||
{
|
||||
FILE *pFile = fopen(sFilename.c_str(), "rb");
|
||||
if(pFile == NULL)
|
||||
{
|
||||
fprintf(stderr, "PNG file \"%s\" could not be opened.\n", sFilename.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
unsigned char header[4];
|
||||
if(fread(header, 1, 4, pFile) != 4)
|
||||
{
|
||||
fprintf(stderr, "Could not read header of \"%s\".\n", sFilename.c_str());
|
||||
fclose(pFile);
|
||||
exit(1);
|
||||
}
|
||||
bool bIsPng = !png_sig_cmp(header, 0, 4);
|
||||
if(!bIsPng)
|
||||
{
|
||||
fprintf(stderr, "Header of \"%s\" indicates it is not a PNG file.\n", sFilename.c_str());
|
||||
fclose(pFile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
*pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!*pngPtr)
|
||||
{
|
||||
fprintf(stderr, "Could not initialize PNG data.\n");
|
||||
fclose(pFile);
|
||||
exit(1);
|
||||
}
|
||||
*infoPtr = png_create_info_struct(*pngPtr);
|
||||
if(!*infoPtr)
|
||||
{
|
||||
fprintf(stderr, "Could not initialize PNG info data.\n");
|
||||
png_destroy_read_struct(pngPtr, (png_infopp)NULL, (png_infopp)NULL);
|
||||
fclose(pFile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
*endInfo = png_create_info_struct(*pngPtr);
|
||||
if(!*endInfo)
|
||||
{
|
||||
fprintf(stderr, "Could not initialize PNG end data.\n");
|
||||
png_destroy_read_struct(pngPtr, infoPtr, (png_infopp)NULL);
|
||||
fclose(pFile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Setup callback in case of errors. */
|
||||
if(setjmp(png_jmpbuf(*pngPtr))) {
|
||||
fprintf(stderr, "Error detected while reading PNG file.\n");
|
||||
png_destroy_read_struct(pngPtr, infoPtr, endInfo);
|
||||
fclose(pFile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Initialize for file reading. */
|
||||
png_init_io(*pngPtr, pFile);
|
||||
png_set_sig_bytes(*pngPtr, 4);
|
||||
|
||||
png_read_png(*pngPtr, *infoPtr, PNG_TRANSFORM_IDENTITY, NULL);
|
||||
*pRows = png_get_rows(*pngPtr, *infoPtr);
|
||||
fclose(pFile);
|
||||
}
|
||||
|
||||
|
||||
Image32bpp *Load32Bpp(const std::string &sFilename, int line, int left, int width, int top, int height)
|
||||
{
|
||||
png_structp pngPtr;
|
||||
png_infop infoPtr;
|
||||
png_infop endInfo;
|
||||
uint8 **pRows;
|
||||
OpenFile(sFilename, &pngPtr, &infoPtr, &endInfo, &pRows);
|
||||
|
||||
int iWidth = png_get_image_width(pngPtr, infoPtr);
|
||||
int iHeight = png_get_image_height(pngPtr, infoPtr);
|
||||
int iBitDepth = png_get_bit_depth(pngPtr, infoPtr);
|
||||
int iColorType = png_get_color_type(pngPtr, infoPtr);
|
||||
|
||||
if (iWidth < left + width)
|
||||
{
|
||||
fprintf(stderr, "Sprite at line %d: Sprite is not wide enough, require %d columns (%d + %d) while only %d columns are available.\n", line, left + width, left, width, iWidth);
|
||||
exit(1);
|
||||
}
|
||||
if (iHeight < top + height)
|
||||
{
|
||||
fprintf(stderr, "Sprite at line %d: Sprite is not high enough, require %d rows (%d + %d) while only %d rows are available.\n", line, top + height, top, height, iHeight);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (iBitDepth != 8)
|
||||
{
|
||||
fprintf(stderr, "Sprite at line %d: \"%s\" is not an 32bpp file (channels are not 8 bit wide)\n", line, sFilename.c_str());
|
||||
png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
|
||||
exit(1);
|
||||
}
|
||||
if (iColorType != PNG_COLOR_TYPE_RGB_ALPHA)
|
||||
{
|
||||
fprintf(stderr, "Sprite at line %d: \"%s\" is not an RGBA file\n", line, sFilename.c_str());
|
||||
png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Image32bpp *img = new Image32bpp(width, height);
|
||||
uint32 *pData = img->pData;
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
uint8 *pRow = pRows[top + i] + left;
|
||||
for (int j = 0; j < width; j++)
|
||||
{
|
||||
*pData++ = MakeRGBA(pRow[0], pRow[1], pRow[2], pRow[3]);
|
||||
pRow += 4;
|
||||
}
|
||||
}
|
||||
|
||||
png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
|
||||
return img;
|
||||
}
|
||||
|
||||
Image8bpp *Load8Bpp(const std::string &sFilename, int line, int left, int width, int top, int height)
|
||||
{
|
||||
png_structp pngPtr;
|
||||
png_infop infoPtr;
|
||||
png_infop endInfo;
|
||||
uint8 **pRows;
|
||||
OpenFile(sFilename, &pngPtr, &infoPtr, &endInfo, &pRows);
|
||||
|
||||
int iWidth = png_get_image_width(pngPtr, infoPtr);
|
||||
int iHeight = png_get_image_height(pngPtr, infoPtr);
|
||||
int iBitDepth = png_get_bit_depth(pngPtr, infoPtr);
|
||||
int iColorType = png_get_color_type(pngPtr, infoPtr);
|
||||
|
||||
if (iWidth < left + width)
|
||||
{
|
||||
fprintf(stderr, "Sprite at line %d: Sprite is not wide enough, require %d columns (%d + %d) while only %d columns are available.\n", line, left + width, left, width, iWidth);
|
||||
exit(1);
|
||||
}
|
||||
if (iHeight < top + height)
|
||||
{
|
||||
fprintf(stderr, "Sprite at line %d: Sprite is not high enough, require %d rows (%d + %d) while only %d rows are available.\n", line, top + height, top, height, iHeight);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (iBitDepth != 8)
|
||||
{
|
||||
fprintf(stderr, "Sprite at line %d: \"%s\" is not an 8bpp file (the channel is not 8 bit wide\n", line, sFilename.c_str());
|
||||
png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
|
||||
exit(1);
|
||||
}
|
||||
if (iColorType != PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
fprintf(stderr, "Sprite at line %d: \"%s\" is not a palleted image file\n", line, sFilename.c_str());
|
||||
png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Image8bpp *img = new Image8bpp(width, height);
|
||||
uint8 *pData = img->pData;
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
int y = top + i;
|
||||
for (int j = 0; j < width; j++)
|
||||
{
|
||||
int x = left + j;
|
||||
uint8 v = pRows[y][x];
|
||||
*pData = v;
|
||||
pData++;
|
||||
}
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
// vim: et sw=4 ts=4 sts=4
|
65
SpriteEncoder/image.h
Normal file
65
SpriteEncoder/image.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright (c) 2013 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef IMAGE_H
|
||||
#define IMAGE_H
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
class Image32bpp
|
||||
{
|
||||
public:
|
||||
Image32bpp(int iWidth, int iHeight);
|
||||
~Image32bpp();
|
||||
|
||||
uint32 Get(int offset) const;
|
||||
|
||||
int iWidth;
|
||||
int iHeight;
|
||||
uint32 *pData;
|
||||
};
|
||||
|
||||
class Image8bpp
|
||||
{
|
||||
public:
|
||||
Image8bpp(int iWidth, int iHeight);
|
||||
~Image8bpp();
|
||||
|
||||
unsigned char Get(int offset) const;
|
||||
|
||||
int iWidth;
|
||||
int iHeight;
|
||||
uint8 *pData;
|
||||
};
|
||||
|
||||
uint8 GetR(uint32 rgba);
|
||||
uint8 GetG(uint32 rgba);
|
||||
uint8 GetB(uint32 rgba);
|
||||
uint8 GetA(uint32 rgba);
|
||||
|
||||
Image32bpp *Load32Bpp(const std::string &sFilename, int line, int left, int width, int top, int height);
|
||||
Image8bpp *Load8Bpp(const std::string &sFilename, int line, int left, int width, int top, int height);
|
||||
|
||||
#endif
|
||||
|
||||
// vim: et sw=4 ts=4 sts=4
|
39
SpriteEncoder/mk
Executable file
39
SpriteEncoder/mk
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2013 Albert "Alberth" Hofkamp
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
# of the Software, and to permit persons to whom the Software is furnished to do
|
||||
# so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
set -e -u -x
|
||||
|
||||
CCFLAGS="-Wall -g"
|
||||
FLEXFLAGS=
|
||||
|
||||
bison --defines=tokens.h --output=parser.cpp parser.y
|
||||
flex $FLEXFLAGS --outfile=scanner.cpp scanner.l
|
||||
|
||||
g++ $CCFLAGS -c -o parser.o parser.cpp
|
||||
g++ $CCFLAGS -c -o scanner.o scanner.cpp
|
||||
g++ $CCFLAGS -c -o encode.o encode.cpp
|
||||
g++ $CCFLAGS -c -o ast.o ast.cpp
|
||||
g++ $CCFLAGS -c -o image.o image.cpp
|
||||
g++ $CCFLAGS -c -o output.o output.cpp
|
||||
|
||||
g++ $CCFLAGS -o encoder parser.o scanner.o encode.o ast.o image.o output.o -lpng
|
||||
|
141
SpriteEncoder/output.cpp
Normal file
141
SpriteEncoder/output.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
Copyright (c) 2013 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include "output.h"
|
||||
|
||||
DataBlock::DataBlock()
|
||||
{
|
||||
m_iUsed = 0;
|
||||
m_pNext = NULL;
|
||||
}
|
||||
|
||||
bool DataBlock::Full()
|
||||
{
|
||||
return m_iUsed == BUF_SIZE;
|
||||
}
|
||||
|
||||
void DataBlock::Add(unsigned char byte)
|
||||
{
|
||||
assert(m_iUsed < BUF_SIZE);
|
||||
buffer[m_iUsed++] = byte;
|
||||
}
|
||||
|
||||
void DataBlock::Write(FILE *handle)
|
||||
{
|
||||
if (fwrite(buffer, 1, m_iUsed, handle) != (size_t)m_iUsed)
|
||||
{
|
||||
fprintf(stderr, "Writing output failed!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Output::Output()
|
||||
{
|
||||
m_pFirst = NULL;
|
||||
m_pLast = NULL;
|
||||
}
|
||||
|
||||
Output::~Output()
|
||||
{
|
||||
DataBlock *pBlk = m_pFirst;
|
||||
while (pBlk != NULL)
|
||||
{
|
||||
DataBlock *pBlk2 = pBlk->m_pNext;
|
||||
delete pBlk;
|
||||
pBlk = pBlk2;
|
||||
}
|
||||
}
|
||||
|
||||
void Output::Uint16(int iValue)
|
||||
{
|
||||
Uint8(iValue & 0xFF);
|
||||
Uint8((iValue >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
void Output::Uint8(unsigned char byte)
|
||||
{
|
||||
if (m_pLast == NULL || m_pLast->Full())
|
||||
{
|
||||
DataBlock *pBlk = new DataBlock();
|
||||
if (m_pLast == NULL)
|
||||
{
|
||||
m_pFirst = pBlk;
|
||||
m_pLast = pBlk;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pLast->m_pNext = pBlk;
|
||||
m_pLast = pBlk;
|
||||
}
|
||||
}
|
||||
m_pLast->Add(byte);
|
||||
}
|
||||
|
||||
int Output::Reserve(int iSize)
|
||||
{
|
||||
// Count current size.
|
||||
int iLength = 0;
|
||||
DataBlock *pBlk = m_pFirst;
|
||||
while (pBlk != NULL)
|
||||
{
|
||||
iLength += pBlk->m_iUsed;
|
||||
pBlk = pBlk->m_pNext;
|
||||
}
|
||||
|
||||
// Add 'size' bytes as reserved space.
|
||||
for (int i = 0; i < iSize; i++)
|
||||
{
|
||||
Uint8(0);
|
||||
}
|
||||
return iLength;
|
||||
}
|
||||
|
||||
void Output::Write(int iAddress, unsigned char iValue)
|
||||
{
|
||||
int iOffset = 0;
|
||||
DataBlock *pBlk = m_pFirst;
|
||||
while (pBlk != NULL && iOffset + pBlk->m_iUsed < iAddress)
|
||||
{
|
||||
iOffset += pBlk->m_iUsed;
|
||||
pBlk = pBlk->m_pNext;
|
||||
}
|
||||
assert(pBlk != NULL);
|
||||
iAddress -= iOffset;
|
||||
assert(iAddress >= 0 && iAddress < BUF_SIZE);
|
||||
pBlk->buffer[iAddress] = iValue;
|
||||
}
|
||||
|
||||
void Output::Write(const char *fname)
|
||||
{
|
||||
FILE *handle = fopen(fname, "wb");
|
||||
DataBlock *pBlk = m_pFirst;
|
||||
while (pBlk != NULL)
|
||||
{
|
||||
pBlk->Write(handle);
|
||||
pBlk = pBlk->m_pNext;
|
||||
}
|
||||
fclose(handle);
|
||||
}
|
||||
|
||||
// vim: et sw=4 ts=4 sts=4
|
61
SpriteEncoder/output.h
Normal file
61
SpriteEncoder/output.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright (c) 2013 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef OUTPUT_H
|
||||
#define OUTPUT_H
|
||||
|
||||
#define BUF_SIZE 100000
|
||||
|
||||
class DataBlock
|
||||
{
|
||||
public:
|
||||
DataBlock();
|
||||
|
||||
bool Full();
|
||||
void Add(unsigned char byte);
|
||||
void Write(FILE *handle);
|
||||
|
||||
unsigned char buffer[BUF_SIZE];
|
||||
int m_iUsed;
|
||||
DataBlock *m_pNext;
|
||||
};
|
||||
|
||||
class Output
|
||||
{
|
||||
public:
|
||||
Output();
|
||||
~Output();
|
||||
|
||||
void Write(const char *fname);
|
||||
|
||||
void Uint8(unsigned char byte);
|
||||
void Uint16(int val);
|
||||
void Write(int address, unsigned char byte);
|
||||
int Reserve(int size);
|
||||
|
||||
DataBlock *m_pFirst;
|
||||
DataBlock *m_pLast;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// vim: et sw=4 ts=4 sts=4
|
79
SpriteEncoder/parser.y
Normal file
79
SpriteEncoder/parser.y
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright (c) 2013 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
%{
|
||||
#include <list>
|
||||
#include "ast.h"
|
||||
#include <cstdio>
|
||||
|
||||
std::set<Sprite> g_oSprites;
|
||||
%}
|
||||
|
||||
|
||||
%token CURLY_OPEN CURLY_CLOSE EQUAL SEMICOL
|
||||
%token LEFTKW TOPKW WIDTHKW HEIGHTKW BASEIMGKW RECOLOURKW SPRITEKW LAYERKW
|
||||
|
||||
%token<number> NUMBER
|
||||
%token<text> STRING
|
||||
|
||||
%type<m_pSprite> SpriteSettings Sprite
|
||||
|
||||
%start Program
|
||||
|
||||
|
||||
%%
|
||||
|
||||
Program : /* empty */
|
||||
{ g_oSprites.clear(); }
|
||||
| Program Sprite
|
||||
{ g_oSprites.insert(*$2); delete $2; }
|
||||
;
|
||||
|
||||
Sprite : SPRITEKW NUMBER CURLY_OPEN SpriteSettings CURLY_CLOSE
|
||||
{ $$ = $4; $$->m_iSprite = $2; }
|
||||
;
|
||||
|
||||
SpriteSettings : /* empty */
|
||||
{ $$ = new Sprite; }
|
||||
| SpriteSettings LEFTKW EQUAL NUMBER SEMICOL
|
||||
{ $$ = $1; $$->m_iLeft = $4; }
|
||||
| SpriteSettings TOPKW EQUAL NUMBER SEMICOL
|
||||
{ $$ = $1; $$->m_iTop = $4; }
|
||||
| SpriteSettings WIDTHKW EQUAL NUMBER SEMICOL
|
||||
{ $$ = $1; $$->m_iWidth = $4; }
|
||||
| SpriteSettings HEIGHTKW EQUAL NUMBER SEMICOL
|
||||
{ $$ = $1; $$->m_iHeight = $4; }
|
||||
| SpriteSettings BASEIMGKW EQUAL STRING SEMICOL
|
||||
{ $$ = $1; $$->m_sBaseImage = $4; }
|
||||
| SpriteSettings RECOLOURKW EQUAL STRING SEMICOL
|
||||
{ $$ = $1; $$->SetRecolour($4); }
|
||||
| SpriteSettings LAYERKW NUMBER EQUAL NUMBER SEMICOL
|
||||
{ $$ = $1; $$->m_aNumber[($3) & 0xFF] = ($5) & 0xFF; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void yyerror(const char *msg)
|
||||
{
|
||||
fprintf(stderr, "Parse error at line %d: %s\n", yylval.line, msg);
|
||||
exit(1);
|
||||
}
|
104
SpriteEncoder/scanner.l
Normal file
104
SpriteEncoder/scanner.l
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
Copyright (c) 2013 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
%{
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include "ast.h"
|
||||
#include "tokens.h"
|
||||
|
||||
int line = 1;
|
||||
std::string filename;
|
||||
%}
|
||||
|
||||
%x IN_STRING
|
||||
%x IN_COMMENT
|
||||
|
||||
%option noyywrap
|
||||
|
||||
%%
|
||||
|
||||
"{" { yylval.line = line; return CURLY_OPEN; }
|
||||
"}" { yylval.line = line; return CURLY_CLOSE; }
|
||||
"=" { yylval.line = line; return EQUAL; }
|
||||
";" { yylval.line = line; return SEMICOL; }
|
||||
|
||||
"sprite" { yylval.line = line; return SPRITEKW; }
|
||||
"left" { yylval.line = line; return LEFTKW; }
|
||||
"top" { yylval.line = line; return TOPKW; }
|
||||
"width" { yylval.line = line; return WIDTHKW; }
|
||||
"height" { yylval.line = line; return HEIGHTKW; }
|
||||
"base" { yylval.line = line; return BASEIMGKW; }
|
||||
"recolour" { yylval.line = line; return RECOLOURKW; }
|
||||
"layer" { yylval.line = line; return LAYERKW; }
|
||||
|
||||
"0" { yylval.line = line;
|
||||
yylval.number = 0;
|
||||
return NUMBER; }
|
||||
|
||||
[1-9][0-9]* { yylval.line = line;
|
||||
yylval.number = atoi(yytext);
|
||||
return NUMBER; }
|
||||
|
||||
\" { yylval.text = "";
|
||||
yylval.line = line;
|
||||
BEGIN(IN_STRING); }
|
||||
|
||||
<IN_STRING>\" { BEGIN(INITIAL);
|
||||
return STRING; }
|
||||
|
||||
<IN_STRING>. { yylval.text += yytext; }
|
||||
|
||||
"//" { BEGIN(IN_COMMENT); }
|
||||
|
||||
<IN_COMMENT>\n { BEGIN(INITIAL);
|
||||
line++; }
|
||||
|
||||
<IN_COMMENT>. { }
|
||||
|
||||
" " { }
|
||||
|
||||
\t { }
|
||||
|
||||
\n { line++; }
|
||||
|
||||
. { fprintf(stderr, "Unrecognized character encountered at line %d\n", line);
|
||||
exit(1); }
|
||||
|
||||
<IN_COMMENT><<EOF>> { BEGIN(INITIAL); }
|
||||
<IN_STRING><<EOF>> { BEGIN(INITIAL); }
|
||||
|
||||
%%
|
||||
|
||||
void SetupScanner(const char *fname, FILE *new_file)
|
||||
{
|
||||
if (new_file == NULL || fname == NULL)
|
||||
{
|
||||
new_file = stdin;
|
||||
}
|
||||
yyrestart(new_file);
|
||||
BEGIN(INITIAL);
|
||||
|
||||
filename = (fname == NULL) ? "<stdin>" : fname;
|
||||
line = 1;
|
||||
}
|
||||
|
Reference in New Issue
Block a user