From eb71ca25d0c4f10b39c653d9b9847e38aac198d7 Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 27 Apr 2020 20:51:35 +0200 Subject: [PATCH] started working on gl3 rasters --- src/gl/gl3device.cpp | 4 +- src/gl/gl3raster.cpp | 282 ++++++++++++++++++++++++++++------- src/gl/rwgl3.h | 9 ++ src/gl/shaders/header.vert | 4 +- src/gl/shaders/header_vs.inc | 4 +- src/raster.cpp | 37 +++++ src/rwobjects.h | 5 + src/texture.cpp | 7 + 8 files changed, 294 insertions(+), 58 deletions(-) diff --git a/src/gl/gl3device.cpp b/src/gl/gl3device.cpp index be03612..a3a70f5 100644 --- a/src/gl/gl3device.cpp +++ b/src/gl/gl3device.cpp @@ -240,11 +240,13 @@ setActiveTexture(int32 n) } } -static void +uint32 bindTexture(uint32 texid) { + uint32 prev = boundTexture[activeTexture]; boundTexture[activeTexture] = texid; glBindTexture(GL_TEXTURE_2D, texid); + return prev; } // TODO: support mipmaps diff --git a/src/gl/gl3raster.cpp b/src/gl/gl3raster.cpp index 43b4580..911b48f 100644 --- a/src/gl/gl3raster.cpp +++ b/src/gl/gl3raster.cpp @@ -29,29 +29,36 @@ rasterCreateTexture(Raster *raster) Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset); switch(raster->format & 0xF00){ case Raster::C8888: - natras->internalFormat = GL_RGBA; + natras->internalFormat = GL_RGBA8; natras->format = GL_RGBA; natras->type = GL_UNSIGNED_BYTE; natras->hasAlpha = 1; + natras->bbp = 4; + raster->depth = 32; break; case Raster::C888: - natras->internalFormat = GL_RGB; + natras->internalFormat = GL_RGB8; natras->format = GL_RGB; natras->type = GL_UNSIGNED_BYTE; natras->hasAlpha = 0; + natras->bbp = 3; + raster->depth = 24; break; case Raster::C1555: - // TODO: check if this is correct - natras->internalFormat = GL_RGBA; + natras->internalFormat = GL_RGB5_A1; natras->format = GL_RGBA; - natras->type = GL_UNSIGNED_SHORT_1_5_5_5_REV; + natras->type = GL_UNSIGNED_SHORT_5_5_5_1; natras->hasAlpha = 1; + natras->bbp = 2; + raster->depth = 16; break; default: RWERROR((ERR_INVRASTER)); return nil; } + raster->stride = raster->width*natras->bbp; + glGenTextures(1, &natras->texid); glBindTexture(GL_TEXTURE_2D, natras->texid); glTexImage2D(GL_TEXTURE_2D, 0, natras->internalFormat, @@ -80,23 +87,22 @@ rasterCreateCameraTexture(Raster *raster) Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset); switch(raster->format & 0xF00){ case Raster::C8888: - natras->internalFormat = GL_RGBA; + natras->internalFormat = GL_RGBA8; natras->format = GL_RGBA; natras->type = GL_UNSIGNED_BYTE; natras->hasAlpha = 1; break; case Raster::C888: default: - natras->internalFormat = GL_RGB; + natras->internalFormat = GL_RGB8; natras->format = GL_RGB; natras->type = GL_UNSIGNED_BYTE; natras->hasAlpha = 0; break; case Raster::C1555: - // TODO: check if this is correct - natras->internalFormat = GL_RGBA; + natras->internalFormat = GL_RGB5_A1; natras->format = GL_RGBA; - natras->type = GL_UNSIGNED_SHORT_1_5_5_5_REV; + natras->type = GL_UNSIGNED_SHORT_5_5_5_1; natras->hasAlpha = 1; break; } @@ -136,6 +142,32 @@ rasterCreateZbuffer(Raster *raster) #endif +/* +{ 0, 0, 0 }, +{ 16, 4, GL_RGBA }, // 1555 +{ 16, 3, GL_RGB }, // 565 +{ 16, 4, GL_RGBA }, // 4444 +{ 0, 0, 0 }, // LUM8 +{ 32, 4, GL_RGBA }, // 8888 +{ 24, 3, GL_RGB }, // 888 +{ 16, 3, GL_RGB }, // D16 +{ 24, 3, GL_RGB }, // D24 +{ 32, 4, GL_RGBA }, // D32 +{ 16, 3, GL_RGB }, // 555 + +0, +GL_RGB5_A1, +GL_RGB5, +GL_RGBA4, +0, +GL_RGBA8, +GL_RGB8, +GL_RGB5, +GL_RGB8, +GL_RGBA8, +GL_RGB5 +*/ + Raster* rasterCreate(Raster *raster) { @@ -173,23 +205,59 @@ rasterCreate(Raster *raster) } uint8* -rasterLock(Raster*, int32 level, int32 lockMode) +rasterLock(Raster *raster, int32 level, int32 lockMode) { - printf("locking\n"); +#ifdef RW_OPENGL + Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset); + uint8 *px; + + assert(raster->privateFlags == 0); + + px = (uint8*)rwMalloc(raster->stride*raster->height, 0); // TODO: hint + assert(raster->pixels == nil); + raster->pixels = px; + + if(lockMode & Raster::LOCKREAD || !(lockMode & Raster::LOCKNOFETCH)){ + uint32 prev = bindTexture(natras->texid); + glGetTexImage(GL_TEXTURE_2D, level, natras->format, natras->type, px); + bindTexture(prev); + } + + raster->privateFlags = lockMode; + + return px; +#else return nil; +#endif } void -rasterUnlock(Raster*, int32) +rasterUnlock(Raster *raster, int32 level) { - printf("unlocking\n"); +#ifdef RW_OPENGL + Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset); + + assert(raster->pixels); + + if(raster->privateFlags & Raster::LOCKWRITE){ + uint32 prev = bindTexture(natras->texid); + glTexImage2D(GL_TEXTURE_2D, level, natras->internalFormat, + raster->width, raster->height, + 0, natras->format, natras->type, raster->pixels); + bindTexture(prev); + } + + rwFree(raster->pixels); + raster->pixels = nil; + raster->privateFlags = 0; +#endif } int32 rasterNumLevels(Raster*) { - printf("numlevels\n"); - return 0; + // TODO + return 1; } // Almost the same as d3d9 and ps2 function @@ -242,23 +310,14 @@ imageFindRasterFormat(Image *img, int32 type, return 1; } -static uint8* -flipImage(Image *image) -{ - int i; - uint8 *newPx = (uint8*)rwMalloc(image->stride*image->height, 0); - for(i = 0; i < image->height; i++) - memcpy(&newPx[i*image->stride], &image->pixels[(image->height-1-i)*image->stride], image->stride); - return newPx; -} - bool32 rasterFromImage(Raster *raster, Image *image) { if((raster->type&0xF) != Raster::TEXTURE) return 0; -#ifdef RW_OPENGL + void (*conv)(uint8 *out, uint8 *in) = nil; + // Unpalettize image if necessary but don't change original Image *truecolimg = nil; if(image->depth <= 8){ @@ -270,28 +329,27 @@ rasterFromImage(Raster *raster, Image *image) image = truecolimg; } - // NB: important to set the format of the input data here! Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset); switch(image->depth){ case 32: - if(raster->format != Raster::C8888 && - raster->format != Raster::C888) + if(raster->format == Raster::C8888) + conv = conv_RGBA8888_to_RGBA8888; + else if(raster->format == Raster::C888) + conv = conv_RGB888_to_RGB888; + else goto err; - natras->format = GL_RGBA; - natras->type = GL_UNSIGNED_BYTE; - natras->hasAlpha = 1; break; case 24: - if(raster->format != Raster::C888) goto err; - natras->format = GL_RGB; - natras->type = GL_UNSIGNED_BYTE; - natras->hasAlpha = 0; + if(raster->format == Raster::C888) + conv = conv_RGB888_to_RGB888; + else + goto err; break; case 16: - if(raster->format != Raster::C1555) goto err; - natras->format = GL_RGBA; - natras->type = GL_UNSIGNED_SHORT_1_5_5_5_REV; - natras->hasAlpha = 1; + if(raster->format == Raster::C1555) + conv = conv_RGBA1555_to_RGBA5551; + else + goto err; break; case 8: @@ -304,17 +362,26 @@ rasterFromImage(Raster *raster, Image *image) natras->hasAlpha = image->hasAlpha(); + uint8 *pixels = raster->lock(0, Raster::LOCKWRITE|Raster::LOCKNOFETCH); + assert(pixels); + uint8 *imgpixels = image->pixels + (image->height-1)*image->stride; - uint8 *flipped = flipImage(image); + int x, y; + assert(image->width == raster->width); + assert(image->height == raster->height); + for(y = 0; y < image->height; y++){ + uint8 *imgrow = imgpixels; + uint8 *rasrow = pixels; + for(x = 0; x < image->width; x++){ + conv(rasrow, imgrow); + imgrow += image->bpp; + rasrow += natras->bbp; + } + imgpixels -= image->stride; + pixels += raster->stride; + } - glBindTexture(GL_TEXTURE_2D, natras->texid); - glTexImage2D(GL_TEXTURE_2D, 0, natras->internalFormat, - raster->width, raster->height, - 0, natras->format, natras->type, flipped); - glBindTexture(GL_TEXTURE_2D, 0); - - rwFree(flipped); -#endif + raster->unlock(0); return 1; } @@ -327,10 +394,12 @@ createNativeRaster(void *object, int32 offset, int32) } static void* -destroyNativeRaster(void *object, int32, int32) +destroyNativeRaster(void *object, int32 offset, int32) { - //Gl3Raster *ras = PLUGINOFFSET(Gl3Raster, object, offset); - // TODO + Gl3Raster *ras = PLUGINOFFSET(Gl3Raster, object, offset); +#ifdef RW_OPENGL + glDeleteTextures(1, &ras->texid); +#endif return object; } @@ -342,6 +411,113 @@ copyNativeRaster(void *dst, void *, int32 offset, int32) return dst; } +static uint32 +getLevelSize(Raster *raster, int32 level) +{ + Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset); + uint32 size = raster->stride*raster->height; + while(level--) + size /= 4; + return size; +} + +Texture* +readNativeTexture(Stream *stream) +{ + uint32 platform; + if(!findChunk(stream, ID_STRUCT, nil, nil)){ + RWERROR((ERR_CHUNK, "STRUCT")); + return nil; + } + platform = stream->readU32(); + if(platform != PLATFORM_GL3){ + RWERROR((ERR_PLATFORM, platform)); + return nil; + } + Texture *tex = Texture::create(nil); + if(tex == nil) + return nil; + + // Texture + tex->filterAddressing = stream->readU32(); + stream->read(tex->name, 32); + stream->read(tex->mask, 32); + + // Raster + uint32 format = stream->readU32(); + int32 width = stream->readI32(); + int32 height = stream->readI32(); + int32 depth = stream->readI32(); + int32 numLevels = stream->readI32(); + + Raster *raster; + Gl3Raster *natras; + raster = Raster::create(width, height, depth, format | Raster::TEXTURE, PLATFORM_GL3); + assert(raster); + natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset); + tex->raster = raster; + + uint32 size; + 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->read(data, size); + raster->unlock(i); + }else + stream->seek(size); + } + return tex; +} + +void +writeNativeTexture(Texture *tex, Stream *stream) +{ + Raster *raster = tex->raster; + Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset); + + int32 chunksize = getSizeNativeTexture(tex); + writeChunkHeader(stream, ID_STRUCT, chunksize-12); + stream->writeU32(PLATFORM_GL3); + + // Texture + stream->writeU32(tex->filterAddressing); + stream->write(tex->name, 32); + stream->write(tex->mask, 32); + + // Raster + int32 numLevels = raster->getNumLevels(); + stream->writeI32(raster->format); + stream->writeI32(raster->width); + stream->writeI32(raster->height); + stream->writeI32(raster->depth); + stream->writeI32(numLevels); + // TODO: compression? auto mipmaps? + + uint32 size; + uint8 *data; + for(int32 i = 0; i < numLevels; i++){ + size = getLevelSize(raster, i); + stream->writeU32(size); + data = raster->lock(i, Raster::LOCKREAD); + stream->write(data, size); + raster->unlock(i); + } +} + +uint32 +getSizeNativeTexture(Texture *tex) +{ + uint32 size = 12 + 72 + 20; + int32 levels = tex->raster->getNumLevels(); + for(int32 i = 0; i < levels; i++) + size += 4 + getLevelSize(tex->raster, i); + return size; +} + + + void registerNativeRaster(void) { nativeRasterOffset = Raster::registerPlugin(sizeof(Gl3Raster), diff --git a/src/gl/rwgl3.h b/src/gl/rwgl3.h index 91e462c..2384ee7 100644 --- a/src/gl/rwgl3.h +++ b/src/gl/rwgl3.h @@ -171,6 +171,10 @@ int32 setLights(WorldLights *lightData); // per Mesh void setTexture(int32 n, Texture *tex); + +uint32 bindTexture(uint32 texid); + + void flushCache(void); #endif @@ -202,6 +206,7 @@ struct Gl3Raster int32 internalFormat; int32 type; int32 format; + int32 bbp; // bytes per pixel // texture object uint32 texid; @@ -212,6 +217,10 @@ struct Gl3Raster uint8 addressV; }; +Texture *readNativeTexture(Stream *stream); +void writeNativeTexture(Texture *tex, Stream *stream); +uint32 getSizeNativeTexture(Texture *tex); + void registerNativeRaster(void); } diff --git a/src/gl/shaders/header.vert b/src/gl/shaders/header.vert index 8048156..20c5097 100644 --- a/src/gl/shaders/header.vert +++ b/src/gl/shaders/header.vert @@ -84,5 +84,5 @@ float DoFog(float w) } #define DIRECTIONALS -//#define POINTLIGHTS -//#define SPOTLIGHTS \ No newline at end of file +#define POINTLIGHTS +#define SPOTLIGHTS \ No newline at end of file diff --git a/src/gl/shaders/header_vs.inc b/src/gl/shaders/header_vs.inc index 2f884dc..b127335 100644 --- a/src/gl/shaders/header_vs.inc +++ b/src/gl/shaders/header_vs.inc @@ -85,5 +85,5 @@ const char *header_vert_src = "}\n" "#define DIRECTIONALS\n" -"//#define POINTLIGHTS\n" -"//#define SPOTLIGHTS\n"; +"#define POINTLIGHTS\n" +"#define SPOTLIGHTS\n"; diff --git a/src/raster.cpp b/src/raster.cpp index bee0c89..9dfe47a 100644 --- a/src/raster.cpp +++ b/src/raster.cpp @@ -215,5 +215,42 @@ Raster::renderFast(int32 x, int32 y) return engine->device.rasterRenderFast(this,x, y); } +void +conv_RGBA8888_to_RGBA8888(uint8 *out, uint8 *in) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +void +conv_RGB888_to_RGBA8888(uint8 *out, uint8 *in) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = 0xFF; +} + +void +conv_RGB888_to_RGB888(uint8 *out, uint8 *in) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +void +conv_RGBA1555_to_RGBA5551(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; +} } diff --git a/src/rwobjects.h b/src/rwobjects.h index b8a1b5b..9e64a64 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -251,6 +251,11 @@ struct Raster }; }; +void conv_RGBA8888_to_RGBA8888(uint8 *out, uint8 *in); +void conv_RGB888_to_RGBA8888(uint8 *out, uint8 *in); +void conv_RGB888_to_RGB888(uint8 *out, uint8 *in); +void conv_RGBA1555_to_RGBA5551(uint8 *out, uint8 *in); + #define IGNORERASTERIMP 0 diff --git a/src/texture.cpp b/src/texture.cpp index fe52097..4fb3dcc 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -14,6 +14,7 @@ #include "d3d/rwxbox.h" #include "d3d/rwd3d8.h" #include "d3d/rwd3d9.h" +#include "gl/rwgl3.h" #define PLUGIN_ID 0 @@ -455,6 +456,8 @@ Texture::streamReadNative(Stream *stream) return d3d9::readNativeTexture(stream); if(platform == PLATFORM_XBOX) return xbox::readNativeTexture(stream); + if(platform == PLATFORM_GL3) + return gl3::readNativeTexture(stream); assert(0 && "unsupported platform"); return nil; } @@ -470,6 +473,8 @@ Texture::streamWriteNative(Stream *stream) d3d9::writeNativeTexture(this, stream); else if(this->raster->platform == PLATFORM_XBOX) xbox::writeNativeTexture(this, stream); + else if(this->raster->platform == PLATFORM_GL3) + gl3::writeNativeTexture(this, stream); else assert(0 && "unsupported platform"); } @@ -485,6 +490,8 @@ Texture::streamGetSizeNative(void) return d3d9::getSizeNativeTexture(this); if(this->raster->platform == PLATFORM_XBOX) return xbox::getSizeNativeTexture(this); + if(this->raster->platform == PLATFORM_GL3) + return gl3::getSizeNativeTexture(this); assert(0 && "unsupported platform"); return 0; }