mirror of
https://github.com/ZDoom/Raze.git
synced 2024-12-15 15:11:41 +00:00
aa04307ad1
git-svn-id: https://svn.eduke32.com/eduke32@6074 1a8010ca-5511-0410-912e-c29ae57300e0
1438 lines
40 KiB
C++
1438 lines
40 KiB
C++
/**
|
|
* BUILD ART file editing tool
|
|
* @author Jonathon Fowler
|
|
* @license Artistic License 2.0 (http://www.perlfoundation.org/artistic_license_2_0)
|
|
*/
|
|
// Bstring and C++ STL --> C conversion by Hendricks266
|
|
|
|
#include "compat.h"
|
|
|
|
////////// Bstring //////////
|
|
|
|
class Bstring {
|
|
public:
|
|
Bstring(void);
|
|
Bstring(const char*);
|
|
Bstring(const Bstring&);
|
|
~Bstring(void);
|
|
|
|
operator const char*() const;
|
|
const char* operator()(void) const;
|
|
char& operator[](int);
|
|
|
|
Bstring& operator=(const char*);
|
|
Bstring& operator=(const Bstring&);
|
|
|
|
Bstring& operator+=(const char*);
|
|
Bstring& operator+=(const Bstring&);
|
|
|
|
bool operator==(const Bstring&) const;
|
|
bool operator!=(const Bstring&) const;
|
|
bool operator< (const Bstring&) const;
|
|
bool operator<=(const Bstring&) const;
|
|
bool operator> (const Bstring&) const;
|
|
bool operator>=(const Bstring&) const;
|
|
|
|
bool operator==(const char*) const;
|
|
bool operator!=(const char*) const;
|
|
bool operator< (const char*) const;
|
|
bool operator<=(const char*) const;
|
|
bool operator> (const char*) const;
|
|
bool operator>=(const char*) const;
|
|
|
|
int compare(const char*) const;
|
|
int compare(const Bstring&) const;
|
|
|
|
unsigned length(void) const;
|
|
|
|
void clear(void);
|
|
|
|
protected:
|
|
char* data;
|
|
};
|
|
|
|
Bstring::Bstring(void) { data = NULL; }
|
|
Bstring::Bstring(const Bstring &value) {
|
|
if (&value != this)
|
|
(*this)=value();
|
|
}
|
|
Bstring::Bstring(const char *str) {
|
|
data = NULL;
|
|
(*this)=str;
|
|
}
|
|
|
|
Bstring::~Bstring(void) { clear(); }
|
|
|
|
Bstring::operator const char*() const { return data; }
|
|
const char* Bstring::operator()(void) const { return data; }
|
|
char& Bstring::operator[](int index) { return data[index]; }
|
|
|
|
Bstring& Bstring::operator=(const Bstring &value)
|
|
{
|
|
if (&value != this)
|
|
(*this)=value();
|
|
|
|
return *this;
|
|
}
|
|
Bstring& Bstring::operator=(const char *str)
|
|
{
|
|
clear();
|
|
data = Bstrdup(str);
|
|
|
|
return *this;
|
|
}
|
|
|
|
Bstring& Bstring::operator+=(const Bstring &value)
|
|
{
|
|
(*this)+=value();
|
|
|
|
return *this;
|
|
}
|
|
Bstring& Bstring::operator+=(const char *str)
|
|
{
|
|
data = (char*) Brealloc(data, (Bstrlen(data) + Bstrlen(str) + 1) * sizeof(char));
|
|
Bstrcat(data, str);
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool Bstring::operator==(const Bstring &value) const { return Bstrcmp(data, value()) == 0; }
|
|
bool Bstring::operator!=(const Bstring &value) const { return Bstrcmp(data, value()) != 0; }
|
|
bool Bstring::operator< (const Bstring &value) const { return Bstrcmp(data, value()) < 0; }
|
|
bool Bstring::operator<=(const Bstring &value) const { return Bstrcmp(data, value()) <= 0; }
|
|
bool Bstring::operator> (const Bstring &value) const { return Bstrcmp(data, value()) > 0; }
|
|
bool Bstring::operator>=(const Bstring &value) const { return Bstrcmp(data, value()) >= 0; }
|
|
|
|
bool Bstring::operator==(const char *str) const { return Bstrcmp(data, str) == 0; }
|
|
bool Bstring::operator!=(const char *str) const { return Bstrcmp(data, str) != 0; }
|
|
bool Bstring::operator< (const char *str) const { return Bstrcmp(data, str) < 0; }
|
|
bool Bstring::operator<=(const char *str) const { return Bstrcmp(data, str) <= 0; }
|
|
bool Bstring::operator> (const char *str) const { return Bstrcmp(data, str) > 0; }
|
|
bool Bstring::operator>=(const char *str) const { return Bstrcmp(data, str) >= 0; }
|
|
|
|
int Bstring::compare(const Bstring &value) const { return Bstrcmp(data,value()); }
|
|
int Bstring::compare(const char *str) const { return Bstrcmp(data,str); }
|
|
|
|
unsigned Bstring::length(void) const { return Bstrlen(data); }
|
|
|
|
void Bstring::clear(void)
|
|
{
|
|
DO_FREE_AND_NULL(data);
|
|
}
|
|
|
|
////////// arttool //////////
|
|
|
|
void usage()
|
|
{
|
|
Bprintf("BUILD ART file editing tool\n");
|
|
Bprintf("Copyright (C) 2008 Jonathon Fowler <jf@jonof.id.au>\n");
|
|
Bprintf("Released under the Artistic License 2.0\n");
|
|
Bprintf("\n");
|
|
Bprintf(" arttool info [tilenum]\n");
|
|
Bprintf(" Display information about a specific tile, or all if none is specified\n");
|
|
Bprintf("\n");
|
|
Bprintf(" arttool create [options]\n");
|
|
Bprintf(" -f <filenum> Selects which numbered ART file to create (default 0)\n");
|
|
Bprintf(" -o <offset> Specifies the first tile in the file (default 0)\n");
|
|
Bprintf(" -n <ntiles> The number of tiles for the art file (default 256)\n");
|
|
Bprintf(" Creates an empty ART file named 'tilesXXX.art'\n");
|
|
Bprintf("\n");
|
|
Bprintf(" arttool addtile [options] <tilenum> <filename>\n");
|
|
Bprintf(" -x <pixels> X-centre\n");
|
|
Bprintf(" -y <pixels> Y-centre\n");
|
|
Bprintf(" -ann <frames> Animation frame span\n");
|
|
Bprintf(" -ant <type> Animation type (0=none, 1=oscillate, 2=forward, 3=reverse)\n");
|
|
Bprintf(" -ans <speed> Animation speed\n");
|
|
Bprintf(" Adds a tile to the 'tilesXXX.art' set from a TGA or PCX source\n");
|
|
Bprintf("\n");
|
|
Bprintf(" arttool rmtile <tilenum>\n");
|
|
Bprintf(" Removes a tile from the 'tilesXXX.art' set\n");
|
|
Bprintf("\n");
|
|
Bprintf(" arttool exporttile <tilenum>\n");
|
|
Bprintf(" Exports a tile from the 'tilesXXX.art' set to a PCX file\n");
|
|
Bprintf("\n");
|
|
Bprintf(" arttool tileprop [options] <tilenum>\n");
|
|
Bprintf(" -x <pixels> X-centre\n");
|
|
Bprintf(" -y <pixels> Y-centre\n");
|
|
Bprintf(" -ann <frames> Animation frame span, may be negative\n");
|
|
Bprintf(" -ant <type> Animation type (0=none, 1=oscillate, 2=forward, 3=reverse)\n");
|
|
Bprintf(" -ans <speed> Animation speed\n");
|
|
Bprintf(" Changes tile properties\n");
|
|
Bprintf("\n");
|
|
}
|
|
|
|
class ARTFile {
|
|
private:
|
|
Bstring filename_;
|
|
int localtilestart_;
|
|
int localtileend_;
|
|
short * tilesizx_;
|
|
short * tilesizy_;
|
|
int * picanm_;
|
|
int datastartoffset_;
|
|
|
|
// for removing or replacing tile data
|
|
int markprelength_, markskiplength_, markpostlength_;
|
|
char * insert_;
|
|
int insertlen_;
|
|
|
|
void writeShort(BFILE *ofs, short s)
|
|
{
|
|
Bassert(ofs);
|
|
char d[2] = { static_cast<char>(s&255), static_cast<char>((s>>8)&255) };
|
|
Bfwrite(d,1,2,ofs); // 2 == sizeof(d)
|
|
}
|
|
|
|
void writeLong(BFILE *ofs, int l)
|
|
{
|
|
Bassert(ofs);
|
|
char d[4] = { static_cast<char>(l&255), static_cast<char>((l>>8)&255), static_cast<char>((l>>16)&255), static_cast<char>((l>>24)&255) };
|
|
Bfwrite(d,1,4,ofs); // 4 == sizeof(d)
|
|
}
|
|
|
|
short readShort(BFILE *ifs)
|
|
{
|
|
Bassert(ifs);
|
|
unsigned char d[2];
|
|
unsigned short s;
|
|
Bfread(d,1,2,ifs); // 2 == sizeof(d)
|
|
s = (unsigned short)d[0];
|
|
s |= (unsigned short)d[1] << 8;
|
|
return (short)s;
|
|
}
|
|
|
|
int readLong(BFILE *ifs)
|
|
{
|
|
Bassert(ifs);
|
|
unsigned char d[4];
|
|
unsigned int l;
|
|
Bfread(d,1,4,ifs); // 4 == sizeof(d)
|
|
l = (unsigned int)d[0];
|
|
l |= (unsigned int)d[1] << 8;
|
|
l |= (unsigned int)d[2] << 16;
|
|
l |= (unsigned int)d[3] << 24;
|
|
return (int)l;
|
|
}
|
|
|
|
void dispose()
|
|
{
|
|
if (tilesizx_) delete [] tilesizx_;
|
|
if (tilesizy_) delete [] tilesizy_;
|
|
if (picanm_) delete [] picanm_;
|
|
if (insert_) delete [] insert_;
|
|
|
|
insert_ = 0;
|
|
insertlen_ = 0;
|
|
}
|
|
|
|
void load()
|
|
{
|
|
BFILE *infile = Bfopen(filename_(),"rb");
|
|
int i, ntiles;
|
|
|
|
if (infile != NULL && readLong(infile) == 1)
|
|
{
|
|
readLong(infile); // skip the numtiles
|
|
dispose();
|
|
|
|
localtilestart_ = readLong(infile);
|
|
localtileend_ = readLong(infile);
|
|
ntiles = localtileend_ - localtilestart_ + 1;
|
|
|
|
tilesizx_ = new short[ntiles];
|
|
tilesizy_ = new short[ntiles];
|
|
picanm_ = new int[ntiles];
|
|
|
|
for (i = 0; i < ntiles; ++i) {
|
|
tilesizx_[i] = readShort(infile);
|
|
}
|
|
for (i = 0; i < ntiles; ++i) {
|
|
tilesizy_[i] = readShort(infile);
|
|
}
|
|
for (i = 0; i < ntiles; ++i) {
|
|
picanm_[i] = readLong(infile);
|
|
}
|
|
|
|
datastartoffset_ = Bftell(infile);
|
|
|
|
Bfclose(infile);
|
|
}
|
|
}
|
|
|
|
public:
|
|
ARTFile(Bstring const & filename)
|
|
: filename_(filename), localtilestart_(0), localtileend_(-1),
|
|
tilesizx_(0), tilesizy_(0), picanm_(0), datastartoffset_(0),
|
|
markprelength_(0), markskiplength_(0), markpostlength_(0),
|
|
insert_(0), insertlen_(0)
|
|
{
|
|
load();
|
|
}
|
|
|
|
~ARTFile()
|
|
{
|
|
dispose();
|
|
}
|
|
|
|
/**
|
|
* Sets up for an empty file
|
|
* @param start the starting tile
|
|
* @param ntiles the number of tiles total
|
|
*/
|
|
void init(int start, int ntiles)
|
|
{
|
|
dispose();
|
|
|
|
localtilestart_ = start;
|
|
localtileend_ = start + ntiles - 1;
|
|
tilesizx_ = new short[ntiles];
|
|
tilesizy_ = new short[ntiles];
|
|
picanm_ = new int[ntiles];
|
|
datastartoffset_ = 0;
|
|
|
|
memset(tilesizx_, 0, sizeof(short)*ntiles);
|
|
memset(tilesizy_, 0, sizeof(short)*ntiles);
|
|
memset(picanm_, 0, sizeof(int)*ntiles);
|
|
|
|
markprelength_ = 0;
|
|
markskiplength_ = 0;
|
|
markpostlength_ = 0;
|
|
insert_ = 0;
|
|
insertlen_ = 0;
|
|
}
|
|
|
|
/**
|
|
* Returns the number of tiles in the loaded file
|
|
* @return 0 means no file loaded
|
|
*/
|
|
int getNumTiles()
|
|
{
|
|
return (localtileend_ - localtilestart_ + 1);
|
|
}
|
|
|
|
int getFirstTile()
|
|
{
|
|
return localtilestart_;
|
|
}
|
|
|
|
int getLastTile()
|
|
{
|
|
return localtileend_;
|
|
}
|
|
|
|
void removeTile(int tile)
|
|
{
|
|
int i, end;
|
|
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return;
|
|
}
|
|
|
|
end = localtileend_ - tile;
|
|
tile -= localtilestart_;
|
|
|
|
markprelength_ = markpostlength_ = 0;
|
|
|
|
for (i = 0; i < tile; ++i) {
|
|
markprelength_ += tilesizx_[i] * tilesizy_[i];
|
|
}
|
|
markskiplength_ = tilesizx_[tile] * tilesizy_[tile];
|
|
for (i = tile + 1; i <= end; ++i) {
|
|
markpostlength_ += tilesizx_[i] * tilesizy_[i];
|
|
}
|
|
|
|
tilesizx_[tile] = tilesizy_[tile] = 0;
|
|
}
|
|
|
|
void replaceTile(int tile, char * replace, int replacelen)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return;
|
|
}
|
|
|
|
removeTile(tile);
|
|
|
|
insert_ = replace;
|
|
insertlen_ = replacelen;
|
|
}
|
|
|
|
void getTileSize(int tile, int& x, int &y)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
x = y = -1;
|
|
return;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
x = tilesizx_[tile];
|
|
y = tilesizy_[tile];
|
|
}
|
|
|
|
void setTileSize(int tile, int x, int y)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
tilesizx_[tile] = x;
|
|
tilesizy_[tile] = y;
|
|
}
|
|
|
|
void setXOfs(int tile, int x)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
picanm_[tile] &= ~(255<<8);
|
|
picanm_[tile] |= ((int)((unsigned char)x) << 8);
|
|
}
|
|
|
|
void setYOfs(int tile, int y)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
picanm_[tile] &= ~(255<<16);
|
|
picanm_[tile] |= ((int)((unsigned char)y) << 16);
|
|
}
|
|
|
|
int getXOfs(int tile)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return 0;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
return (picanm_[tile] >> 8) & 255;
|
|
}
|
|
|
|
int getYOfs(int tile)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return 0;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
return (picanm_[tile] >> 16) & 255;
|
|
}
|
|
|
|
void setAnimType(int tile, int type)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
picanm_[tile] &= ~(3<<6);
|
|
picanm_[tile] |= ((int)(type&3) << 6);
|
|
}
|
|
|
|
int getAnimType(int tile)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return 0;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
return (picanm_[tile] >> 6) & 3;
|
|
}
|
|
|
|
void setAnimFrames(int tile, int frames)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
picanm_[tile] &= ~(63);
|
|
picanm_[tile] |= ((int)(frames&63));
|
|
}
|
|
|
|
int getAnimFrames(int tile)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return 0;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
return picanm_[tile] & 63;
|
|
}
|
|
|
|
void setAnimSpeed(int tile, int speed)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
picanm_[tile] &= ~(15<<24);
|
|
picanm_[tile] |= ((int)(speed&15) << 24);
|
|
}
|
|
|
|
int getAnimSpeed(int tile)
|
|
{
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return 0;
|
|
}
|
|
|
|
tile -= localtilestart_;
|
|
return (picanm_[tile] >> 24) & 15;
|
|
}
|
|
|
|
int write()
|
|
{
|
|
BFILE *outfile = tmpfile();
|
|
|
|
BFILE *infile = Bfopen(filename_(),"rb");
|
|
int tmp, left;
|
|
static const unsigned int blksize = 4096;
|
|
char blk[blksize];
|
|
|
|
if (infile == NULL && (markprelength_ > 0 || markskiplength_ > 0 || markpostlength_ > 0)) {
|
|
return -1; // couldn't open the original file for copying
|
|
} else if (infile != NULL) {
|
|
// skip to the start of the existing ART data
|
|
int ofs = 4+4+4+4+(2+2+4)*(localtileend_-localtilestart_+1);
|
|
Bfseek(infile, ofs, SEEK_CUR);
|
|
}
|
|
|
|
// write a header to the temporary file
|
|
writeLong(outfile, 1); // version
|
|
writeLong(outfile, 0); // numtiles
|
|
writeLong(outfile, localtilestart_);
|
|
writeLong(outfile, localtileend_);
|
|
for (int i = 0; i < localtileend_ - localtilestart_ + 1; ++i) {
|
|
writeShort(outfile, tilesizx_[i]);
|
|
}
|
|
for (int i = 0; i < localtileend_ - localtilestart_ + 1; ++i) {
|
|
writeShort(outfile, tilesizy_[i]);
|
|
}
|
|
for (int i = 0; i < localtileend_ - localtilestart_ + 1; ++i) {
|
|
writeLong(outfile, picanm_[i]);
|
|
}
|
|
|
|
// copy the existing leading tile data to be kept
|
|
left = markprelength_;
|
|
while (left > 0) {
|
|
tmp = left;
|
|
if ((unsigned int)tmp > blksize) {
|
|
tmp = blksize;
|
|
}
|
|
Bfread(blk, 1, tmp, infile);
|
|
Bfwrite(blk, 1, tmp, outfile);
|
|
left -= tmp;
|
|
}
|
|
|
|
// insert the replacement data
|
|
if (insertlen_ > 0) {
|
|
Bfwrite(insert_, 1, insertlen_, outfile);
|
|
}
|
|
|
|
if (markskiplength_ > 0) {
|
|
Bfseek(infile, markskiplength_, SEEK_CUR);
|
|
}
|
|
|
|
// copy the existing trailing tile data to be kept
|
|
left = markpostlength_;
|
|
while (left > 0) {
|
|
tmp = left;
|
|
if ((unsigned int)tmp > blksize) {
|
|
tmp = blksize;
|
|
}
|
|
Bfread(blk, 1, tmp, infile);
|
|
Bfwrite(blk, 1, tmp, outfile);
|
|
left -= tmp;
|
|
}
|
|
|
|
// clean up
|
|
const long int tempsize = Bftell(outfile);
|
|
Brewind(outfile);
|
|
|
|
Bfclose(infile);
|
|
|
|
infile = Bfopen(filename_(),"wb");
|
|
|
|
char * buffer = (char*)Bmalloc(tempsize * sizeof(char));
|
|
|
|
Bfread(buffer, 1, tempsize, outfile);
|
|
Bfwrite(buffer, 1, tempsize, infile);
|
|
|
|
Bfclose(infile);
|
|
Bfclose(outfile);
|
|
|
|
return 0;
|
|
}
|
|
|
|
char * readTile(int tile, int& bytes)
|
|
{
|
|
bytes = -1;
|
|
|
|
if (tile < localtilestart_ || tile > localtileend_) {
|
|
return 0;
|
|
}
|
|
tile -= localtilestart_;
|
|
|
|
if (tilesizx_[tile] == 0 || tilesizy_[tile] == 0) {
|
|
bytes = 0;
|
|
return 0;
|
|
}
|
|
|
|
BFILE *infile = Bfopen(filename_(),"rb");
|
|
if (infile == NULL) {
|
|
return 0;
|
|
} else {
|
|
// skip to the start of the existing ART data
|
|
Bfseek(infile, datastartoffset_, SEEK_SET);
|
|
}
|
|
|
|
bytes = tilesizx_[tile] * tilesizy_[tile];
|
|
char * data = new char[bytes];
|
|
|
|
for (int i = 0; i < tile; i++) {
|
|
Bfseek(infile, tilesizx_[i] * tilesizy_[i], SEEK_CUR);
|
|
}
|
|
if (Bfread(data, bytes, 1, infile) != 1) {
|
|
delete [] data;
|
|
data = 0;
|
|
}
|
|
|
|
Bfclose(infile);
|
|
|
|
return data;
|
|
}
|
|
};
|
|
|
|
|
|
class PCX {
|
|
private:
|
|
static int writebyte(unsigned char colour, unsigned char count, BFILE *ofs)
|
|
{
|
|
if (!count) return 0;
|
|
if (count == 1 && (colour & 0xc0) != 0xc0) {
|
|
Bfputc(colour, ofs);
|
|
return 1;
|
|
} else {
|
|
Bfputc(0xc0 | count, ofs);
|
|
Bfputc(colour, ofs);
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
static void writeline(unsigned char *buf, int bytes, int step, BFILE *ofs)
|
|
{
|
|
unsigned char ths, last;
|
|
int srcIndex;
|
|
unsigned char runCount;
|
|
|
|
runCount = 1;
|
|
last = *buf;
|
|
|
|
for (srcIndex=1; srcIndex<bytes; srcIndex++) {
|
|
buf += step;
|
|
ths = *buf;
|
|
if (ths == last) {
|
|
runCount++;
|
|
if (runCount == 63) {
|
|
writebyte(last, runCount, ofs);
|
|
runCount = 0;
|
|
}
|
|
} else {
|
|
if (runCount)
|
|
writebyte(last, runCount, ofs);
|
|
|
|
last = ths;
|
|
runCount = 1;
|
|
}
|
|
}
|
|
|
|
if (runCount) writebyte(last, runCount, ofs);
|
|
if (bytes&1) writebyte(0, 1, ofs);
|
|
}
|
|
|
|
public:
|
|
/**
|
|
* Decodes a PCX file to BUILD's column-major pixel order
|
|
* @param data the raw file data
|
|
* @param datalen the length of the raw file data
|
|
* @param imgdata receives a pointer to the decoded image data
|
|
* @param imgdataw receives the decoded image width
|
|
* @param imgdatah receives the decoded image height
|
|
* @return 0 on success, 1 if the format is invalid
|
|
*/
|
|
static int decode(unsigned char * data, int datalen, char ** imgdata, int& imgdataw, int& imgdatah)
|
|
{
|
|
if (datalen < 128 ||
|
|
data[0] != 10 ||
|
|
data[1] != 5 ||
|
|
data[2] != 1 ||
|
|
data[3] != 8 ||
|
|
data[64] != 0 ||
|
|
data[65] != 1) {
|
|
return 1;
|
|
}
|
|
|
|
int bpl = data[66] + ((int)data[67] << 8);
|
|
int x, y, repeat, colour;
|
|
unsigned char *wptr;
|
|
int roff;
|
|
|
|
imgdataw = (data[8] + ((int)data[9] << 8)) - (data[4] + ((int)data[5] << 8)) + 1;
|
|
imgdatah = (data[10] + ((int)data[11] << 8)) - (data[6] + ((int)data[7] << 8)) + 1;
|
|
|
|
*imgdata = new char [imgdataw * imgdatah];
|
|
|
|
roff = 128;
|
|
for (y = 0; y < imgdatah; y++) {
|
|
wptr = (unsigned char *) (*imgdata + y);
|
|
x = 0;
|
|
do {
|
|
if (EDUKE32_PREDICT_FALSE(roff >= datalen))
|
|
return 1;
|
|
repeat = *(data + roff++);
|
|
|
|
if ((repeat & 192) == 192) {
|
|
if (EDUKE32_PREDICT_FALSE(roff >= datalen))
|
|
return 1;
|
|
colour = *(data + roff++);
|
|
repeat = repeat & 63;
|
|
} else {
|
|
colour = repeat;
|
|
repeat = 1;
|
|
}
|
|
|
|
for (; repeat > 0; repeat--, x++) {
|
|
if (x < imgdataw) {
|
|
*wptr = (unsigned char) colour;
|
|
wptr += imgdatah; // next column
|
|
}
|
|
}
|
|
} while (x < bpl);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Writes a PCX file from data in BUILD's column-major pixel order
|
|
* @param ofs the output file stream
|
|
* @param imgdata a pointer to the image data
|
|
* @param imgdataw the image width
|
|
* @param imgdatah the image height
|
|
* @param palette the image palette, 256*3 bytes
|
|
* @return 0 on success
|
|
*/
|
|
static int write(BFILE *ofs, unsigned char * imgdata, int imgdataw, int imgdatah, unsigned char * palette)
|
|
{
|
|
unsigned char head[128];
|
|
int bpl = imgdataw + (imgdataw&1);
|
|
|
|
memset(head,0,128);
|
|
head[0] = 10;
|
|
head[1] = 5;
|
|
head[2] = 1;
|
|
head[3] = 8;
|
|
head[8] = (imgdataw-1) & 0xff;
|
|
head[9] = ((imgdataw-1) >> 8) & 0xff;
|
|
head[10] = (imgdatah-1) & 0xff;
|
|
head[11] = ((imgdatah-1) >> 8) & 0xff;
|
|
head[12] = 72; head[13] = 0;
|
|
head[14] = 72; head[15] = 0;
|
|
head[65] = 1; // 8-bit
|
|
head[66] = bpl & 0xff;
|
|
head[67] = (bpl >> 8) & 0xff;
|
|
head[68] = 1;
|
|
|
|
Bfwrite(head, sizeof(head), 1, ofs);
|
|
for (int i = 0; i < imgdatah; i++) {
|
|
writeline(imgdata + i, imgdataw, imgdatah, ofs);
|
|
}
|
|
|
|
Bfputc(12, ofs);
|
|
Bfwrite(palette, 768, 1, ofs);
|
|
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Loads a tile from a picture file into memory
|
|
* @param filename the filename
|
|
* @param imgdata receives a pointer to the decoded image data
|
|
* @param imgdataw receives the decoded image width
|
|
* @param imgdatah receives the decoded image height
|
|
* @return 0 on success
|
|
*/
|
|
int loadimage(Bstring const & filename, char ** imgdata, int& imgdataw, int& imgdatah)
|
|
{
|
|
BFILE *infile = Bfopen(filename(),"rb");
|
|
unsigned char * data = 0;
|
|
int datalen = 0, err = 0;
|
|
|
|
if (infile == NULL)
|
|
return 1;
|
|
|
|
struct Bstat stbuf;
|
|
if (Bfstat(Bfileno(infile), &stbuf) == -1)
|
|
return 1;
|
|
|
|
datalen = stbuf.st_size;
|
|
|
|
data = new unsigned char [datalen];
|
|
Bfread(data, 1, datalen, infile);
|
|
Bfclose(infile);
|
|
|
|
err = PCX::decode(data, datalen, imgdata, imgdataw, imgdatah);
|
|
|
|
delete [] data;
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Saves a tile from memory to disk, taking the palette from palette.dat
|
|
* @param filename the filename
|
|
* @param imgdata a pointer to the image data
|
|
* @param imgdataw the image width
|
|
* @param imgdatah the image height
|
|
* @return 0 on success
|
|
*/
|
|
int saveimage(Bstring const & filename, char * imgdata, int imgdataw, int imgdatah)
|
|
{
|
|
BFILE *outfile = Bfopen(filename(), "wb");
|
|
BFILE *palfile = Bfopen("palette.dat", "rb");
|
|
unsigned char palette[768];
|
|
|
|
if (palfile != NULL) {
|
|
Bfread(palette, 768, 1, palfile);
|
|
for (int i=0; i<256*3; i++) {
|
|
palette[i] <<= 2;
|
|
}
|
|
Bfclose(palfile);
|
|
} else {
|
|
Bfprintf(stderr, "warning: palette.dat could not be loaded\n");
|
|
for (int i=0; i<256; i++) {
|
|
palette[i*3+0] = i;
|
|
palette[i*3+1] = i;
|
|
palette[i*3+2] = i;
|
|
}
|
|
}
|
|
|
|
if (outfile == NULL) {
|
|
return 1;
|
|
}
|
|
|
|
PCX::write(outfile, (unsigned char *)imgdata, imgdataw, imgdatah, palette);
|
|
|
|
Bfclose(outfile);
|
|
|
|
return 0;
|
|
}
|
|
|
|
class Operation {
|
|
protected:
|
|
Bstring makefilename(int n)
|
|
{
|
|
Bstring filename("tilesXXX.art");
|
|
filename[5] = '0' + (n / 100) % 10;
|
|
filename[6] = '0' + (n / 10) % 10;
|
|
filename[7] = '0' + (n / 1) % 10;
|
|
return filename;
|
|
}
|
|
|
|
public:
|
|
typedef enum {
|
|
ERR_NO_ERROR = 0,
|
|
ERR_BAD_OPTION = 1,
|
|
ERR_BAD_VALUE = 2,
|
|
ERR_TOO_MANY_PARAMS = 3,
|
|
ERR_NO_ART_FILE = 4,
|
|
ERR_INVALID_IMAGE = 5,
|
|
} Result;
|
|
|
|
static char const * translateResult(Result r)
|
|
{
|
|
switch (r) {
|
|
case ERR_NO_ERROR: return "no error";
|
|
case ERR_BAD_OPTION: return "bad option";
|
|
case ERR_BAD_VALUE: return "bad value";
|
|
case ERR_TOO_MANY_PARAMS: return "too many parameters given";
|
|
case ERR_NO_ART_FILE: return "no ART file was found";
|
|
case ERR_INVALID_IMAGE: return "a nonexistent, corrupt, or unrecognised image was given";
|
|
default: return "unknown error";
|
|
}
|
|
}
|
|
|
|
virtual ~Operation()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Sets an option
|
|
* @param opt the option name
|
|
* @param value the option value
|
|
* @return a value from the Result enum
|
|
*/
|
|
virtual Result setOption(const Bstring &opt, const Bstring &value) = 0;
|
|
|
|
/**
|
|
* Sets a parameter from the unnamed sequence
|
|
* @param number the parameter number
|
|
* @param value the parameter value
|
|
* @return a value from the Result enum
|
|
*/
|
|
virtual Result setParameter(const int &number, const Bstring &value) = 0;
|
|
|
|
/**
|
|
* Do the operation
|
|
* @return a value from the Result enum
|
|
*/
|
|
virtual Result perform() = 0;
|
|
};
|
|
class InfoOp : public Operation {
|
|
private:
|
|
int tilenum_;
|
|
|
|
void outputInfo(ARTFile& art, int tile)
|
|
{
|
|
Bprintf(" Tile %i: ", tile);
|
|
|
|
int w, h;
|
|
art.getTileSize(tile, w, h);
|
|
Bprintf("%ix%i ", w, h);
|
|
|
|
Bprintf("Xofs: %i, ", art.getXOfs(tile));
|
|
Bprintf("Yofs: %i, ", art.getYOfs(tile));
|
|
Bprintf("AnimType: %i, ", art.getAnimType(tile));
|
|
Bprintf("AnimFrames: %i, ", art.getAnimFrames(tile));
|
|
Bprintf("AnimSpeed: %i\n", art.getAnimSpeed(tile));
|
|
}
|
|
|
|
public:
|
|
InfoOp() : tilenum_(-1) { }
|
|
|
|
virtual Result setOption(const Bstring &opt ATTRIBUTE((unused)), const Bstring &value ATTRIBUTE((unused)))
|
|
{
|
|
return ERR_BAD_OPTION;
|
|
}
|
|
|
|
virtual Result setParameter(const int &number, const Bstring &value)
|
|
{
|
|
switch (number) {
|
|
case 0:
|
|
tilenum_ = atoi(value());
|
|
return ERR_NO_ERROR;
|
|
default:
|
|
return ERR_TOO_MANY_PARAMS;
|
|
}
|
|
}
|
|
|
|
virtual Result perform()
|
|
{
|
|
int filenum = 0, tile;
|
|
|
|
for (filenum = 0; filenum < 1000; filenum++) {
|
|
Bstring filename = makefilename(filenum);
|
|
ARTFile art(filename);
|
|
|
|
if (art.getNumTiles() == 0) {
|
|
// no file exists, so give up
|
|
if (tilenum_ < 0) {
|
|
return ERR_NO_ERROR;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (tilenum_ >= 0) {
|
|
if (tilenum_ > art.getLastTile()) {
|
|
// Not in this file.
|
|
continue;
|
|
} else {
|
|
Bprintf("File %s\n", filename());
|
|
outputInfo(art, tilenum_);
|
|
}
|
|
return ERR_NO_ERROR;
|
|
} else {
|
|
Bprintf("File %s\n", filename());
|
|
for (tile = art.getFirstTile(); tile <= art.getLastTile(); tile++) {
|
|
outputInfo(art, tile);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ERR_NO_ART_FILE;
|
|
}
|
|
};
|
|
|
|
class CreateOp : public Operation {
|
|
private:
|
|
int filen_, offset_, ntiles_;
|
|
public:
|
|
CreateOp() : filen_(0), offset_(0), ntiles_(256) { }
|
|
|
|
virtual Result setOption(const Bstring &opt, const Bstring &value)
|
|
{
|
|
if (opt == "f") {
|
|
filen_ = atoi(value());
|
|
if (filen_ < 0 || filen_ > 999) {
|
|
return ERR_BAD_VALUE;
|
|
}
|
|
} else if (opt == "o") {
|
|
offset_ = atoi(value());
|
|
if (offset_ < 0) {
|
|
return ERR_BAD_VALUE;
|
|
}
|
|
} else if (opt == "n") {
|
|
ntiles_ = atoi(value());
|
|
if (ntiles_ < 1) {
|
|
return ERR_BAD_VALUE;
|
|
}
|
|
} else {
|
|
return ERR_BAD_OPTION;
|
|
}
|
|
return ERR_NO_ERROR;
|
|
}
|
|
|
|
virtual Result setParameter(const int &number ATTRIBUTE((unused)), const Bstring &value ATTRIBUTE((unused)))
|
|
{
|
|
return ERR_TOO_MANY_PARAMS;
|
|
}
|
|
|
|
virtual Result perform()
|
|
{
|
|
ARTFile art(makefilename(filen_));
|
|
|
|
art.init(offset_, ntiles_);
|
|
art.write();
|
|
|
|
return ERR_NO_ERROR;
|
|
}
|
|
};
|
|
|
|
class AddTileOp : public Operation {
|
|
private:
|
|
int xofs_, yofs_;
|
|
int animframes_, animtype_, animspeed_;
|
|
int tilenum_;
|
|
Bstring filename_;
|
|
public:
|
|
AddTileOp()
|
|
: xofs_(0), yofs_(0),
|
|
animframes_(0), animtype_(0), animspeed_(0),
|
|
tilenum_(-1), filename_("")
|
|
{ }
|
|
|
|
virtual Result setOption(const Bstring &opt, const Bstring &value)
|
|
{
|
|
if (opt == "x") {
|
|
xofs_ = atoi(value());
|
|
} else if (opt == "y") {
|
|
yofs_ = atoi(value());
|
|
} else if (opt == "ann") {
|
|
animframes_ = atoi(value());
|
|
if (animframes_ < 0 || animframes_ > 63) {
|
|
return ERR_BAD_VALUE;
|
|
}
|
|
} else if (opt == "ant") {
|
|
animtype_ = atoi(value());
|
|
if (animtype_ < 0 || animtype_ > 3) {
|
|
return ERR_BAD_VALUE;
|
|
}
|
|
} else if (opt == "ans") {
|
|
animspeed_ = atoi(value());
|
|
if (animspeed_ < 0 || animspeed_ > 15) {
|
|
return ERR_BAD_VALUE;
|
|
}
|
|
} else {
|
|
return ERR_BAD_OPTION;
|
|
}
|
|
return ERR_NO_ERROR;
|
|
}
|
|
|
|
virtual Result setParameter(const int &number, const Bstring &value)
|
|
{
|
|
switch (number) {
|
|
case 0:
|
|
tilenum_ = atoi(value());
|
|
return ERR_NO_ERROR;
|
|
case 1:
|
|
filename_ = value;
|
|
return ERR_NO_ERROR;
|
|
default:
|
|
return ERR_TOO_MANY_PARAMS;
|
|
}
|
|
}
|
|
|
|
virtual Result perform()
|
|
{
|
|
int tilesperfile = 0, nextstart = 0;
|
|
int filenum = 0;
|
|
char * imgdata = 0;
|
|
int imgdataw = 0, imgdatah = 0;
|
|
|
|
// open the first art file to get the file size used by default
|
|
{
|
|
ARTFile art(makefilename(0));
|
|
tilesperfile = art.getNumTiles();
|
|
if (tilesperfile == 0) {
|
|
return ERR_NO_ART_FILE;
|
|
}
|
|
}
|
|
|
|
// load the tile image into memory
|
|
switch (loadimage(filename_, &imgdata, imgdataw, imgdatah)) {
|
|
case 0: break; // win
|
|
default: return ERR_INVALID_IMAGE;
|
|
}
|
|
|
|
// open art files until we find one that encompasses the range we need
|
|
// and when we find it, make the change
|
|
for (filenum = 0; filenum < 1000; filenum++) {
|
|
ARTFile art(makefilename(filenum));
|
|
bool dirty = false, done = false;
|
|
|
|
if (art.getNumTiles() == 0) {
|
|
// no file exists, so we treat it as though it does
|
|
art.init(nextstart, tilesperfile);
|
|
dirty = true;
|
|
}
|
|
|
|
if (tilenum_ >= art.getFirstTile() && tilenum_ <= art.getLastTile()) {
|
|
art.replaceTile(tilenum_, imgdata, imgdataw * imgdatah);
|
|
art.setTileSize(tilenum_, imgdataw, imgdatah);
|
|
art.setXOfs(tilenum_, xofs_);
|
|
art.setYOfs(tilenum_, yofs_);
|
|
art.setAnimFrames(tilenum_, animframes_);
|
|
art.setAnimSpeed(tilenum_, animspeed_);
|
|
art.setAnimType(tilenum_, animtype_);
|
|
done = true;
|
|
dirty = true;
|
|
|
|
imgdata = 0; // ARTFile.replaceTile took ownership of the pointer
|
|
}
|
|
|
|
nextstart += art.getNumTiles();
|
|
|
|
if (dirty) {
|
|
art.write();
|
|
}
|
|
if (done) {
|
|
return ERR_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
if (imgdata) {
|
|
delete [] imgdata;
|
|
}
|
|
|
|
return ERR_NO_ART_FILE;
|
|
}
|
|
};
|
|
|
|
class RmTileOp : public Operation {
|
|
private:
|
|
int tilenum_;
|
|
public:
|
|
RmTileOp() : tilenum_(-1) { }
|
|
|
|
virtual Result setOption(const Bstring &opt ATTRIBUTE((unused)), const Bstring &value ATTRIBUTE((unused)))
|
|
{
|
|
return ERR_BAD_OPTION;
|
|
}
|
|
|
|
virtual Result setParameter(const int &number, const Bstring &value)
|
|
{
|
|
switch (number) {
|
|
case 0:
|
|
tilenum_ = atoi(value());
|
|
return ERR_NO_ERROR;
|
|
default:
|
|
return ERR_TOO_MANY_PARAMS;
|
|
}
|
|
}
|
|
|
|
virtual Result perform()
|
|
{
|
|
int filenum = 0;
|
|
|
|
// open art files until we find one that encompasses the range we need
|
|
// and when we find it, remove the tile
|
|
for (filenum = 0; filenum < 1000; filenum++) {
|
|
ARTFile art(makefilename(filenum));
|
|
|
|
if (art.getNumTiles() == 0) {
|
|
// no file exists, so give up
|
|
break;
|
|
}
|
|
|
|
if (tilenum_ >= art.getFirstTile() && tilenum_ <= art.getLastTile()) {
|
|
art.removeTile(tilenum_);
|
|
art.write();
|
|
return ERR_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
return ERR_NO_ART_FILE;
|
|
}
|
|
};
|
|
|
|
class ExportTileOp : public Operation {
|
|
private:
|
|
int tilenum_;
|
|
public:
|
|
ExportTileOp() : tilenum_(-1) { }
|
|
|
|
virtual Result setOption(const Bstring &opt ATTRIBUTE((unused)), const Bstring &value ATTRIBUTE((unused)))
|
|
{
|
|
return ERR_BAD_OPTION;
|
|
}
|
|
|
|
virtual Result setParameter(const int &number, const Bstring &value)
|
|
{
|
|
switch (number) {
|
|
case 0:
|
|
tilenum_ = atoi(value());
|
|
return ERR_NO_ERROR;
|
|
default:
|
|
return ERR_TOO_MANY_PARAMS;
|
|
}
|
|
}
|
|
|
|
virtual Result perform()
|
|
{
|
|
int filenum = 0;
|
|
|
|
Bstring filename("tile0000.pcx");
|
|
filename[4] = '0' + (tilenum_ / 1000) % 10;
|
|
filename[5] = '0' + (tilenum_ / 100) % 10;
|
|
filename[6] = '0' + (tilenum_ / 10) % 10;
|
|
filename[7] = '0' + (tilenum_) % 10;
|
|
|
|
// open art files until we find the one that encompasses the range we need
|
|
// and when we find it, export it
|
|
for (filenum = 0; filenum < 1000; filenum++) {
|
|
ARTFile art(makefilename(filenum));
|
|
|
|
if (art.getNumTiles() == 0) {
|
|
// no file exists, so give up
|
|
break;
|
|
}
|
|
|
|
if (tilenum_ >= art.getFirstTile() && tilenum_ <= art.getLastTile()) {
|
|
int bytes, w, h;
|
|
char * data = art.readTile(tilenum_, bytes);
|
|
art.getTileSize(tilenum_, w, h);
|
|
|
|
if (bytes == 0) {
|
|
return ERR_NO_ERROR;
|
|
}
|
|
|
|
switch (saveimage(filename, data, w, h)) {
|
|
case 0: break; // win
|
|
default: return ERR_INVALID_IMAGE;
|
|
}
|
|
|
|
delete [] data;
|
|
|
|
return ERR_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
return ERR_NO_ART_FILE;
|
|
}
|
|
};
|
|
|
|
class TilePropOp : public Operation {
|
|
private:
|
|
int xofs_, yofs_;
|
|
int animframes_, animtype_, animspeed_;
|
|
int tilenum_;
|
|
|
|
int settings_;
|
|
|
|
enum {
|
|
SET_XOFS = 1,
|
|
SET_YOFS = 2,
|
|
SET_ANIMFRAMES = 4,
|
|
SET_ANIMTYPE = 8,
|
|
SET_ANIMSPEED = 16,
|
|
};
|
|
public:
|
|
TilePropOp()
|
|
: xofs_(0), yofs_(0),
|
|
animframes_(0), animtype_(0), animspeed_(0),
|
|
tilenum_(-1), settings_(0)
|
|
{ }
|
|
|
|
virtual Result setOption(const Bstring &opt, const Bstring &value)
|
|
{
|
|
if (opt == "x") {
|
|
xofs_ = atoi(value());
|
|
settings_ |= SET_XOFS;
|
|
} else if (opt == "y") {
|
|
yofs_ = atoi(value());
|
|
settings_ |= SET_YOFS;
|
|
} else if (opt == "ann") {
|
|
animframes_ = atoi(value());
|
|
settings_ |= SET_ANIMFRAMES;
|
|
if (animframes_ < 0 || animframes_ > 63) {
|
|
return ERR_BAD_VALUE;
|
|
}
|
|
} else if (opt == "ant") {
|
|
animtype_ = atoi(value());
|
|
settings_ |= SET_ANIMTYPE;
|
|
if (animtype_ < 0 || animtype_ > 3) {
|
|
return ERR_BAD_VALUE;
|
|
}
|
|
} else if (opt == "ans") {
|
|
animspeed_ = atoi(value());
|
|
settings_ |= SET_ANIMSPEED;
|
|
if (animspeed_ < 0 || animspeed_ > 15) {
|
|
return ERR_BAD_VALUE;
|
|
}
|
|
} else {
|
|
return ERR_BAD_OPTION;
|
|
}
|
|
return ERR_NO_ERROR;
|
|
}
|
|
|
|
virtual Result setParameter(const int &number, const Bstring &value)
|
|
{
|
|
switch (number) {
|
|
case 0:
|
|
tilenum_ = atoi(value());
|
|
return ERR_NO_ERROR;
|
|
default:
|
|
return ERR_TOO_MANY_PARAMS;
|
|
}
|
|
}
|
|
|
|
virtual Result perform()
|
|
{
|
|
int filenum = 0;
|
|
|
|
if (settings_ == 0) {
|
|
return ERR_NO_ERROR;
|
|
}
|
|
|
|
// open art files until we find one that encompasses the range we need
|
|
// and when we find it, make the change
|
|
for (filenum = 0; filenum < 1000; filenum++) {
|
|
ARTFile art(makefilename(filenum));
|
|
|
|
if (art.getNumTiles() == 0) {
|
|
// no file exists, so give up
|
|
break;
|
|
}
|
|
|
|
if (tilenum_ >= art.getFirstTile() && tilenum_ <= art.getLastTile()) {
|
|
if (settings_ & SET_XOFS) {
|
|
art.setXOfs(tilenum_, xofs_);
|
|
}
|
|
if (settings_ & SET_YOFS) {
|
|
art.setYOfs(tilenum_, yofs_);
|
|
}
|
|
if (settings_ & SET_ANIMFRAMES) {
|
|
art.setAnimFrames(tilenum_, animframes_);
|
|
}
|
|
if (settings_ & SET_ANIMSPEED) {
|
|
art.setAnimSpeed(tilenum_, animspeed_);
|
|
}
|
|
if (settings_ & SET_ANIMTYPE) {
|
|
art.setAnimType(tilenum_, animtype_);
|
|
}
|
|
art.write();
|
|
return ERR_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
return ERR_NO_ART_FILE;
|
|
}
|
|
};
|
|
|
|
int main(int argc, char ** argv)
|
|
{
|
|
int showusage = 0;
|
|
Operation * oper = 0;
|
|
Operation::Result err = Operation::ERR_NO_ERROR;
|
|
|
|
if (argc < 2) {
|
|
showusage = 1;
|
|
} else {
|
|
Bstring opt(argv[1]);
|
|
Bstring value;
|
|
|
|
// create the option handler object according to the first param
|
|
if (opt == "info") {
|
|
oper = new InfoOp;
|
|
} else if (opt == "create") {
|
|
oper = new CreateOp;
|
|
} else if (opt == "addtile") {
|
|
oper = new AddTileOp;
|
|
} else if (opt == "rmtile") {
|
|
oper = new RmTileOp;
|
|
} else if (opt == "exporttile") {
|
|
oper = new ExportTileOp;
|
|
} else if (opt == "tileprop") {
|
|
oper = new TilePropOp;
|
|
} else {
|
|
showusage = 2;
|
|
}
|
|
|
|
// apply the command line options given
|
|
if (oper) {
|
|
int unnamedParm = 0;
|
|
for (int i = 2; i < argc && !showusage; ++i) {
|
|
if (argv[i][0] == '-') {
|
|
opt = argv[i] + 1;
|
|
if (i+1 >= argc) {
|
|
showusage = 2;
|
|
break;
|
|
}
|
|
value = argv[i+1];
|
|
++i;
|
|
|
|
switch (err = oper->setOption(opt, value)) {
|
|
case Operation::ERR_NO_ERROR: break;
|
|
default:
|
|
Bfprintf(stderr, "error: %s\n", Operation::translateResult(err));
|
|
showusage = 2;
|
|
break;
|
|
}
|
|
} else {
|
|
value = argv[i];
|
|
switch (oper->setParameter(unnamedParm, value)) {
|
|
case Operation::ERR_NO_ERROR: break;
|
|
default:
|
|
Bfprintf(stderr, "error: %s\n", Operation::translateResult(err));
|
|
showusage = 2;
|
|
break;
|
|
}
|
|
++unnamedParm;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (showusage) {
|
|
usage();
|
|
if (oper) delete oper;
|
|
return (showusage - 1);
|
|
} else if (oper) {
|
|
err = oper->perform();
|
|
delete oper;
|
|
|
|
switch (err) {
|
|
case Operation::ERR_NO_ERROR: return 0;
|
|
default:
|
|
Bfprintf(stderr, "error: %s\n", Operation::translateResult(err));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|