diff --git a/TODO b/TODO index 71bab56..bde3c1c 100644 --- a/TODO +++ b/TODO @@ -9,10 +9,6 @@ TODO: driver - metrics -- mipmaps - -opengl -- DXT conversion from d3d ps2 - rendering! diff --git a/src/d3d/d3d.cpp b/src/d3d/d3d.cpp index 453cb36..a35c24a 100644 --- a/src/d3d/d3d.cpp +++ b/src/d3d/d3d.cpp @@ -207,11 +207,11 @@ unlockVertices(void *vertexBuffer) } void* -createTexture(int32 width, int32 height, int32 numlevels, uint32 format) +createTexture(int32 width, int32 height, int32 numlevels, uint32 usage, uint32 format) { #ifdef RW_D3D9 IDirect3DTexture9 *tex; - d3ddevice->CreateTexture(width, height, numlevels, 0, + d3ddevice->CreateTexture(width, height, numlevels, usage, (D3DFORMAT)format, D3DPOOL_MANAGED, &tex, nil); if(tex) d3d9Globals.numTextures++; @@ -406,11 +406,7 @@ rasterSetFormat(Raster *raster) natras->hasAlpha = formatInfoRW[(raster->format >> 8) & 0xF].hasAlpha; raster->stride = raster->width*natras->bpp; - raster->pixels = nil; - raster->originalWidth = raster->width; - raster->originalHeight = raster->height; - raster->originalStride = raster->stride; - raster->originalPixels = raster->pixels; + natras->autogenMipmap = (raster->format & (Raster::MIPMAP|Raster::AUTOMIPMAP)) == (Raster::MIPMAP|Raster::AUTOMIPMAP); } static Raster* @@ -421,10 +417,17 @@ rasterCreateTexture(Raster *raster) if(natras->format == D3DFMT_P8) natras->palette = (uint8*)rwNew(4*256, MEMDUR_EVENT | ID_DRIVER); - levels = Raster::calculateNumLevels(raster->width, raster->height); + if(natras->autogenMipmap) + levels = 0; + else if(raster->format & Raster::MIPMAP) + levels = Raster::calculateNumLevels(raster->width, raster->height); + else + levels = 1; + assert(natras->texture == nil); natras->texture = createTexture(raster->width, raster->height, - raster->format & Raster::MIPMAP ? levels : 1, + levels, + natras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0, natras->format); if(natras->texture == nil){ RWERROR((ERR_NOTEXTURE)); @@ -445,12 +448,17 @@ rasterCreateCameraTexture(Raster *raster) int32 levels; D3dRaster *natras = GETD3DRASTEREXT(raster); - levels = Raster::calculateNumLevels(raster->width, raster->height); + if(natras->autogenMipmap) + levels = 0; + else if(raster->format & Raster::MIPMAP) + levels = Raster::calculateNumLevels(raster->width, raster->height); + else + levels = 1; IDirect3DTexture9 *tex; d3ddevice->CreateTexture(raster->width, raster->height, - raster->format & Raster::MIPMAP ? levels : 1, - D3DUSAGE_RENDERTARGET, + levels, + (natras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0) | D3DUSAGE_RENDERTARGET, (D3DFORMAT)natras->format, D3DPOOL_DEFAULT, &tex, nil); assert(natras->texture == nil); natras->texture = tex; @@ -467,10 +475,8 @@ static Raster* rasterCreateCamera(Raster *raster) { D3dRaster *natras = GETD3DRASTEREXT(raster); - raster->originalWidth = raster->width; - raster->originalHeight = raster->height; - raster->originalStride = raster->stride = 0; - raster->originalPixels = raster->pixels = nil; + + natras->autogenMipmap = 0; natras->format = d3d9Globals.present.BackBufferFormat; raster->depth = findFormatDepth(natras->format); @@ -483,10 +489,8 @@ static Raster* rasterCreateZbuffer(Raster *raster) { D3dRaster *natras = GETD3DRASTEREXT(raster); - raster->originalWidth = raster->width; - raster->originalHeight = raster->height; - raster->originalStride = raster->stride = 0; - raster->originalPixels = raster->pixels = nil; + + natras->autogenMipmap = 0; // TODO: allow other formats natras->format = d3d9Globals.present.AutoDepthStencilFormat; @@ -518,33 +522,47 @@ rasterCreateZbuffer(Raster *raster) Raster* rasterCreate(Raster *raster) { - D3dRaster *natras = GETD3DRASTEREXT(raster); - rasterSetFormat(raster); + Raster *ret = raster; + if(raster->width == 0 || raster->height == 0){ raster->flags |= Raster::DONTALLOCATE; raster->stride = 0; - return raster; + goto ret; } if(raster->flags & Raster::DONTALLOCATE) - return raster; + goto ret; switch(raster->type){ case Raster::NORMAL: case Raster::TEXTURE: - return rasterCreateTexture(raster); + ret = rasterCreateTexture(raster); + break; #ifdef RW_D3D9 case Raster::CAMERATEXTURE: - return rasterCreateCameraTexture(raster); + ret = rasterCreateCameraTexture(raster); + break; case Raster::ZBUFFER: - return rasterCreateZbuffer(raster); + ret = rasterCreateZbuffer(raster); + break; case Raster::CAMERA: - return rasterCreateCamera(raster); + ret = rasterCreateCamera(raster); + break; #endif + + default: + RWERROR((ERR_INVRASTER)); + return nil; } - return nil; + +ret: + raster->originalWidth = raster->width; + raster->originalHeight = raster->height; + raster->originalStride = raster->stride; + raster->originalPixels = raster->pixels; + return ret; } uint8* @@ -569,7 +587,8 @@ rasterLock(Raster *raster, int32 level, int32 lockMode) case Raster::TEXTURE: { tex->GetSurfaceLevel(level, &surf); natras->lockedSurf = surf; - surf->LockRect(&lr, 0, flags); + HRESULT res = surf->LockRect(&lr, 0, flags); + assert(res == D3D_OK); break; } @@ -583,15 +602,17 @@ rasterLock(Raster *raster, int32 level, int32 lockMode) raster->stride = lr.Pitch; if(raster->width == 0) raster->width = 1; if(raster->height == 0) raster->height = 1; - +#else + RasterLevels *levels = (RasterLevels*)natras->texture; + raster->pixels = levels->levels[level].data; + raster->width = levels->levels[level].width; + raster->height = levels->levels[level].height; + raster->stride = raster->width*natras->bpp; +#endif if(lockMode & Raster::LOCKREAD) raster->privateFlags |= Raster::PRIVATELOCK_READ; if(lockMode & Raster::LOCKWRITE) raster->privateFlags |= Raster::PRIVATELOCK_WRITE; return raster->pixels; -#else - RasterLevels *levels = (RasterLevels*)natras->texture; - return levels->levels[level].data; -#endif } void @@ -701,38 +722,39 @@ rasterFromImage(Raster *raster, Image *image) } D3dRaster *natras = GETD3DRASTEREXT(raster); + int32 format = raster->format&0xF00; switch(image->depth){ case 32: - if(raster->format == Raster::C8888) + if(format == Raster::C8888) conv = conv_BGRA8888_from_RGBA8888; - else if(raster->format == Raster::C888) + else if(format == Raster::C888) conv = conv_BGR888_from_RGB888; else goto err; break; case 24: - if(raster->format == Raster::C8888) + if(format == Raster::C8888) conv = conv_BGRA8888_from_RGB888; - else if(raster->format == Raster::C888) + else if(format == Raster::C888) conv = conv_BGR888_from_RGB888; else goto err; break; case 16: - if(raster->format == Raster::C1555) + if(format == Raster::C1555) conv = conv_ARGB1555_from_ARGB1555; else goto err; break; case 8: - if(raster->format == (Raster::PAL8 | Raster::C8888)) + if(format == (Raster::PAL8 | Raster::C8888)) conv = conv_8_from_8; else goto err; break; case 4: - if(raster->format == (Raster::PAL4 | Raster::C8888) || - raster->format == (Raster::PAL8 | Raster::C8888)) + if(format == (Raster::PAL4 | Raster::C8888) || + format == (Raster::PAL8 | Raster::C8888)) conv = conv_8_from_8; else goto err; @@ -758,7 +780,13 @@ rasterFromImage(Raster *raster, Image *image) } } - uint8 *pixels = raster->lock(0, Raster::LOCKWRITE|Raster::LOCKNOFETCH); + bool unlock = false; + if(raster->pixels == nil){ + raster->lock(0, Raster::LOCKWRITE|Raster::LOCKNOFETCH); + unlock = true; + } + + uint8 *pixels = raster->pixels; assert(pixels); uint8 *imgpixels = image->pixels; @@ -776,7 +804,8 @@ rasterFromImage(Raster *raster, Image *image) imgpixels += image->stride; pixels += raster->stride; } - raster->unlock(0); + if(unlock) + raster->unlock(0); if(truecolimg) truecolimg->destroy(); @@ -789,11 +818,23 @@ rasterToImage(Raster *raster) { int32 depth; Image *image; + + bool unlock = false; + if(raster->pixels == nil){ + raster->lock(0, Raster::LOCKREAD); + unlock = true; + } + D3dRaster *natras = GETD3DRASTEREXT(raster); if(natras->customFormat){ - image = Image::create(raster->width, raster->height, 32); + int w = raster->width; + int h = raster->height; + // pixels are in the upper right corner + if(w < 4) w = 4; + if(h < 4) h = 4; + image = Image::create(w, h, 32); image->allocate(); - uint8 *pix = raster->lock(0, Raster::LOCKREAD); + uint8 *pix = raster->pixels; switch(natras->format){ case D3DFMT_DXT1: image->setPixelsDXT(1, pix); @@ -807,11 +848,17 @@ rasterToImage(Raster *raster) image->setPixelsDXT(5, pix); break; default: - raster->unlock(0); image->destroy(); + if(unlock) + raster->unlock(0); return nil; } - raster->unlock(0); + // fix it up again + image->width = raster->width; + image->height = raster->height; + + if(unlock) + raster->unlock(0); return image; } @@ -865,7 +912,7 @@ rasterToImage(Raster *raster) } uint8 *imgpixels = image->pixels; - uint8 *pixels = raster->lock(0, Raster::LOCKREAD); + uint8 *pixels = raster->pixels; int x, y; assert(image->width == raster->width); @@ -881,10 +928,11 @@ rasterToImage(Raster *raster) imgpixels += image->stride; pixels += raster->stride; } - raster->unlock(0); - image->compressPalette(); + if(unlock) + raster->unlock(0); + return image; } @@ -916,8 +964,16 @@ allocateDXT(Raster *raster, int32 dxt, int32 numLevels, bool32 hasAlpha) D3dRaster *ras = GETD3DRASTEREXT(raster); ras->format = dxtMap[dxt-1]; ras->hasAlpha = hasAlpha; + ras->customFormat = 1; + if(ras->autogenMipmap) + numLevels = 0; + else if(raster->format & Raster::MIPMAP) + {} + else + numLevels = 1; ras->texture = createTexture(raster->width, raster->height, - raster->format & Raster::MIPMAP ? numLevels : 1, + numLevels, + ras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0, ras->format); raster->flags &= ~Raster::DONTALLOCATE; } diff --git a/src/d3d/d3d8.cpp b/src/d3d/d3d8.cpp index d360eb5..de7ae29 100644 --- a/src/d3d/d3d8.cpp +++ b/src/d3d/d3d8.cpp @@ -468,35 +468,54 @@ readAsImage(Stream *stream, int32 width, int32 height, int32 depth, int32 format for(int32 i = 0; i < pallen; i++) palette[i*4+3] = 0xFF; - // Only read one mipmap - for(int32 i = 0; i < numLevels; i++){ - uint32 size = stream->readU32(); - if(i == 0){ - data = rwNewT(uint8, size, MEMDUR_FUNCTION | ID_IMAGE); - stream->read8(data, size); - }else - stream->seek(size); - } + Raster *ras = nil; - if(format & (Raster::PAL4 | Raster::PAL8)){ - uint8 *idx = data; - uint8 *pixels = img->pixels; - for(int y = 0; y < img->height; y++){ - uint8 *line = pixels; - for(int x = 0; x < img->width; x++){ - line[0] = palette[*idx*4+0]; - line[1] = palette[*idx*4+1]; - line[2] = palette[*idx*4+2]; - line[3] = palette[*idx*4+3]; - line += 4; - idx++; - } - pixels += img->stride; + for(int i = 0; i < numLevels; i++){ + if(ras){ + ras->lock(i, Raster::LOCKWRITE|Raster::LOCKNOFETCH); + img->width = ras->width; + img->height = ras->height; + img->stride = img->width*img->bpp; } + + uint32 size = stream->readU32(); + // one allocation is enough, first level is largest + if(data == nil) + data = rwNewT(uint8, size, MEMDUR_FUNCTION | ID_IMAGE); + stream->read8(data, size); + + + if(format & (Raster::PAL4 | Raster::PAL8)){ + uint8 *idx = data; + uint8 *pixels = img->pixels; + for(int y = 0; y < img->height; y++){ + uint8 *line = pixels; + for(int x = 0; x < img->width; x++){ + line[0] = palette[*idx*4+0]; + line[1] = palette[*idx*4+1]; + line[2] = palette[*idx*4+2]; + line[3] = palette[*idx*4+3]; + line += img->bpp; + idx++; + } + pixels += img->stride; + } + } + + if(ras == nil){ + // Important to have filled the image with data + int32 newformat; + Raster::imageFindRasterFormat(img, format&7, &width, &height, &depth, &newformat); + newformat |= format & (Raster::MIPMAP | Raster::AUTOMIPMAP); + ras = Raster::create(width, height, depth, newformat); + ras->lock(i, Raster::LOCKWRITE|Raster::LOCKNOFETCH); + } + + ras->setFromImage(img); + ras->unlock(i); } rwFree(data); - Raster *ras = Raster::createFromImage(img, PLATFORM_D3D8); img->destroy(); return ras; } @@ -545,7 +564,7 @@ readNativeTexture(Stream *stream) Raster *raster; D3dRaster *ras; if(compression){ - raster = Raster::create(width, height, depth, format | type | 0x80, PLATFORM_D3D8); + raster = Raster::create(width, height, depth, format | type | Raster::DONTALLOCATE, PLATFORM_D3D8); ras = GETD3DRASTEREXT(raster); allocateDXT(raster, compression, numLevels, hasAlpha); ras->customFormat = 1; diff --git a/src/d3d/d3d9.cpp b/src/d3d/d3d9.cpp index 7f7bc35..851397b 100644 --- a/src/d3d/d3d9.cpp +++ b/src/d3d/d3d9.cpp @@ -751,6 +751,7 @@ readNativeTexture(Stream *stream) ext->hasAlpha = flags & 1; ext->texture = createTexture(raster->width, raster->height, raster->format & Raster::MIPMAP ? numLevels : 1, + 0, ext->format); assert(ext->texture); raster->flags &= ~Raster::DONTALLOCATE; @@ -811,7 +812,9 @@ writeNativeTexture(Texture *tex, Stream *stream) uint8 flags = 0; if(ext->hasAlpha) flags |= 1; - // no automipmapgen and cube supported yet + // no cube supported yet + if(ext->autogenMipmap) + flags |= 4; if(ext->customFormat) flags |= 8; stream->writeU8(flags); diff --git a/src/d3d/d3ddevice.cpp b/src/d3d/d3ddevice.cpp index 17b1e22..28be314 100644 --- a/src/d3d/d3ddevice.cpp +++ b/src/d3d/d3ddevice.cpp @@ -170,12 +170,16 @@ static uint32 cullmodeMap[] = { D3DCULL_CCW }; -// TODO: support mipmaps -static uint32 filterConvMap_NoMIP[] = { +static uint32 filterConvMap[] = { 0, D3DTEXF_POINT, D3DTEXF_LINEAR, D3DTEXF_POINT, D3DTEXF_LINEAR, D3DTEXF_POINT, D3DTEXF_LINEAR }; +static uint32 filterConvMap_MIP[] = { + 0, D3DTEXF_NONE, D3DTEXF_NONE, + D3DTEXF_POINT, D3DTEXF_POINT, + D3DTEXF_LINEAR, D3DTEXF_LINEAR +}; static uint32 addressConvMap[] = { 0, D3DTADDRESS_WRAP, D3DTADDRESS_MIRROR, D3DTADDRESS_CLAMP, D3DTADDRESS_BORDER @@ -304,8 +308,9 @@ restoreD3d9Device(void) d3ddevice->SetTexture(i, nil); setSamplerState(i, D3DSAMP_ADDRESSU, addressConvMap[rwStateCache.texstage[i].addressingU]); setSamplerState(i, D3DSAMP_ADDRESSV, addressConvMap[rwStateCache.texstage[i].addressingV]); - setSamplerState(i, D3DSAMP_MAGFILTER, filterConvMap_NoMIP[rwStateCache.texstage[i].filter]); - setSamplerState(i, D3DSAMP_MINFILTER, filterConvMap_NoMIP[rwStateCache.texstage[i].filter]); + setSamplerState(i, D3DSAMP_MAGFILTER, filterConvMap[rwStateCache.texstage[i].filter]); + setSamplerState(i, D3DSAMP_MINFILTER, filterConvMap[rwStateCache.texstage[i].filter]); + setSamplerState(i, D3DSAMP_MIPFILTER, filterConvMap_MIP[rwStateCache.texstage[i].filter]); } for(s = 0; s < MAXNUMSTATES; s++) if(validStates[s]) @@ -438,11 +443,11 @@ setRasterStage(uint32 stage, Raster *raster) static void setFilterMode(uint32 stage, int32 filter) { - // TODO: mip mapping if(rwStateCache.texstage[stage].filter != (Texture::FilterMode)filter){ rwStateCache.texstage[stage].filter = (Texture::FilterMode)filter; - setSamplerState(stage, D3DSAMP_MAGFILTER, filterConvMap_NoMIP[filter]); - setSamplerState(stage, D3DSAMP_MINFILTER, filterConvMap_NoMIP[filter]); + setSamplerState(stage, D3DSAMP_MAGFILTER, filterConvMap[filter]); + setSamplerState(stage, D3DSAMP_MINFILTER, filterConvMap[filter]); + setSamplerState(stage, D3DSAMP_MIPFILTER, filterConvMap_MIP[filter]); } } diff --git a/src/d3d/rwd3d.h b/src/d3d/rwd3d.h index 523fe82..34593b6 100644 --- a/src/d3d/rwd3d.h +++ b/src/d3d/rwd3d.h @@ -234,6 +234,9 @@ enum { D3DDECLUSAGE_FOG, // 11 D3DDECLUSAGE_DEPTH, // 12 D3DDECLUSAGE_SAMPLE // 13 + , + + D3DUSAGE_AUTOGENMIPMAP = 0x400 }; #endif @@ -249,7 +252,7 @@ void destroyVertexBuffer(void *vertexBuffer); uint8 *lockVertices(void *vertexBuffer, uint32 offset, uint32 size, uint32 flags); void unlockVertices(void *vertexBuffer); -void *createTexture(int32 width, int32 height, int32 levels, uint32 format); +void *createTexture(int32 width, int32 height, int32 levels, uint32 usage, uint32 format); void destroyTexture(void *texture); uint8 *lockTexture(void *texture, int32 level); void unlockTexture(void *texture, int32 level); @@ -263,8 +266,9 @@ struct D3dRaster void *lockedSurf; uint32 format; uint32 bpp; // bytes per pixel - bool32 hasAlpha; - bool32 customFormat; + bool hasAlpha; + bool customFormat; + bool autogenMipmap; }; int32 getLevelSize(Raster *raster, int32 level); diff --git a/src/d3d/rwxbox.h b/src/d3d/rwxbox.h index fef8284..1abebe1 100644 --- a/src/d3d/rwxbox.h +++ b/src/d3d/rwxbox.h @@ -84,7 +84,9 @@ struct XboxRaster void *texture; void *palette; uint32 format; - bool32 hasAlpha; + uint32 bpp; // bytes per pixel + bool hasAlpha; + bool customFormat; bool32 unknownFlag; }; @@ -92,6 +94,7 @@ int32 getLevelSize(Raster *raster, int32 level); extern int32 nativeRasterOffset; void registerNativeRaster(void); +#define GETXBOXRASTEREXT(raster) PLUGINOFFSET(rw::xbox::XboxRaster, raster, rw::xbox::nativeRasterOffset) Texture *readNativeTexture(Stream *stream); void writeNativeTexture(Texture *tex, Stream *stream); diff --git a/src/d3d/xbox.cpp b/src/d3d/xbox.cpp index 35c065e..83327ba 100644 --- a/src/d3d/xbox.cpp +++ b/src/d3d/xbox.cpp @@ -522,97 +522,137 @@ createTexture(int32 width, int32 height, int32 numlevels, uint32 format) return levels; } +struct RasterFormatInfo +{ + uint32 d3dformat; + int32 depth; + bool32 hasAlpha; + uint32 rwFormat; +}; + +// indexed directly by RW format +static RasterFormatInfo formatInfoRW[16] = { + { 0, 0, 0}, + { D3DFMT_A1R5G5B5, 16, 1, Raster::C1555 }, + { D3DFMT_R5G6B5, 16, 0, Raster::C565 }, + { D3DFMT_A4R4G4B4, 16, 1, Raster::C4444 }, + { D3DFMT_L8, 8, 0, Raster::LUM8 }, + { D3DFMT_A8R8G8B8, 32, 1, Raster::C8888 }, + { D3DFMT_X8R8G8B8, 32, 0, Raster::C888 }, + { D3DFMT_UNKNOWN, 16, 0, Raster::D16 }, + { D3DFMT_UNKNOWN, 32, 0, Raster::D24 }, + { D3DFMT_UNKNOWN, 32, 0, Raster::D32 }, + { D3DFMT_X1R5G5B5, 16, 0, Raster::C555 } +}; + +static void +rasterSetFormat(Raster *raster) +{ + assert(raster->format != 0); // no default yet + + XboxRaster *natras = GETXBOXRASTEREXT(raster); + if(raster->format & (Raster::PAL4 | Raster::PAL8)){ + natras->format = D3DFMT_P8; + raster->depth = 8; + }else{ + natras->format = formatInfoRW[(raster->format >> 8) & 0xF].d3dformat; + raster->depth = formatInfoRW[(raster->format >> 8) & 0xF].depth; + } + natras->bpp = raster->depth/8; + natras->hasAlpha = formatInfoRW[(raster->format >> 8) & 0xF].hasAlpha; + raster->stride = raster->width&natras->bpp; +} + +static Raster* +rasterCreateTexture(Raster *raster) +{ + XboxRaster *natras = GETXBOXRASTEREXT(raster); + int32 levels; + + if(natras->format == D3DFMT_P8) + natras->palette = (uint8*)rwNew(4*256, MEMDUR_EVENT | ID_DRIVER); + levels = Raster::calculateNumLevels(raster->width, raster->height); + assert(natras->texture == nil); + natras->texture = createTexture(raster->width, raster->height, + raster->format & Raster::MIPMAP ? levels : 1, + natras->format); + if(natras->texture == nil){ + RWERROR((ERR_NOTEXTURE)); + return nil; + } + return raster; +} + Raster* rasterCreate(Raster *raster) { - static uint32 formatMap[] = { - D3DFMT_UNKNOWN, - D3DFMT_A1R5G5B5, - D3DFMT_R5G6B5, - D3DFMT_A4R4G4B4, - D3DFMT_L8, - D3DFMT_A8R8G8B8, - D3DFMT_X8R8G8B8, - D3DFMT_UNKNOWN, - D3DFMT_UNKNOWN, - D3DFMT_UNKNOWN, - D3DFMT_X1R5G5B5, - D3DFMT_UNKNOWN, - D3DFMT_UNKNOWN, - D3DFMT_UNKNOWN, - D3DFMT_UNKNOWN, - D3DFMT_UNKNOWN - }; - static bool32 alphaMap[] = { - 0, - 1, - 0, - 1, - 0, - 1, - 0, - 0, 0, 0, - 0, - 0, 0, 0, 0, 0 - }; + rasterSetFormat(raster); - XboxRaster *natras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); - uint32 format; - int32 levels; + Raster *ret = raster; // Dummy to use as subraster if(raster->width == 0 || raster->height == 0){ raster->flags |= Raster::DONTALLOCATE; raster->stride = 0; - return raster; + goto ret; } + if(raster->flags & Raster::DONTALLOCATE) + goto ret; switch(raster->type){ case Raster::NORMAL: case Raster::TEXTURE: - if(raster->flags & Raster::DONTALLOCATE) - return raster; - if(raster->format & (Raster::PAL4 | Raster::PAL8)){ - format = D3DFMT_P8; - natras->palette = (uint8*)rwNew(4*256, MEMDUR_EVENT | ID_DRIVER); - }else - format = formatMap[(raster->format >> 8) & 0xF]; - natras->format = 0; - natras->hasAlpha = alphaMap[(raster->format >> 8) & 0xF]; - levels = Raster::calculateNumLevels(raster->width, raster->height); - natras->texture = createTexture(raster->width, raster->height, - raster->format & Raster::MIPMAP ? levels : 1, - format); - if(natras->texture == nil){ - RWERROR((ERR_NOTEXTURE)); - return nil; - } - return raster; + ret = rasterCreateTexture(raster); + break; + default: + RWERROR((ERR_INVRASTER)); + return nil; } - // unsupported - return nil; + +ret: + raster->originalWidth = raster->width; + raster->originalHeight = raster->height; + raster->originalStride = raster->stride; + raster->originalPixels = raster->pixels; + return ret; } uint8* rasterLock(Raster *raster, int32 level, int32 lockMode) { - // TODO? - (void)lockMode; + XboxRaster *natras = GETXBOXRASTEREXT(raster); + + // check if already locked + if(raster->privateFlags & (Raster::PRIVATELOCK_READ|Raster::PRIVATELOCK_WRITE)) + return nil; - XboxRaster *natras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); RasterLevels *levels = (RasterLevels*)natras->texture; - return levels->levels[level].data; + raster->pixels = levels->levels[level].data; + raster->width = levels->levels[level].width; + raster->height = levels->levels[level].height; + raster->stride = raster->width*natras->bpp; + + if(lockMode & Raster::LOCKREAD) raster->privateFlags |= Raster::PRIVATELOCK_READ; + if(lockMode & Raster::LOCKWRITE) raster->privateFlags |= Raster::PRIVATELOCK_WRITE; + + return raster->pixels; } void -rasterUnlock(Raster*, int32) +rasterUnlock(Raster *raster, int32 level) { + raster->width = raster->originalWidth; + raster->height = raster->originalHeight; + raster->stride = raster->originalStride; + raster->pixels = raster->originalPixels; + + raster->privateFlags &= ~(Raster::PRIVATELOCK_READ|Raster::PRIVATELOCK_WRITE); } int32 rasterNumLevels(Raster *raster) { - XboxRaster *natras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); + XboxRaster *natras = GETXBOXRASTEREXT(raster); RasterLevels *levels = (RasterLevels*)natras->texture; return levels->numlevels; } @@ -656,12 +696,23 @@ rasterToImage(Raster *raster) { int32 depth; Image *image; - XboxRaster *natras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); - if(natras->format){ - image = Image::create(raster->width, raster->height, 32); + bool unlock = false; + if(raster->pixels == nil){ + raster->lock(0, Raster::LOCKREAD); + unlock = true; + } + + XboxRaster *natras = GETXBOXRASTEREXT(raster); + if(natras->customFormat){ + int w = raster->width; + int h = raster->height; + // pixels are in the upper right corner + if(w < 4) w = 4; + if(h < 4) h = 4; + image = Image::create(w, h, 32); image->allocate(); - uint8 *pix = raster->lock(0, Raster::LOCKREAD); + uint8 *pix = raster->pixels; switch(natras->format){ case D3DFMT_DXT1: image->setPixelsDXT(1, pix); @@ -677,11 +728,17 @@ rasterToImage(Raster *raster) break; default: assert(0 && "unknown format"); - raster->unlock(0); image->destroy(); + if(unlock) + raster->unlock(0); return nil; } - raster->unlock(0); + // fix it up again + image->width = raster->width; + image->height = raster->height; + + if(unlock) + raster->unlock(0); return image; } @@ -714,48 +771,51 @@ rasterToImage(Raster *raster) pallength = 256; } - uint8 *in, *out; image = Image::create(raster->width, raster->height, depth); image->allocate(); if(pallength){ - out = image->palette; - in = (uint8*)natras->palette; + uint8 *out = image->palette; + uint8 *in = (uint8*)natras->palette; + // bytes are BGRA unlike regular d3d! for(int32 i = 0; i < pallength; i++){ - out[0] = in[2]; - out[1] = in[1]; - out[2] = in[0]; - out[3] = in[3]; + conv_BGRA8888_from_RGBA8888(out, in); in += 4; out += 4; } } - out = image->pixels; - in = raster->lock(0, Raster::LOCKREAD); + uint8 *imgpixels = image->pixels; + uint8 *pixels = raster->pixels; - unswizzle(out, in, image->width, image->height, depth < 8 ? 1 : depth/8); + // NB: + assert(image->bpp == natras->bpp); + assert(image->stride == raster->stride); + unswizzle(imgpixels, pixels, image->width, image->height, image->bpp); // Fix RGB order - // TODO: stride uint8 tmp; if(depth > 8) - for(int32 y = 0; y < image->height; y++) - for(int32 x = 0; x < image->width; x++) + for(int32 y = 0; y < image->height; y++){ + uint8 *imgrow = imgpixels; + // uint8 *rasrow = pixels; + for(int32 x = 0; x < image->width; x++){ switch(raster->format & 0xF00){ case Raster::C8888: - tmp = out[0]; - out[0] = out[2]; - out[2] = tmp; - out += 4; - break; case Raster::C888: - tmp = out[0]; - out[0] = out[2]; - out[2] = tmp; - out += 3; + tmp = imgrow[0]; + imgrow[0] = imgrow[2]; + imgrow[2] = tmp; + imgrow += image->bpp; break; } - raster->unlock(0); + } + imgpixels += image->stride; + // pixels += raster->stride; + } + image->compressPalette(); + + if(unlock) + raster->unlock(0); return image; } @@ -763,7 +823,7 @@ rasterToImage(Raster *raster) int32 getLevelSize(Raster *raster, int32 level) { - XboxRaster *ras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); + XboxRaster *ras = GETXBOXRASTEREXT(raster); RasterLevels *levels = (RasterLevels*)ras->texture; return levels->levels[level].size; } @@ -776,6 +836,7 @@ createNativeRaster(void *object, int32 offset, int32) raster->palette = nil; raster->format = 0; raster->hasAlpha = 0; + raster->customFormat = 0; raster->unknownFlag = 0; return object; } @@ -836,6 +897,9 @@ readNativeTexture(Stream *stream) stream->read8(tex->name, 32); stream->read8(tex->mask, 32); +//if(strcmp(tex->name, "bluallu") == 0) +//__debugbreak(); + // Raster int32 format = stream->readI32(); bool32 hasAlpha = stream->readI16(); @@ -853,16 +917,17 @@ readNativeTexture(Stream *stream) Raster *raster; if(compression){ raster = Raster::create(width, height, depth, format | type | Raster::DONTALLOCATE, PLATFORM_XBOX); - XboxRaster *ras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); + XboxRaster *ras = GETXBOXRASTEREXT(raster); ras->format = compression; ras->hasAlpha = hasAlpha; ras->texture = createTexture(raster->width, raster->height, raster->format & Raster::MIPMAP ? numLevels : 1, ras->format); + ras->customFormat = 1; raster->flags &= ~Raster::DONTALLOCATE; }else raster = Raster::create(width, height, depth, format | type, PLATFORM_XBOX); - XboxRaster *ras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); + XboxRaster *ras = GETXBOXRASTEREXT(raster); tex->raster = raster; if(raster->format & Raster::PAL4) @@ -892,7 +957,7 @@ writeNativeTexture(Texture *tex, Stream *stream) // Raster Raster *raster = tex->raster; - XboxRaster *ras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); + XboxRaster *ras = GETXBOXRASTEREXT(raster); int32 numLevels = raster->getNumLevels(); stream->writeI32(raster->format); stream->writeI16(ras->hasAlpha); diff --git a/src/gl/gl3device.cpp b/src/gl/gl3device.cpp index de26f8b..13792b8 100644 --- a/src/gl/gl3device.cpp +++ b/src/gl/gl3device.cpp @@ -260,6 +260,8 @@ static uint32 blendMap[] = { GL_SRC_ALPHA_SATURATE, }; +static float maxAnisotropy; + /* * GL state cache */ @@ -434,12 +436,16 @@ bindFramebuffer(uint32 fbo) } } -// TODO: support mipmaps static GLint filterConvMap_NoMIP[] = { 0, GL_NEAREST, GL_LINEAR, GL_NEAREST, GL_LINEAR, GL_NEAREST, GL_LINEAR }; +static GLint filterConvMap_MIP[] = { + 0, GL_NEAREST, GL_LINEAR, + GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST, + GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR +}; static GLint addressConvMap[] = { 0, GL_REPEAT, GL_MIRRORED_REPEAT, @@ -456,8 +462,13 @@ setFilterMode(uint32 stage, int32 filter) Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, rwStateCache.texstage[stage].raster, nativeRasterOffset); if(natras->filterMode != filter){ setActiveTexture(stage); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterConvMap_NoMIP[filter]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterConvMap_NoMIP[filter]); + if(natras->autogenMipmap || natras->numLevels > 1){ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterConvMap_MIP[filter]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterConvMap_MIP[filter]); + }else{ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterConvMap_NoMIP[filter]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterConvMap_NoMIP[filter]); + } natras->filterMode = filter; } } @@ -547,8 +558,13 @@ setRasterStage(uint32 stage, Raster *raster) uint32 addrU = rwStateCache.texstage[stage].addressingU; uint32 addrV = rwStateCache.texstage[stage].addressingV; if(natras->filterMode != filter){ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterConvMap_NoMIP[filter]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterConvMap_NoMIP[filter]); + if(natras->autogenMipmap || natras->numLevels > 1){ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterConvMap_MIP[filter]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterConvMap_MIP[filter]); + }else{ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterConvMap_NoMIP[filter]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterConvMap_NoMIP[filter]); + } natras->filterMode = filter; } if(natras->addressU != addrU){ @@ -1521,6 +1537,8 @@ initOpenGL(void) resetRenderState(); + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy); + #ifndef RW_GLES2 glGenVertexArrays(1, &vao); glBindVertexArray(vao); diff --git a/src/gl/gl3raster.cpp b/src/gl/gl3raster.cpp index 6e8cecc..2298fdd 100644 --- a/src/gl/gl3raster.cpp +++ b/src/gl/gl3raster.cpp @@ -22,10 +22,50 @@ namespace gl3 { int32 nativeRasterOffset; +static uint32 +getLevelSize(Raster *raster, int32 level) +{ + int i; + Gl3Raster *natras = GETGL3RASTEREXT(raster); + + int w = raster->originalWidth; + int h = raster->originalHeight; + int s = raster->originalStride; + int minDim = 1; + #ifdef RW_OPENGL + switch(natras->internalFormat){ + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + minDim = 4; + break; + } +#endif + + for(i = 0; i < level; i++){ + if(w > minDim){ + w /= 2; + s /= 2; + } + if(h > minDim) + h /= 2; + } + + return s*h; +} + +#ifdef RW_OPENGL + static Raster* rasterCreateTexture(Raster *raster) { + if(raster->format & (Raster::PAL4 | Raster::PAL8)){ + RWERROR((ERR_NOTEXTURE)); + return nil; + } + Gl3Raster *natras = GETGL3RASTEREXT(raster); switch(raster->format & 0xF00){ case Raster::C8888: @@ -65,19 +105,36 @@ rasterCreateTexture(Raster *raster) natras->bpp = 4; #endif - natras->isCompressed = 0; - raster->stride = raster->width*natras->bpp; + if(raster->format & Raster::MIPMAP){ + int w = raster->width; + int h = raster->height; + natras->numLevels = 0; + while(w != 1 || h != 1){ + natras->numLevels++; + if(w > 1) w /= 2; + if(h > 1) h /= 2; + } + } + natras->autogenMipmap = (raster->format & (Raster::MIPMAP|Raster::AUTOMIPMAP)) == (Raster::MIPMAP|Raster::AUTOMIPMAP); + if(natras->autogenMipmap) + natras->numLevels = 1; + glGenTextures(1, &natras->texid); uint32 prev = bindTexture(natras->texid); glTexImage2D(GL_TEXTURE_2D, 0, natras->internalFormat, raster->width, raster->height, 0, natras->format, natras->type, nil); + // TODO: allocate other levels...probably + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, natras->numLevels-1); natras->filterMode = 0; natras->addressU = 0; natras->addressV = 0; +// TEST +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f); + bindTexture(prev); return raster; } @@ -125,10 +182,10 @@ rasterCreateCameraTexture(Raster *raster) // natras->bpp = 4; #endif - natras->isCompressed = 0; - raster->stride = raster->width*natras->bpp; + natras->autogenMipmap = (raster->format & (Raster::MIPMAP|Raster::AUTOMIPMAP)) == (Raster::MIPMAP|Raster::AUTOMIPMAP); + glGenTextures(1, &natras->texid); uint32 prev = bindTexture(natras->texid); glTexImage2D(GL_TEXTURE_2D, 0, natras->internalFormat, @@ -156,10 +213,8 @@ rasterCreateCamera(Raster *raster) Gl3Raster *natras = GETGL3RASTEREXT(raster); // TODO: set/check width, height, depth, format? - raster->originalWidth = raster->width; - raster->originalHeight = raster->height; - raster->stride = 0; - raster->pixels = nil; + + natras->autogenMipmap = 0; natras->texid = 0; natras->fbo = 0; @@ -174,16 +229,12 @@ rasterCreateZbuffer(Raster *raster) Gl3Raster *natras = GETGL3RASTEREXT(raster); // TODO: set/check width, height, depth, format? - raster->originalWidth = raster->width; - raster->originalHeight = raster->height; - raster->stride = 0; - raster->pixels = nil; natras->internalFormat = GL_DEPTH_COMPONENT; natras->format = GL_DEPTH_COMPONENT; natras->type = GL_UNSIGNED_BYTE; - natras->isCompressed = 0; + natras->autogenMipmap = 0; glGenTextures(1, &natras->texid); uint32 prev = bindTexture(natras->texid); @@ -202,8 +253,75 @@ rasterCreateZbuffer(Raster *raster) return raster; } + #endif + +void +allocateDXT(Raster *raster, int32 dxt, int32 numLevels, bool32 hasAlpha) +{ +#ifdef RW_OPENGL + assert(raster->type == Raster::TEXTURE); + + Gl3Raster *natras = GETGL3RASTEREXT(raster); + switch(dxt){ + case 1: + if(hasAlpha){ + natras->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + natras->format = GL_RGBA; + }else{ + natras->internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + natras->format = GL_RGB; + } + // bogus, but stride*height should be the size of the image + // 4x4 in 8 bytes + raster->stride = raster->width/2; + break; + case 3: + natras->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + natras->format = GL_RGBA; + // 4x4 in 16 bytes + raster->stride = raster->width; + break; + case 5: + natras->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + natras->format = GL_RGBA; + // 4x4 in 16 bytes + raster->stride = raster->width; + break; + default: + assert(0 && "invalid DXT format"); + } + natras->type = GL_UNSIGNED_BYTE; + natras->hasAlpha = hasAlpha; + natras->bpp = 2; + raster->depth = 16; + + natras->isCompressed = 1; + if(raster->format & Raster::MIPMAP) + natras->numLevels = numLevels; + natras->autogenMipmap = (raster->format & (Raster::MIPMAP|Raster::AUTOMIPMAP)) == (Raster::MIPMAP|Raster::AUTOMIPMAP); + if(natras->autogenMipmap) + natras->numLevels = 1; + + glGenTextures(1, &natras->texid); + uint32 prev = bindTexture(natras->texid); + glTexImage2D(GL_TEXTURE_2D, 0, natras->internalFormat, + raster->width, raster->height, + 0, natras->format, natras->type, nil); + // TODO: allocate other levels...probably + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, natras->numLevels-1); + natras->filterMode = 0; + natras->addressU = 0; + natras->addressV = 0; + + bindTexture(prev); + + raster->originalStride = raster->stride; + raster->flags &= ~Raster::DONTALLOCATE; +#endif +} + /* { 0, 0, 0 }, { 16, 4, GL_RGBA }, // 1555 @@ -233,31 +351,50 @@ GL_RGB5 Raster* rasterCreate(Raster *raster) { + Gl3Raster *natras = GETGL3RASTEREXT(raster); + + natras->isCompressed = 0; + natras->hasAlpha = 0; + natras->numLevels = 1; + + Raster *ret = raster; + if(raster->width == 0 || raster->height == 0){ raster->flags |= Raster::DONTALLOCATE; raster->stride = 0; - return raster; + goto ret; } if(raster->flags & Raster::DONTALLOCATE) - return raster; + goto ret; switch(raster->type){ #ifdef RW_OPENGL case Raster::NORMAL: case Raster::TEXTURE: - return rasterCreateTexture(raster); + ret = rasterCreateTexture(raster); + break; case Raster::CAMERATEXTURE: - return rasterCreateCameraTexture(raster); + ret = rasterCreateCameraTexture(raster); + break; case Raster::ZBUFFER: - return rasterCreateZbuffer(raster); + ret = rasterCreateZbuffer(raster); + break; case Raster::CAMERA: - return rasterCreateCamera(raster); + ret = rasterCreateCamera(raster); + break; #endif default: RWERROR((ERR_INVRASTER)); return nil; } + +ret: + raster->originalWidth = raster->width; + raster->originalHeight = raster->height; + raster->originalStride = raster->stride; + raster->originalPixels = raster->pixels; + return ret; } uint8* @@ -266,6 +403,7 @@ rasterLock(Raster *raster, int32 level, int32 lockMode) #ifdef RW_OPENGL Gl3Raster *natras GETGL3RASTEREXT(raster); uint8 *px; + int i; assert(raster->privateFlags == 0); @@ -273,7 +411,16 @@ rasterLock(Raster *raster, int32 level, int32 lockMode) case Raster::NORMAL: case Raster::TEXTURE: case Raster::CAMERATEXTURE: - px = (uint8*)rwMalloc(raster->stride*raster->height, MEMDUR_EVENT | ID_DRIVER); + for(i = 0; i < level; i++){ + if(raster->width > 1){ + raster->width /= 2; + raster->stride /= 2; + } + if(raster->height > 1) + raster->height /= 2; + } + + px = (uint8*)rwMalloc(getLevelSize(raster, level), MEMDUR_EVENT | ID_DRIVER); assert(raster->pixels == nil); raster->pixels = px; @@ -297,6 +444,7 @@ assert(natras->format == GL_RGBA); glDeleteFramebuffers(1, &fbo); #else uint32 prev = bindTexture(natras->texid); + glPixelStorei(GL_PACK_ALIGNMENT, 1); glGetTexImage(GL_TEXTURE_2D, level, natras->format, natras->type, px); bindTexture(prev); #endif @@ -328,28 +476,35 @@ rasterUnlock(Raster *raster, int32 level) if(raster->privateFlags & Raster::LOCKWRITE){ uint32 prev = bindTexture(natras->texid); if(natras->isCompressed) - glCompressedTexImage2D(GL_TEXTURE_2D, 0, natras->internalFormat, + glCompressedTexImage2D(GL_TEXTURE_2D, level, natras->internalFormat, raster->width, raster->height, 0, - raster->stride*raster->height, + getLevelSize(raster, level), raster->pixels); - else + else{ + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, level, natras->internalFormat, raster->width, raster->height, 0, natras->format, natras->type, raster->pixels); + } + if(level == 0 && natras->autogenMipmap) + glGenerateMipmap(GL_TEXTURE_2D); bindTexture(prev); } rwFree(raster->pixels); raster->pixels = nil; - raster->privateFlags = 0; #endif + raster->width = raster->originalWidth; + raster->height = raster->originalHeight; + raster->stride = raster->originalStride; + raster->pixels = raster->originalPixels; + raster->privateFlags = 0; } int32 -rasterNumLevels(Raster*) +rasterNumLevels(Raster *raster) { - // TODO - return 1; + return GETGL3RASTEREXT(raster)->numLevels; } // Almost the same as d3d9 and ps2 function @@ -425,14 +580,16 @@ rasterFromImage(Raster *raster, Image *image) } Gl3Raster *natras = GETGL3RASTEREXT(raster); + int32 format = raster->format&0xF00; + assert(!natras->isCompressed); switch(image->depth){ case 32: #ifdef RW_GLES conv = conv_RGBA8888_from_RGBA8888; #else - if(raster->format == Raster::C8888) + if(format == Raster::C8888) conv = conv_RGBA8888_from_RGBA8888; - else if(raster->format == Raster::C888) + else if(format == Raster::C888) conv = conv_RGB888_from_RGB888; else goto err; @@ -442,9 +599,9 @@ rasterFromImage(Raster *raster, Image *image) #ifdef RW_GLES conv = conv_RGBA8888_from_RGB888; #else - if(raster->format == Raster::C8888) + if(format == Raster::C8888) conv = conv_RGBA8888_from_RGB888; - else if(raster->format == Raster::C888) + else if(format == Raster::C888) conv = conv_RGB888_from_RGB888; else goto err; @@ -454,7 +611,7 @@ rasterFromImage(Raster *raster, Image *image) #ifdef RW_GLES conv = conv_RGBA8888_from_ARGB1555; #else - if(raster->format == Raster::C1555) + if(format == Raster::C1555) conv = conv_RGBA5551_from_ARGB1555; else goto err; @@ -471,7 +628,13 @@ rasterFromImage(Raster *raster, Image *image) natras->hasAlpha = image->hasAlpha(); - uint8 *pixels = raster->lock(0, Raster::LOCKWRITE|Raster::LOCKNOFETCH); + bool unlock = false; + if(raster->pixels == nil){ + raster->lock(0, Raster::LOCKWRITE|Raster::LOCKNOFETCH); + unlock = true; + } + + uint8 *pixels = raster->pixels; assert(pixels); uint8 *imgpixels = image->pixels + (image->height-1)*image->stride; @@ -489,7 +652,8 @@ rasterFromImage(Raster *raster, Image *image) imgpixels -= image->stride; pixels += raster->stride; } - raster->unlock(0); + if(unlock) + raster->unlock(0); if(truecolimg) truecolimg->destroy(); @@ -497,61 +661,6 @@ rasterFromImage(Raster *raster, Image *image) return 1; } -void -allocateDXT(Raster *raster, int32 dxt, int32 numLevels, bool32 hasAlpha) -{ -#ifdef RW_OPENGL - Gl3Raster *natras = GETGL3RASTEREXT(raster); - switch(dxt){ - case 1: - if(hasAlpha){ - natras->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - natras->format = GL_RGBA; - }else{ - natras->internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; - natras->format = GL_RGB; - } - // bogus, but stride*height should be the size of the image - // 4x4 in 8 bytes - raster->stride = raster->width/2; - break; - case 3: - natras->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - natras->format = GL_RGBA; - // 4x4 in 16 bytes - raster->stride = raster->width; - break; - case 5: - natras->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - natras->format = GL_RGBA; - // 4x4 in 16 bytes - raster->stride = raster->width; - break; - default: - assert(0 && "invalid DXT format"); - } - natras->type = GL_UNSIGNED_BYTE; - natras->hasAlpha = hasAlpha; - natras->bpp = 2; - raster->depth = 16; - - natras->isCompressed = 1; - - glGenTextures(1, &natras->texid); - uint32 prev = bindTexture(natras->texid); - glTexImage2D(GL_TEXTURE_2D, 0, natras->internalFormat, - raster->width, raster->height, - 0, natras->format, natras->type, nil); - natras->filterMode = 0; - natras->addressU = 0; - natras->addressV = 0; - - bindTexture(prev); - - raster->flags &= ~Raster::DONTALLOCATE; -#endif -} - static void* createNativeRaster(void *object, int32 offset, int32) { @@ -624,16 +733,6 @@ copyNativeRaster(void *dst, void *, int32 offset, int32) return dst; } -static uint32 -getLevelSize(Raster *raster, int32 level) -{ - Gl3Raster *natras = GETGL3RASTEREXT(raster); - uint32 size = raster->stride*raster->height; - while(level--) - size /= 4; - return size; -} - Texture* readNativeTexture(Stream *stream) { @@ -683,12 +782,9 @@ readNativeTexture(Stream *stream) uint8 *data; for(int32 i = 0; i < numLevels; i++){ size = stream->readU32(); - if(i < raster->getNumLevels()){ - data = raster->lock(i, Raster::LOCKWRITE|Raster::LOCKNOFETCH); - stream->read8(data, size); - raster->unlock(i); - }else - stream->seek(size); + data = raster->lock(i, Raster::LOCKWRITE|Raster::LOCKNOFETCH); + stream->read8(data, size); + raster->unlock(i); } return tex; } @@ -709,7 +805,7 @@ writeNativeTexture(Texture *tex, Stream *stream) stream->write8(tex->mask, 32); // Raster - int32 numLevels = raster->getNumLevels(); + int32 numLevels = natras->numLevels; stream->writeI32(raster->format); stream->writeI32(raster->width); stream->writeI32(raster->height); @@ -758,7 +854,7 @@ writeNativeTexture(Texture *tex, Stream *stream) uint32 getSizeNativeTexture(Texture *tex) { - uint32 size = 12 + 72 + 20; + uint32 size = 12 + 72 + 28; int32 levels = tex->raster->getNumLevels(); for(int32 i = 0; i < levels; i++) size += 4 + getLevelSize(tex->raster, i); diff --git a/src/gl/rwgl3.h b/src/gl/rwgl3.h index 7c01f9b..fd62541 100644 --- a/src/gl/rwgl3.h +++ b/src/gl/rwgl3.h @@ -233,8 +233,10 @@ struct Gl3Raster // texture object uint32 texid; - bool32 isCompressed; - bool32 hasAlpha; + bool isCompressed; + bool hasAlpha; + bool autogenMipmap; + int8 numLevels; // cached filtermode and addressing uint8 filterMode; uint8 addressU; diff --git a/src/image.cpp b/src/image.cpp index ce071b5..8132ddf 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -163,8 +163,8 @@ decompressDXT1(uint8 *adst, int32 w, int32 h, uint8 *src) } /* write bytes */ - for(uint32 k = 0; k < 4; k++) - for(uint32 l = 0; l < 4; l++){ + for(uint32 l = 0; l < 4; l++) + for(uint32 k = 0; k < 4; k++){ dst[(y+l)*w + x+k][0] = c[idx[l*4+k]][0]; dst[(y+l)*w + x+k][1] = c[idx[l*4+k]][1]; dst[(y+l)*w + x+k][2] = c[idx[l*4+k]][2]; @@ -221,8 +221,8 @@ decompressDXT3(uint8 *adst, int32 w, int32 h, uint8 *src) } /* write bytes */ - for(uint32 k = 0; k < 4; k++) - for(uint32 l = 0; l < 4; l++){ + for(uint32 l = 0; l < 4; l++) + for(uint32 k = 0; k < 4; k++){ dst[(y+l)*w + x+k][0] = c[idx[l*4+k]][0]; dst[(y+l)*w + x+k][1] = c[idx[l*4+k]][1]; dst[(y+l)*w + x+k][2] = c[idx[l*4+k]][2]; @@ -308,8 +308,8 @@ decompressDXT5(uint8 *adst, int32 w, int32 h, uint8 *src) } /* write bytes */ - for(uint32 k = 0; k < 4; k++) - for(uint32 l = 0; l < 4; l++){ + for(uint32 l = 0; l < 4; l++) + for(uint32 k = 0; k < 4; k++){ dst[(y+l)*w + x+k][0] = c[idx[l*4+k]][0]; dst[(y+l)*w + x+k][1] = c[idx[l*4+k]][1]; dst[(y+l)*w + x+k][2] = c[idx[l*4+k]][2]; @@ -341,6 +341,22 @@ flipBlock(uint8 *dst, uint8 *src) dst[7] = src[4]; } +// flip top 2 rows of a DXT 2-bit block +static void +flipBlock_half(uint8 *dst, uint8 *src) +{ + // color + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + // bits + dst[4] = src[5]; + dst[5] = src[4]; + dst[6] = src[6]; + dst[7] = src[7]; +} + // flip a DXT3 4-bit alpha block static void flipAlphaBlock3(uint8 *dst, uint8 *src) @@ -355,6 +371,20 @@ flipAlphaBlock3(uint8 *dst, uint8 *src) dst[1] = src[7]; } +// flip top 2 rows of a DXT3 4-bit alpha block +static void +flipAlphaBlock3_half(uint8 *dst, uint8 *src) +{ + dst[0] = src[2]; + dst[1] = src[3]; + dst[2] = src[0]; + dst[3] = src[1]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +} + // flip a DXT5 3-bit alpha block static void flipAlphaBlock5(uint8 *dst, uint8 *src) @@ -370,17 +400,45 @@ flipAlphaBlock5(uint8 *dst, uint8 *src) flipbits |= bits & 0xFFF; bits >>= 12; } - memcpy(src+2, &flipbits, 6); + memcpy(dst+2, &flipbits, 6); +} + +// flip top 2 rows of a DXT5 3-bit alpha block +static void +flipAlphaBlock5_half(uint8 *dst, uint8 *src) +{ + // color + dst[0] = src[0]; + dst[1] = src[1]; + // bits + uint64 bits = *(uint64*)&src[2]; + uint64 flipbits = bits & 0xFFFFFF000000; + flipbits |= (bits>>12) & 0xFFF; + flipbits |= (bits<<12) & 0xFFF000; + memcpy(dst+2, &flipbits, 6); } void flipDXT1(uint8 *dst, uint8 *src, uint32 width, uint32 height) { int x, y; - assert(width % 4 == 0); - assert(height % 4 == 0); - int bw = width/4; - int bh = height/4; + int bw = (width+3)/4; + int bh = (height+3)/4; + if(height < 4){ + // used pixels are always at the top + // so don't swap the full 4 rows + if(height == 2){ + uint8 *s = src; + uint8 *d = dst; + for(x = 0; x < bw; x++){ + flipBlock_half(dst, src); + s += 8; + d += 8; + } + }else + memcpy(dst, src, 8*bw); + return; + } dst += 8*bw*bh; for(y = 0; y < bh; y++){ dst -= 8*bw; @@ -399,10 +457,24 @@ void flipDXT3(uint8 *dst, uint8 *src, uint32 width, uint32 height) { int x, y; - assert(width % 4 == 0); - assert(height % 4 == 0); - int bw = width/4; - int bh = height/4; + int bw = (width+3)/4; + int bh = (height+3)/4; + if(height < 4){ + // used pixels are always at the top + // so don't swap the full 4 rows + if(height == 2){ + uint8 *s = src; + uint8 *d = dst; + for(x = 0; x < bw; x++){ + flipAlphaBlock3_half(d, s); + flipBlock_half(d+8, s+8); + s += 16; + d += 16; + } + }else + memcpy(dst, src, 16*bw); + return; + } dst += 16*bw*bh; for(y = 0; y < bh; y++){ dst -= 16*bw; @@ -422,10 +494,24 @@ void flipDXT5(uint8 *dst, uint8 *src, uint32 width, uint32 height) { int x, y; - assert(width % 4 == 0); - assert(height % 4 == 0); - int bw = width/4; - int bh = height/4; + int bw = (width+3)/4; + int bh = (height+3)/4; + if(height < 4){ + // used pixels are always at the top + // so don't swap the full 4 rows + if(height == 2){ + uint8 *s = src; + uint8 *d = dst; + for(x = 0; x < bw; x++){ + flipAlphaBlock5_half(d, s); + flipBlock_half(d+8, s+8); + s += 16; + d += 16; + } + }else + memcpy(dst, src, 16*bw); + return; + } dst += 16*bw*bh; for(y = 0; y < bh; y++){ dst -= 16*bw; diff --git a/src/plg.cpp b/src/plg.cpp index 4c757c8..c5c3782 100644 --- a/src/plg.cpp +++ b/src/plg.cpp @@ -95,6 +95,13 @@ PluginList::streamRead(Stream *stream, void *object) cont: length -= header.length; } + + // now the always callbacks + FORLIST(lnk, this->plugins){ + Plugin *p = PLG(lnk); + if(p->alwaysCallback) + p->alwaysCallback(object, p->offset, p->size); + } return true; } @@ -176,6 +183,7 @@ PluginList::registerPlugin(int32 size, uint32 id, p->write = nil; p->getSize = nil; p->rightsCallback = nil; + p->alwaysCallback = nil; p->parentList = this; this->plugins.add(&p->inParentList); allPlugins.add(&p->inGlobalList); @@ -211,6 +219,19 @@ PluginList::setStreamRightsCallback(uint32 id, RightsCallback cb) return -1; } +int32 +PluginList::setStreamAlwaysCallback(uint32 id, AlwaysCallback cb) +{ + FORLIST(lnk, this->plugins){ + Plugin *p = PLG(lnk); + if(p->id == id){ + p->alwaysCallback = cb; + return p->offset; + } + } + return -1; +} + int32 PluginList::getPluginOffset(uint32 id) { diff --git a/src/raster.cpp b/src/raster.cpp index 183ec6b..021855f 100644 --- a/src/raster.cpp +++ b/src/raster.cpp @@ -10,10 +10,11 @@ #include "rwobjects.h" #include "rwengine.h" //#include "ps2/rwps2.h" -//#include "d3d/rwd3d.h" -//#include "d3d/rwxbox.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 @@ -71,6 +72,7 @@ Raster::create(int32 width, int32 height, int32 depth, int32 format, int32 platf raster->width = width; raster->height = height; raster->depth = depth; + raster->stride = 0; raster->pixels = raster->palette = nil; s_plglist.construct(raster); @@ -371,4 +373,176 @@ copyPal8(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, in } + +// Platform conversion + +static rw::Raster* +xbox_to_d3d(rw::Raster *ras) +{ +#ifdef RW_D3D9 + 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; +#else + return nil; +#endif +} + +static rw::Raster* +d3d_to_gl3(rw::Raster *ras) +{ +#ifdef RW_GL3 + using namespace rw; + + 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; +} + + } diff --git a/src/rwobjects.h b/src/rwobjects.h index bf83cbd..622b376 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -268,6 +268,7 @@ struct Raster static Raster *getCurrentContext(void); bool32 renderFast(int32 x, int32 y); + static Raster *convertTexToCurrentPlatform(Raster *ras); #ifndef RWPUBLIC static void registerModule(void); #endif @@ -337,9 +338,6 @@ void expandPal4_BE(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, i void compressPal4_BE(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h); void copyPal8(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h); -void flipDXT1(uint8 *dst, uint8 *src, uint32 width, uint32 height); -void flipDXT3(uint8 *dst, uint8 *src, uint32 width, uint32 height); -void flipDXT5(uint8 *dst, uint8 *src, uint32 width, uint32 height); void flipDXT(int32 type, uint8 *dst, uint8 *src, uint32 width, uint32 height); @@ -352,9 +350,9 @@ struct Texture enum FilterMode { NEAREST = 1, LINEAR, - MIPNEAREST, + MIPNEAREST, // one mipmap MIPLINEAR, - LINEARMIPNEAREST, + LINEARMIPNEAREST, // mipmap interpolated LINEARMIPLINEAR }; enum Addressing { diff --git a/src/rwplg.h b/src/rwplg.h index 69e0f5c..ad2116a 100644 --- a/src/rwplg.h +++ b/src/rwplg.h @@ -10,6 +10,7 @@ typedef Stream *(*StreamRead)(Stream *stream, int32 length, void *object, int32 typedef Stream *(*StreamWrite)(Stream *stream, int32 length, void *object, int32 offset, int32 size); typedef int32 (*StreamGetSize)(void *object, int32 offset, int32 size); typedef void (*RightsCallback)(void *object, int32 offset, int32 size, uint32 data); +typedef void (*AlwaysCallback)(void *object, int32 offset, int32 size); struct PluginList { @@ -38,6 +39,7 @@ struct PluginList Constructor, Destructor, CopyConstructor); int32 registerStream(uint32 id, StreamRead, StreamWrite, StreamGetSize); int32 setStreamRightsCallback(uint32 id, RightsCallback cb); + int32 setStreamAlwaysCallback(uint32 id, AlwaysCallback cb); int32 getPluginOffset(uint32 id); }; @@ -53,6 +55,7 @@ struct Plugin StreamWrite write; StreamGetSize getSize; RightsCallback rightsCallback; + AlwaysCallback alwaysCallback; PluginList *parentList; LLLink inParentList; LLLink inGlobalList; @@ -71,6 +74,9 @@ struct Plugin static int32 setStreamRightsCallback(uint32 id, RightsCallback cb){ \ return s_plglist.setStreamRightsCallback(id, cb); \ } \ + static int32 setStreamAlwaysCallback(uint32 id, AlwaysCallback cb){ \ + return s_plglist.setStreamAlwaysCallback(id, cb); \ + } \ static int32 getPluginOffset(uint32 id){ \ return s_plglist.getPluginOffset(id); \ } diff --git a/src/rwplugins.h b/src/rwplugins.h index 326d4af..65a63b7 100644 --- a/src/rwplugins.h +++ b/src/rwplugins.h @@ -218,6 +218,7 @@ struct Skin uint8 *data; // only used by delete void *platformData; // a place to store platform specific stuff + bool32 legacyType; // old skin attached to atomic, needed for always CB void init(int32 numBones, int32 numUsedBones, int32 numVertices); void findNumWeights(int32 numVertices); diff --git a/src/skin.cpp b/src/skin.cpp index 3d7eac4..d2865e8 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -265,6 +265,7 @@ readSkinLegacy(Stream *stream, int32 len, void *object, int32, int32) Skin *skin = rwNewT(Skin, 1, MEMDUR_EVENT | ID_SKIN); *PLUGINOFFSET(Skin*, geometry, skinGlobals.geoOffset) = skin; skin->init(numBones, numBones, numVertices); + skin->legacyType = 1; skin->numWeights = 4; stream->read8(skin->indices, numVertices*4); @@ -307,6 +308,17 @@ skinRights(void *object, int32, int32, uint32) Skin::setPipeline((Atomic*)object, 1); } +static void +skinAlways(void *object, int32, int32) +{ + Atomic *atomic = (Atomic*)object; + Geometry *geo = atomic->geometry; + if(geo == nil) return; + Skin *skin = Skin::get(geo); + if(skin == nil) return; + Skin::setPipeline((Atomic*)object, 1); +} + static void* createSkinAtm(void *object, int32 offset, int32) { @@ -373,6 +385,7 @@ registerSkinPlugin(void) skinGlobals.atomicOffset = o; Atomic::registerPluginStream(ID_SKIN, readSkinLegacy, nil, nil); Atomic::setStreamRightsCallback(ID_SKIN, skinRights); + Atomic::setStreamAlwaysCallback(ID_SKIN, skinAlways); } void @@ -417,6 +430,7 @@ Skin::init(int32 numBones, int32 numUsedBones, int32 numVertices) this->rle = nil; this->platformData = nil; + this->legacyType = 0; } diff --git a/tools/playground/main.cpp b/tools/playground/main.cpp index ada15a9..ccf64a2 100644 --- a/tools/playground/main.cpp +++ b/tools/playground/main.cpp @@ -243,7 +243,7 @@ InitRW(void) rw::d3d::isP8supported = false; - postfxtest(); +// postfxtest(); initFont();