#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 block; unsigned tileWidth; unsigned tileHeight; unsigned tileStride; unsigned tileOffset; vector tile; unsigned mosaicWidth; unsigned mosaicHeight; unsigned mosaicStride; unsigned mosaicOffset; vector mosaic; unsigned paddingWidth; unsigned paddingHeight; unsigned paddingColor; vector 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& 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.strip(); if(item.match("f(?*) ?*")) { item.ltrim("f(", 1L); lstring part = item.split(") ", 1L); lstring args = part[0].split(";", 3L).strip(); 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("base64", 1L); if(item.match("(?*) *")) { item.ltrim("(", 1L); lstring part = item.split(") ", 1L); offset = eval(part[0]); item = part(1, ""); } item.strip(); 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("file ", 1L); item.strip(); //... } 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(":", 1L).strip(); if(part.size() != 2) continue; 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