mirror of https://github.com/bsnes-emu/bsnes.git
127 lines
4.7 KiB
C++
127 lines
4.7 KiB
C++
|
#ifdef NALL_MOSAIC_INTERNAL_HPP
|
||
|
|
||
|
namespace nall {
|
||
|
namespace mosaic {
|
||
|
|
||
|
struct parser {
|
||
|
image canvas;
|
||
|
|
||
|
//export from bitstream to canvas
|
||
|
inline void load(bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) {
|
||
|
canvas.allocate(width, height);
|
||
|
canvas.clear(ctx.paddingColor);
|
||
|
parse(1, stream, offset, ctx, width, height);
|
||
|
}
|
||
|
|
||
|
//import from canvas to bitstream
|
||
|
inline bool save(bitstream &stream, uint64_t offset, context &ctx) {
|
||
|
if(stream.readonly) return false;
|
||
|
parse(0, stream, offset, ctx, canvas.width, canvas.height);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
inline parser() : canvas(0, 32, 0u, 255u << 16, 255u << 8, 255u << 0) {
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
inline uint32_t read(unsigned x, unsigned y) const {
|
||
|
unsigned addr = y * canvas.width + x;
|
||
|
if(addr >= canvas.width * canvas.height) return 0u;
|
||
|
uint32_t *buffer = (uint32_t*)canvas.data;
|
||
|
return buffer[addr];
|
||
|
}
|
||
|
|
||
|
inline void write(unsigned x, unsigned y, uint32_t data) {
|
||
|
unsigned addr = y * canvas.width + x;
|
||
|
if(addr >= canvas.width * canvas.height) return;
|
||
|
uint32_t *buffer = (uint32_t*)canvas.data;
|
||
|
buffer[addr] = data;
|
||
|
}
|
||
|
|
||
|
inline void parse(bool load, bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) {
|
||
|
stream.endian = ctx.endian;
|
||
|
unsigned canvasWidth = width / (ctx.mosaicWidth * ctx.tileWidth * ctx.blockWidth + ctx.paddingWidth);
|
||
|
unsigned canvasHeight = height / (ctx.mosaicHeight * ctx.tileHeight * ctx.blockHeight + ctx.paddingHeight);
|
||
|
unsigned bitsPerBlock = ctx.depth * ctx.blockWidth * ctx.blockHeight;
|
||
|
|
||
|
unsigned objectOffset = 0;
|
||
|
for(unsigned objectY = 0; objectY < canvasHeight; objectY++) {
|
||
|
for(unsigned objectX = 0; objectX < canvasWidth; objectX++) {
|
||
|
if(objectOffset >= ctx.count && ctx.count > 0) break;
|
||
|
unsigned objectIX = objectX * ctx.objectWidth();
|
||
|
unsigned objectIY = objectY * ctx.objectHeight();
|
||
|
objectOffset++;
|
||
|
|
||
|
unsigned mosaicOffset = 0;
|
||
|
for(unsigned mosaicY = 0; mosaicY < ctx.mosaicHeight; mosaicY++) {
|
||
|
for(unsigned mosaicX = 0; mosaicX < ctx.mosaicWidth; mosaicX++) {
|
||
|
unsigned mosaicData = ctx.mosaic(mosaicOffset, mosaicOffset);
|
||
|
unsigned mosaicIX = (mosaicData % ctx.mosaicWidth) * (ctx.tileWidth * ctx.blockWidth);
|
||
|
unsigned mosaicIY = (mosaicData / ctx.mosaicWidth) * (ctx.tileHeight * ctx.blockHeight);
|
||
|
mosaicOffset++;
|
||
|
|
||
|
unsigned tileOffset = 0;
|
||
|
for(unsigned tileY = 0; tileY < ctx.tileHeight; tileY++) {
|
||
|
for(unsigned tileX = 0; tileX < ctx.tileWidth; tileX++) {
|
||
|
unsigned tileData = ctx.tile(tileOffset, tileOffset);
|
||
|
unsigned tileIX = (tileData % ctx.tileWidth) * ctx.blockWidth;
|
||
|
unsigned tileIY = (tileData / ctx.tileWidth) * ctx.blockHeight;
|
||
|
tileOffset++;
|
||
|
|
||
|
unsigned blockOffset = 0;
|
||
|
for(unsigned blockY = 0; blockY < ctx.blockHeight; blockY++) {
|
||
|
for(unsigned blockX = 0; blockX < ctx.blockWidth; blockX++) {
|
||
|
if(load) {
|
||
|
unsigned palette = 0;
|
||
|
for(unsigned n = 0; n < ctx.depth; n++) {
|
||
|
unsigned index = blockOffset++;
|
||
|
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
||
|
palette |= stream.read(offset + ctx.block(index, index)) << n;
|
||
|
}
|
||
|
|
||
|
write(
|
||
|
objectIX + mosaicIX + tileIX + blockX,
|
||
|
objectIY + mosaicIY + tileIY + blockY,
|
||
|
ctx.palette(palette, palette)
|
||
|
);
|
||
|
} else /* save */ {
|
||
|
uint32_t palette = read(
|
||
|
objectIX + mosaicIX + tileIX + blockX,
|
||
|
objectIY + mosaicIY + tileIY + blockY
|
||
|
);
|
||
|
|
||
|
for(unsigned n = 0; n < ctx.depth; n++) {
|
||
|
unsigned index = blockOffset++;
|
||
|
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
||
|
stream.write(offset + ctx.block(index, index), palette & 1);
|
||
|
palette >>= 1;
|
||
|
}
|
||
|
}
|
||
|
} //blockX
|
||
|
} //blockY
|
||
|
|
||
|
offset += ctx.blockStride;
|
||
|
} //tileX
|
||
|
|
||
|
offset += ctx.blockOffset;
|
||
|
} //tileY
|
||
|
|
||
|
offset += ctx.tileStride;
|
||
|
} //mosaicX
|
||
|
|
||
|
offset += ctx.tileOffset;
|
||
|
} //mosaicY
|
||
|
|
||
|
offset += ctx.mosaicStride;
|
||
|
} //objectX
|
||
|
|
||
|
offset += ctx.mosaicOffset;
|
||
|
} //objectY
|
||
|
}
|
||
|
};
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|