diff options
| author | claude-bot <[email protected]> | 2026-07-13 12:40:03 +0000 |
|---|---|---|
| committer | claude-bot <[email protected]> | 2026-07-13 12:40:03 +0000 |
| commit | 847962910f0bff071f3bf07c9abb87764fb6cac3 (patch) | |
| tree | ddcd429e134c7fd5f72ddc97ced175de8d66fcd0 /src/raster.cpp | |
| download | librw-master.tar.gz librw-master.zip | |
Snapshot for re3/reVC vendoring, per @lzcnt.
Source: https://github.com/aap/librw (master).
Diffstat (limited to 'src/raster.cpp')
| -rw-r--r-- | src/raster.cpp | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/src/raster.cpp b/src/raster.cpp new file mode 100644 index 0000000..c7ebffe --- /dev/null +++ b/src/raster.cpp @@ -0,0 +1,559 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "rwbase.h" +#include "rwerror.h" +#include "rwplg.h" +#include "rwpipeline.h" +#include "rwobjects.h" +#include "rwengine.h" +//#include "ps2/rwps2.h" +#include "d3d/rwd3d.h" +#include "d3d/rwxbox.h" +//#include "d3d/rwd3d8.h" +//#include "d3d/rwd3d9.h" +#include "gl/rwgl3.h" + +#define PLUGIN_ID 0 + +namespace rw { + +int32 Raster::numAllocated; + +struct RasterGlobals +{ + int32 sp; + Raster *stack[32]; +}; +int32 rasterModuleOffset; + +#define RASTERGLOBAL(v) (PLUGINOFFSET(RasterGlobals, engine, rasterModuleOffset)->v) + +static void* +rasterOpen(void *object, int32 offset, int32 size) +{ + int i; + rasterModuleOffset = offset; + RASTERGLOBAL(sp) = -1; + for(i = 0; i < (int)nelem(RASTERGLOBAL(stack)); i++) + RASTERGLOBAL(stack)[i] = nil; + return object; +} + +static void* +rasterClose(void *object, int32 offset, int32 size) +{ + return object; +} + +void +Raster::registerModule(void) +{ + Engine::registerPlugin(sizeof(RasterGlobals), ID_RASTERMODULE, rasterOpen, rasterClose); +} + +Raster* +Raster::create(int32 width, int32 height, int32 depth, int32 format, int32 platform) +{ + // TODO: pass arguments through to the driver and create the raster there + Raster *raster = (Raster*)rwMalloc(s_plglist.size, MEMDUR_EVENT); // TODO + assert(raster != nil); + numAllocated++; + raster->parent = raster; + raster->offsetX = 0; + raster->offsetY = 0; + raster->platform = platform ? platform : rw::platform; + raster->type = format & 0x7; + raster->flags = format & 0xF8; + raster->privateFlags = 0; + raster->format = format & 0xFF00; + raster->width = width; + raster->height = height; + raster->depth = depth; + raster->stride = 0; + raster->pixels = raster->palette = nil; + s_plglist.construct(raster); + +// printf("%d %d %d %d\n", raster->type, raster->width, raster->height, raster->depth); + return engine->driver[raster->platform]->rasterCreate(raster); +} + +void +Raster::subRaster(Raster *parent, Rect *r) +{ + if((this->flags & DONTALLOCATE) == 0) + return; + this->width = r->w; + this->height = r->h; + this->offsetX = parent->offsetX + r->x; + this->offsetY = parent->offsetY + r->y; + this->parent = parent->parent; +} + +void +Raster::destroy(void) +{ + s_plglist.destruct(this); + rwFree(this); + numAllocated--; +} + +uint8* +Raster::lock(int32 level, int32 lockMode) +{ + return engine->driver[this->platform]->rasterLock(this, level, lockMode); +} + +void +Raster::unlock(int32 level) +{ + engine->driver[this->platform]->rasterUnlock(this, level); +} + +uint8* +Raster::lockPalette(int32 lockMode) +{ + return engine->driver[this->platform]->rasterLockPalette(this, lockMode); +} + +void +Raster::unlockPalette(void) +{ + engine->driver[this->platform]->rasterUnlockPalette(this); +} + +int32 +Raster::getNumLevels(void) +{ + return engine->driver[this->platform]->rasterNumLevels(this); +} + +int32 +Raster::calculateNumLevels(int32 width, int32 height) +{ + int32 size = width >= height ? width : height; + int32 n; + for(n = 0; size != 0; n++) + size /= 2; + return n; +} + +bool +Raster::formatHasAlpha(int32 format) +{ + return (format & 0xF00) == Raster::C8888 || + (format & 0xF00) == Raster::C1555 || + (format & 0xF00) == Raster::C4444; +} + +bool32 +Raster::imageFindRasterFormat(Image *image, int32 type, + int32 *pWidth, int32 *pHeight, int32 *pDepth, int32 *pFormat, + int32 platform) +{ + return engine->driver[platform ? platform : rw::platform]->imageFindRasterFormat( + image, type, pWidth, pHeight, pDepth, pFormat); +} + +Raster* +Raster::setFromImage(Image *image, int32 platform) +{ + if(engine->driver[platform ? platform : rw::platform]->rasterFromImage(this, image)) + return this; + return nil; +} + +Raster* +Raster::createFromImage(Image *image, int32 platform) +{ + Raster *raster; + int32 width, height, depth, format; + if(!imageFindRasterFormat(image, TEXTURE, &width, &height, &depth, &format, platform)) + return nil; + raster = Raster::create(width, height, depth, format, platform); + if(raster == nil) + return nil; + return raster->setFromImage(image, platform); +} + +Image* +Raster::toImage(void) +{ + return engine->driver[this->platform]->rasterToImage(this); +} + +void +Raster::show(uint32 flags) +{ + engine->device.showRaster(this, flags); +} + +Raster* +Raster::pushContext(Raster *raster) +{ + RasterGlobals *g = PLUGINOFFSET(RasterGlobals, engine, rasterModuleOffset); + if(g->sp >= (int32)nelem(g->stack)-1) + return nil; + return g->stack[++g->sp] = raster; +} + +Raster* +Raster::popContext(void) +{ + RasterGlobals *g = PLUGINOFFSET(RasterGlobals, engine, rasterModuleOffset); + if(g->sp < 0) + return nil; + return g->stack[g->sp--]; +} + +Raster* +Raster::getCurrentContext(void) +{ + RasterGlobals *g = PLUGINOFFSET(RasterGlobals, engine, rasterModuleOffset); + if(g->sp < 0 || g->sp >= (int32)nelem(g->stack)) + return nil; + return g->stack[g->sp]; +} + +bool32 +Raster::renderFast(int32 x, int32 y) +{ + return engine->device.rasterRenderFast(this,x, y); +} + +void +conv_RGBA8888_from_RGBA8888(uint8 *out, uint8 *in) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +void +conv_BGRA8888_from_RGBA8888(uint8 *out, uint8 *in) +{ + out[2] = in[0]; + out[1] = in[1]; + out[0] = in[2]; + out[3] = in[3]; +} + +void +conv_RGBA8888_from_RGB888(uint8 *out, uint8 *in) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = 0xFF; +} + +void +conv_BGRA8888_from_RGB888(uint8 *out, uint8 *in) +{ + out[2] = in[0]; + out[1] = in[1]; + out[0] = in[2]; + out[3] = 0xFF; +} + +void +conv_RGB888_from_RGB888(uint8 *out, uint8 *in) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +void +conv_BGR888_from_RGB888(uint8 *out, uint8 *in) +{ + out[2] = in[0]; + out[1] = in[1]; + out[0] = in[2]; +} + +void +conv_ARGB1555_from_ARGB1555(uint8 *out, uint8 *in) +{ + out[0] = in[0]; + out[1] = in[1]; +} + +void +conv_ARGB1555_from_RGB555(uint8 *out, uint8 *in) +{ + out[0] = in[0]; + out[1] = in[1] | 0x80; +} + +void +conv_RGBA5551_from_ARGB1555(uint8 *out, uint8 *in) +{ + uint32 r, g, b, a; + a = (in[1]>>7) & 1; + r = (in[1]>>2) & 0x1F; + g = (in[1]&3)<<3 | ((in[0]>>5)&7); + b = in[0] & 0x1F; + out[0] = a | b<<1 | g<<6; + out[1] = g>>2 | r<<3; +} + +void +conv_ARGB1555_from_RGBA5551(uint8 *out, uint8 *in) +{ + uint32 r, g, b, a; + a = in[0] & 1; + b = (in[0]>>1) & 0x1F; + g = (in[1]&7)<<2 | ((in[0]>>6)&3); + r = (in[1]>>3) & 0x1F; + out[0] = b | g<<5; + out[1] = g>>3 | r<<2 | a<<7; +} + +void +conv_RGBA8888_from_ARGB1555(uint8 *out, uint8 *in) +{ + uint32 r, g, b, a; + a = (in[1]>>7) & 1; + r = (in[1]>>2) & 0x1F; + g = (in[1]&3)<<3 | ((in[0]>>5)&7); + b = in[0] & 0x1F; + out[0] = r*0xFF/0x1f; + out[1] = g*0xFF/0x1f; + out[2] = b*0xFF/0x1f; + out[3] = a*0xFF; +} + +void +conv_ABGR1555_from_ARGB1555(uint8 *out, uint8 *in) +{ + uint32 r, b; + r = (in[1]>>2) & 0x1F; + b = in[0] & 0x1F; + out[1] = (in[1]&0x83) | b<<2; + out[0] = (in[0]&0xE0) | r; +} + +void +expandPal4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h) +{ + int32 x, y; + for(y = 0; y < h; y++) + for(x = 0; x < w/2; x++){ + dst[y*dststride + x*2 + 0] = src[y*srcstride + x] & 0xF; + dst[y*dststride + x*2 + 1] = src[y*srcstride + x] >> 4; + } +} +void +compressPal4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h) +{ + int32 x, y; + for(y = 0; y < h; y++) + for(x = 0; x < w/2; x++) + dst[y*dststride + x] = src[y*srcstride + x*2 + 0] | src[y*srcstride + x*2 + 1] << 4; +} + +void +expandPal4_BE(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h) +{ + int32 x, y; + for(y = 0; y < h; y++) + for(x = 0; x < w/2; x++){ + dst[y*dststride + x*2 + 1] = src[y*srcstride + x] & 0xF; + dst[y*dststride + x*2 + 0] = src[y*srcstride + x] >> 4; + } +} +void +compressPal4_BE(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h) +{ + int32 x, y; + for(y = 0; y < h; y++) + for(x = 0; x < w/2; x++) + dst[y*dststride + x] = src[y*srcstride + x*2 + 1] | src[y*srcstride + x*2 + 0] << 4; +} + +void +copyPal8(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h) +{ + int32 x, y; + for(y = 0; y < h; y++) + for(x = 0; x < w; x++) + dst[y*dststride + x] = src[y*srcstride + x]; +} + + + +// Platform conversion + +static rw::Raster* +xbox_to_d3d(rw::Raster *ras) +{ + using namespace rw; + + int dxt = 0; + xbox::XboxRaster *xboxras = GETXBOXRASTEREXT(ras); + if(xboxras->customFormat){ + switch(xboxras->format){ + case xbox::D3DFMT_DXT1: dxt = 1; break; + case xbox::D3DFMT_DXT3: dxt = 3; break; + case xbox::D3DFMT_DXT5: dxt = 5; break; + } + } + if(dxt == 0) + return nil; + + Raster *newras = Raster::create(ras->width, ras->height, ras->depth, + ras->format | Raster::TEXTURE | Raster::DONTALLOCATE); + int numLevels = ras->getNumLevels(); + d3d::allocateDXT(newras, dxt, numLevels, xboxras->hasAlpha); + for(int i = 0; i < numLevels; i++){ + uint8 *srcpx = ras->lock(i, Raster::LOCKREAD); + // uint8 *dstpx = newras->lock(i, Raster::LOCKWRITE | Raster::LOCKNOFETCH); + d3d::setTexels(newras, srcpx, i); + // flipDXT(dxt, dstpx, srcpx, ras->width, ras->height); + ras->unlock(i); + // newras->unlock(i); + } + + return newras; +} + +static rw::Raster* +d3d_to_gl3(rw::Raster *ras) +{ +#ifdef RW_GL3 + using namespace rw; + + if(!gl3::gl3Caps.dxtSupported) + return nil; + + int dxt = 0; + d3d::D3dRaster *d3dras = GETD3DRASTEREXT(ras); + if(d3dras->customFormat){ + switch(d3dras->format){ + case d3d::D3DFMT_DXT1: dxt = 1; break; + case d3d::D3DFMT_DXT3: dxt = 3; break; + case d3d::D3DFMT_DXT5: dxt = 5; break; + } + } + if(dxt == 0) + return nil; + + Raster *newras = Raster::create(ras->width, ras->height, ras->depth, + ras->format | Raster::TEXTURE | Raster::DONTALLOCATE); + int numLevels = ras->getNumLevels(); + gl3::allocateDXT(newras, dxt, numLevels, d3dras->hasAlpha); + for(int i = 0; i < numLevels; i++){ + uint8 *srcpx = ras->lock(i, Raster::LOCKREAD); + uint8 *dstpx = newras->lock(i, Raster::LOCKWRITE | Raster::LOCKNOFETCH); + flipDXT(dxt, dstpx, srcpx, ras->width, ras->height); + ras->unlock(i); + newras->unlock(i); + } + + return newras; +#else + return nil; +#endif +} + +static rw::Raster* +xbox_to_gl3(rw::Raster *ras) +{ +#ifdef RW_GL3 + using namespace rw; + + int dxt = 0; + xbox::XboxRaster *xboxras = GETXBOXRASTEREXT(ras); + if(xboxras->customFormat){ + switch(xboxras->format){ + case xbox::D3DFMT_DXT1: dxt = 1; break; + case xbox::D3DFMT_DXT3: dxt = 3; break; + case xbox::D3DFMT_DXT5: dxt = 5; break; + } + } + if(dxt == 0) + return nil; + + Raster *newras = Raster::create(ras->width, ras->height, ras->depth, + ras->format | Raster::TEXTURE | Raster::DONTALLOCATE); + int numLevels = ras->getNumLevels(); + gl3::allocateDXT(newras, dxt, numLevels, xboxras->hasAlpha); + for(int i = 0; i < numLevels; i++){ + uint8 *srcpx = ras->lock(i, Raster::LOCKREAD); + uint8 *dstpx = newras->lock(i, Raster::LOCKWRITE | Raster::LOCKNOFETCH); + flipDXT(dxt, dstpx, srcpx, ras->width, ras->height); + ras->unlock(i); + newras->unlock(i); + } + + return newras; +#else + return nil; +#endif +} + +rw::Raster* +Raster::convertTexToCurrentPlatform(rw::Raster *ras) +{ + using namespace rw; + + if(ras->platform == rw::platform) + return ras; + // compatible platforms + if((ras->platform == PLATFORM_D3D8 && rw::platform == PLATFORM_D3D9) || + (ras->platform == PLATFORM_D3D9 && rw::platform == PLATFORM_D3D8)) + return ras; + + // special cased conversion for DXT + if((ras->platform == PLATFORM_D3D8 || ras->platform == PLATFORM_D3D9) && rw::platform == PLATFORM_GL3){ + Raster *newras = d3d_to_gl3(ras); + if(newras){ + ras->destroy(); + return newras; + } + }else if(ras->platform == PLATFORM_XBOX && (rw::platform == PLATFORM_D3D9 || rw::platform == PLATFORM_D3D8)){ + Raster *newras = xbox_to_d3d(ras); + if(newras){ + ras->destroy(); + return newras; + } + }else if(ras->platform == PLATFORM_XBOX && rw::platform == PLATFORM_GL3){ + Raster *newras = xbox_to_gl3(ras); + if(newras){ + ras->destroy(); + return newras; + } + } + + // fall back to going through Image directly + int32 width, height, depth, format; + Image *img = ras->toImage(); + // TODO: maybe don't *always* do this? + img->unpalettize(); + Raster::imageFindRasterFormat(img, Raster::TEXTURE, &width, &height, &depth, &format); + format |= ras->format & (Raster::MIPMAP | Raster::AUTOMIPMAP); + Raster *newras = Raster::create(width, height, depth, format); + newras->setFromImage(img); + img->destroy(); + int numLevels = ras->getNumLevels(); + for(int i = 1; i < numLevels; i++){ + ras->lock(i, Raster::LOCKREAD); + img = ras->toImage(); + // TODO: maybe don't *always* do this? + img->unpalettize(); + newras->lock(i, Raster::LOCKWRITE|Raster::LOCKNOFETCH); + newras->setFromImage(img); + newras->unlock(i); + ras->unlock(i); + } + ras->destroy(); + ras = newras; + return ras; +} + + +} |
