bsnes/nall/mosaic/context.hpp

228 lines
6.3 KiB
C++
Raw Normal View History

#ifdef NALL_MOSAIC_INTERNAL_HPP
namespace nall {
namespace mosaic {
struct context {
unsigned offset;
unsigned width;
unsigned height;
unsigned count;
bool endian; //0 = lsb, 1 = msb
bool order; //0 = linear, 1 = planar
unsigned depth; //1 - 24bpp
unsigned blockWidth;
unsigned blockHeight;
unsigned blockStride;
unsigned blockOffset;
vector<unsigned> block;
unsigned tileWidth;
unsigned tileHeight;
unsigned tileStride;
unsigned tileOffset;
vector<unsigned> tile;
unsigned mosaicWidth;
unsigned mosaicHeight;
unsigned mosaicStride;
unsigned mosaicOffset;
vector<unsigned> mosaic;
unsigned paddingWidth;
unsigned paddingHeight;
unsigned paddingColor;
vector<unsigned> palette;
unsigned objectWidth() const { return blockWidth * tileWidth * mosaicWidth + paddingWidth; }
unsigned objectHeight() const { return blockHeight * tileHeight * mosaicHeight + paddingHeight; }
unsigned objectSize() const {
unsigned size = blockStride * tileWidth * tileHeight * mosaicWidth * mosaicHeight
+ blockOffset * tileHeight * mosaicWidth * mosaicHeight
+ tileStride * mosaicWidth * mosaicHeight
+ tileOffset * mosaicHeight;
return max(1u, size);
}
unsigned eval(const string& expression) {
if(auto result = Eval::integer(expression)) return result();
return 0u;
}
void eval(vector<unsigned>& buffer, const string& expression_) {
string expression = expression_;
bool function = false;
for(auto& c : expression) {
if(c == '(') function = true;
if(c == ')') function = false;
if(c == ',' && function == true) c = ';';
}
lstring list = expression.split(",");
for(auto& item : list) {
item.trim();
if(item.match("f(?*) ?*")) {
item.ltrim<1>("f(");
lstring part = item.split<1>(") ");
lstring args = part[0].split<3>(";");
for(auto &item : args) item.trim();
unsigned length = eval(args(0, "0"));
unsigned offset = eval(args(1, "0"));
unsigned stride = eval(args(2, "0"));
if(args.size() < 2) offset = buffer.size();
if(args.size() < 3) stride = 1;
for(unsigned n = 0; n < length; n++) {
string fn = part[1];
fn.replace("n", string{n});
fn.replace("o", string{offset});
fn.replace("p", string{buffer.size()});
buffer.resize(offset + 1);
buffer[offset] = eval(fn);
offset += stride;
}
} else if(item.match("base64*")) {
unsigned offset = 0;
item.ltrim<1>("base64");
if(item.match("(?*) *")) {
item.ltrim<1>("(");
lstring part = item.split<1>(") ");
offset = eval(part[0]);
item = part(1, "");
}
item.trim();
for(auto& c : item) {
if(c >= 'A' && c <= 'Z') buffer.append(offset + c - 'A' + 0);
if(c >= 'a' && c <= 'z') buffer.append(offset + c - 'a' + 26);
if(c >= '0' && c <= '9') buffer.append(offset + c - '0' + 52);
if(c == '-') buffer.append(offset + 62);
if(c == '_') buffer.append(offset + 63);
}
} else if(item.match("file *")) {
item.ltrim<1>("file ");
item.trim();
//...
} else if(item.empty() == false) {
buffer.append(eval(item));
}
}
}
void parse(const string& data) {
reset();
lstring lines = data.split("\n");
for(auto& line : lines) {
lstring part = line.split<1>(":");
if(part.size() != 2) continue;
part[0].trim();
part[1].trim();
if(part[0] == "offset") offset = eval(part[1]);
if(part[0] == "width") width = eval(part[1]);
if(part[0] == "height") height = eval(part[1]);
if(part[0] == "count") count = eval(part[1]);
if(part[0] == "endian") endian = eval(part[1]);
if(part[0] == "order") order = eval(part[1]);
if(part[0] == "depth") depth = eval(part[1]);
if(part[0] == "blockWidth") blockWidth = eval(part[1]);
if(part[0] == "blockHeight") blockHeight = eval(part[1]);
if(part[0] == "blockStride") blockStride = eval(part[1]);
if(part[0] == "blockOffset") blockOffset = eval(part[1]);
if(part[0] == "block") eval(block, part[1]);
if(part[0] == "tileWidth") tileWidth = eval(part[1]);
if(part[0] == "tileHeight") tileHeight = eval(part[1]);
if(part[0] == "tileStride") tileStride = eval(part[1]);
if(part[0] == "tileOffset") tileOffset = eval(part[1]);
if(part[0] == "tile") eval(tile, part[1]);
if(part[0] == "mosaicWidth") mosaicWidth = eval(part[1]);
if(part[0] == "mosaicHeight") mosaicHeight = eval(part[1]);
if(part[0] == "mosaicStride") mosaicStride = eval(part[1]);
if(part[0] == "mosaicOffset") mosaicOffset = eval(part[1]);
if(part[0] == "mosaic") eval(mosaic, part[1]);
if(part[0] == "paddingWidth") paddingWidth = eval(part[1]);
if(part[0] == "paddingHeight") paddingHeight = eval(part[1]);
if(part[0] == "paddingColor") paddingColor = eval(part[1]);
if(part[0] == "palette") eval(palette, part[1]);
}
sanitize();
}
bool load(const string& filename) {
string filedata = string::read(filename);
if(filedata.empty()) return false;
parse(filedata);
return true;
}
void sanitize() {
if(depth < 1) depth = 1;
if(depth > 24) depth = 24;
if(blockWidth < 1) blockWidth = 1;
if(blockHeight < 1) blockHeight = 1;
if(tileWidth < 1) tileWidth = 1;
if(tileHeight < 1) tileHeight = 1;
if(mosaicWidth < 1) mosaicWidth = 1;
if(mosaicHeight < 1) mosaicHeight = 1;
//set alpha to full opacity
paddingColor |= 255u << 24;
for(auto& color : palette) color |= 255u << 24;
}
void reset() {
offset = 0;
width = 0;
height = 0;
count = 0;
endian = 1;
order = 0;
depth = 1;
blockWidth = 1;
blockHeight = 1;
blockStride = 0;
blockOffset = 0;
block.reset();
tileWidth = 1;
tileHeight = 1;
tileStride = 0;
tileOffset = 0;
tile.reset();
mosaicWidth = 1;
mosaicHeight = 1;
mosaicStride = 0;
mosaicOffset = 0;
mosaic.reset();
paddingWidth = 0;
paddingHeight = 0;
paddingColor = 0;
palette.reset();
}
context() {
reset();
}
};
}
}
#endif