From 0d6216554c521d9277d4585a3a138f39f4de01bc Mon Sep 17 00:00:00 2001 From: Angelo Papenhoff Date: Tue, 20 Jan 2015 14:48:18 +0100 Subject: [PATCH] Started implementing Rasters. OpenGL test has textures now. --- dffwrite.cpp | 7 ++- src/geometry.cpp | 23 ++++---- src/image.cpp | 147 +++++++++++++++++++++++++++++++++++++++++++++- src/ogl.cpp | 82 ++++++++++++++++++++++++++ src/plugins.cpp | 11 ++-- src/rwobjects.h | 41 ++++++++++++- src/rwogl.h | 11 ++++ tests/gl/main.cpp | 25 ++++++-- 8 files changed, 320 insertions(+), 27 deletions(-) diff --git a/dffwrite.cpp b/dffwrite.cpp index 2cae3fa..b32181b 100644 --- a/dffwrite.cpp +++ b/dffwrite.cpp @@ -58,9 +58,12 @@ main(int argc, char *argv[]) in.close(); delete[] data; + Rw::Image::setSearchPath("./;/home/aap/gamedata/ps2/gtavc/MODELS/gta3_archive/txd_extracted/"); + // Rw::Image *tga = Rw::readTGA("b.tga"); -// assert(tga != NULL); -// Rw::writeTGA(tga, "out.tga"); + Rw::Image *tga = Rw::readTGA("player.tga"); + assert(tga != NULL); + Rw::writeTGA(tga, "out.tga"); // for(Rw::int32 i = 0; i < c->numAtomics; i++) // Rw::Gl::Instance(c->atomicList[i]); diff --git a/src/geometry.cpp b/src/geometry.cpp index e0115a2..0c5c66c 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -49,6 +49,7 @@ Geometry::Geometry(int32 numVerts, int32 numTris, uint32 flags) this->numMaterials = 0; this->materialList = NULL; this->meshHeader = NULL; + this->instData = NULL; this->refCount = 1; this->constructPlugins(); @@ -438,6 +439,7 @@ Texture::Texture(void) memset(this->name, 0, 32); memset(this->mask, 0, 32); this->filterAddressing = (WRAP << 12) | (WRAP << 8) | NEAREST; + this->raster = NULL; this->refCount = 1; this->constructPlugins(); } @@ -462,6 +464,7 @@ Texture::streamRead(Stream *stream) assert(FindChunk(stream, ID_STRUCT, NULL, NULL)); Texture *tex = new Texture; tex->filterAddressing = stream->readU16(); + // TODO: what is this? (mipmap? i think) stream->seek(2); assert(FindChunk(stream, ID_STRING, &length, NULL)); @@ -470,6 +473,10 @@ Texture::streamRead(Stream *stream) assert(FindChunk(stream, ID_STRING, &length, NULL)); stream->read(tex->mask, length); + tex->raster = Raster::read(tex->name, tex->mask); + if(tex->raster == NULL) + printf("didn't find texture %s\n", tex->name); + tex->streamReadPlugins(stream); return tex; @@ -483,17 +490,12 @@ Texture::streamWrite(Stream *stream) WriteChunkHeader(stream, ID_STRUCT, 4); stream->writeU32(this->filterAddressing); - // TODO: 4 char string -> 8 bytes // TODO: length can't be > 32 - size = strlen(this->name)+3 & ~3; - if(size < 4) - size = 4; + size = strlen(this->name)+4 & ~3; WriteChunkHeader(stream, ID_STRING, size); stream->write(this->name, size); - size = strlen(this->mask)+3 & ~3; - if(size < 4) - size = 4; + size = strlen(this->mask)+4 & ~3; WriteChunkHeader(stream, ID_STRING, size); stream->write(this->mask, size); @@ -508,11 +510,8 @@ Texture::streamGetSize(void) int strsize; size += 12 + 4; size += 12 + 12; - // TODO: see above - strsize = strlen(this->name)+3 & ~3; - size += strsize < 4 ? 4 : strsize; - strsize = strlen(this->mask)+3 & ~3; - size += strsize < 4 ? 4 : strsize; + size += strlen(this->name)+4 & ~3; + size += strlen(this->mask)+4 & ~3; size += 12 + this->streamGetPluginSize(); return size; } diff --git a/src/image.cpp b/src/image.cpp index 63e2a5b..442136a 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -29,6 +29,9 @@ writeUInt8(uint8 tmp, ostream &rw) return sizeof(uint8); } +// +// Image +// Image::Image(int32 width, int32 height, int32 depth) { @@ -84,6 +87,71 @@ Image::setPalette(uint8 *palette) this->flags |= 2; } +static char *searchPaths = NULL; +int numSearchPaths = 0; + +void +Image::setSearchPath(const char *path) +{ + char *p, *end; + ::free(searchPaths); + numSearchPaths = 0; + if(path) + searchPaths = p = strdup(path); + else{ + searchPaths = NULL; + return; + } + while(p && *p){ + end = strchr(p, ';'); + if(end) + *end++ = '\0'; + numSearchPaths++; + p = end; + } +} + +void +Image::printSearchPath(void) +{ + char *p = searchPaths; + for(int i = 0; i < numSearchPaths; i++){ + printf("%s\n", p); + p += strlen(p) + 1; + } +} + +char* +Image::getFilename(const char *name) +{ + FILE *f; + char *s, *p = searchPaths; + int len = strlen(name)+1; + if(numSearchPaths == 0){ + f = fopen(name, "r"); + if(f){ + fclose(f); + printf("found %s\n", name); + return strdup(name); + } + return NULL; + }else + for(int i = 0; i < numSearchPaths; i++){ + s = (char*)malloc(strlen(p)+len); + strcpy(s, p); + strcat(s, name); + f = fopen(s, "r"); + if(f){ + fclose(f); + printf("found %s\n", name); + return s; + } + ::free(s); + p += strlen(p) + 1; + } + return NULL; +} + // // TGA I/O // @@ -106,13 +174,18 @@ struct __attribute__((__packed__)) TGAHeader //#pragma pack(push) Image* -readTGA(const char *filename) +readTGA(const char *afilename) { TGAHeader header; Image *image; + char *filename; int depth = 0, palDepth = 0; // TODO: open from image path + filename = Image::getFilename(afilename); + if(filename == NULL) + return NULL; ifstream file(filename, ios::binary); + free(filename); file.read((char*)&header, sizeof(header)); assert(header.imageType == 1 || header.imageType == 2); @@ -225,4 +298,76 @@ writeTGA(Image *image, const char *filename) file.close(); } +// +// Raster +// + +Raster::Raster(void) +{ + this->type = 0; + this->width = this->height = this->depth = this->stride = 0; + this->format = 0; + this->texels = this->palette = NULL; + this->constructPlugins(); +} + +Raster::~Raster(void) +{ + this->destructPlugins(); + delete[] this->texels; + delete[] this->palette; +} + +Raster* +Raster::createFromImage(Image *image) +{ + Raster *raster = new Raster; + raster->type = 4; + raster->width = image->width; + raster->stride = image->stride; + raster->height = image->height; + raster->depth = image->depth; + raster->texels = raster->palette = NULL; + if(raster->depth == 32) + raster->format = Raster::C8888; + else if(raster->depth == 24) + raster->format = Raster::C888; + else if(raster->depth == 16) + raster->format = Raster::C1555; + else if(raster->depth == 8) + raster->format = Raster::PAL8 | Raster::C8888; + else if(raster->depth == 4) + raster->format = Raster::PAL4 | Raster::C8888; + else{ + delete raster; + return NULL; + } + raster->texels = new uint8[raster->stride*raster->height]; + memcpy(raster->texels, image->pixels, raster->stride*raster->height); + if(image->palette){ + int size = raster->depth == 4 ? 16 : 256; + raster->palette = new uint8[size*4]; + memcpy(raster->palette, image->palette, size*4); + } + return raster; +} + +// TODO: do this properly, only an ugly hack right now +Raster* +Raster::read(const char *name, const char *mask) +{ + (void)mask; + char *n = (char*)malloc(strlen(name) + 5); + strcpy(n, name); + strcat(n, ".tga"); + Image *img = readTGA(n); + free(n); + if(img){ + Raster *raster = Raster::createFromImage(img); + delete img; + return raster; + } + return NULL; +} + } diff --git a/src/ogl.cpp b/src/ogl.cpp index b9ffde5..7c56550 100644 --- a/src/ogl.cpp +++ b/src/ogl.cpp @@ -389,5 +389,87 @@ GetSizeNativeSkin(void *object, int32 offset) return size; } +// Raster + +int32 NativeRasterOffset; + +#ifdef RW_OPENGL +struct GlRaster { + GLuint id; +}; + +static void* +createNativeRaster(void *object, int32 offset, int32) +{ + GlRaster *raster = PLUGINOFFSET(GlRaster, object, offset); + raster->id = 0; + return object; +} + +static void* +destroyNativeRaster(void *object, int32 offset, int32) +{ + // TODO: + return object; +} + +static void* +copyNativeRaster(void *dst, void *, int32 offset, int32) +{ + GlRaster *raster = PLUGINOFFSET(GlRaster, dst, offset); + raster->id = 0; + return dst; +} + +void +RegisterNativeRaster(void) +{ + NativeRasterOffset = Raster::registerPlugin(sizeof(GlRaster), + 0x12340001, + createNativeRaster, + destroyNativeRaster, + copyNativeRaster); +} + +void +Raster::upload(void) +{ + GLuint id; + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + if(this->palette){ + printf("can't upload paletted raster\n"); + return; + } + switch(this->format & 0xF00){ + case C8888: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexImage2D(GL_TEXTURE_2D, 0, 4, this->width, this->height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, this->texels); + break; + default: + printf("unsupported raster format: %x\n", this->format); + break; + } + glBindTexture(GL_TEXTURE_2D, 0); + GlRaster *glr = PLUGINOFFSET(GlRaster, this, NativeRasterOffset); + glr->id = id; +} + +void +Raster::bind(int n) +{ + GlRaster *raster = PLUGINOFFSET(GlRaster, this, NativeRasterOffset); + if(raster->id == 0) + this->upload(); + glActiveTexture(GL_TEXTURE0+n); + glBindTexture(GL_TEXTURE_2D, raster->id); + glActiveTexture(GL_TEXTURE0); +} +#endif + } } diff --git a/src/plugins.cpp b/src/plugins.cpp index a244ed9..6fd10fc 100644 --- a/src/plugins.cpp +++ b/src/plugins.cpp @@ -21,7 +21,7 @@ namespace Rw { int32 HAnimOffset; static void* -createHAnim(void *object, int32 offset, int32 size) +createHAnim(void *object, int32 offset, int32) { HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset); hanim->id = -1; @@ -30,7 +30,7 @@ createHAnim(void *object, int32 offset, int32 size) } static void* -destroyHAnim(void *object, int32 offset, int32 size) +destroyHAnim(void *object, int32 offset, int32) { HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset); if(hanim->hierarchy){ @@ -45,7 +45,7 @@ destroyHAnim(void *object, int32 offset, int32 size) } static void* -copyHAnim(void *dst, void *src, int32 offset, int32 size) +copyHAnim(void *dst, void *src, int32 offset, int32) { HAnimData *dsthanim = PLUGINOFFSET(HAnimData, dst, offset); HAnimData *srchanim = PLUGINOFFSET(HAnimData, src, offset); @@ -56,7 +56,7 @@ copyHAnim(void *dst, void *src, int32 offset, int32 size) } static void -readHAnim(Stream *stream, int32 len, void *object, int32 offset, int32) +readHAnim(Stream *stream, int32, void *object, int32 offset, int32) { int32 cnst, numNodes; HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset); @@ -94,7 +94,7 @@ readHAnim(Stream *stream, int32 len, void *object, int32 offset, int32) } static void -writeHAnim(Stream *stream, int32 len, void *object, int32 offset, int32) +writeHAnim(Stream *stream, int32, void *object, int32 offset, int32) { HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset); stream->writeI32(256); @@ -587,7 +587,6 @@ static void readAtomicMatFX(Stream *stream, int32, void *object, int32 offset, int32) { int32 flag; - uint32 version; stream->read(&flag, 4); *PLUGINOFFSET(int32, object, offset) = flag; if(flag) diff --git a/src/rwobjects.h b/src/rwobjects.h index 559c87e..92ab277 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -86,16 +86,55 @@ struct Image void free(void); void setPixels(uint8 *pixels); void setPalette(uint8 *palette); + + static void setSearchPath(const char*); + static void printSearchPath(void); + static char *getFilename(const char*); }; Image *readTGA(const char *filename); void writeTGA(Image *image, const char *filename); -// TODO: raster, link into texdict +struct Raster : PluginBase +{ + int32 type; // hardly used + int32 width, height, depth; + int32 stride; + int32 format; + uint8 *texels; + uint8 *palette; + + Raster(void); + ~Raster(void); + + static Raster *createFromImage(Image *image); + static Raster *read(const char *name, const char *mask); + + enum Format { + DEFAULT = 0, + C1555 = 0x100, + C565 = 0x200, + C4444 = 0x300, + LUM8 = 0x400, + C8888 = 0x500, + C888 = 0x600, + D16 = 0x700, + D24 = 0x800, + D32 = 0x900, + C555 = 0xa00, + AUTOMIPMAP = 0x1000, + PAL8 = 0x2000, + PAL4 = 0x4000, + MIPMAP = 0x8000 + }; +}; + +// TODO: link into texdict struct Texture : PluginBase { char name[32]; char mask[32]; uint32 filterAddressing; + Raster *raster; int32 refCount; Texture(void); diff --git a/src/rwogl.h b/src/rwogl.h index c8e721c..d4bd877 100644 --- a/src/rwogl.h +++ b/src/rwogl.h @@ -43,5 +43,16 @@ void ReadNativeSkin(Stream *stream, int32, void *object, int32 offset); void WriteNativeSkin(Stream *stream, int32 len, void *object, int32 offset); int32 GetSizeNativeSkin(void *object, int32 offset); +// Raster + +struct Raster : Rw::Raster +{ + void upload(void); + void bind(int n); +}; + +extern int32 NativeRasterOffset; +void RegisterNativeRaster(void); + } } diff --git a/tests/gl/main.cpp b/tests/gl/main.cpp index 26b0c8b..ba61bee 100755 --- a/tests/gl/main.cpp +++ b/tests/gl/main.cpp @@ -41,6 +41,15 @@ renderAtomic(Rw::Atomic *atomic) uint64 offset = 0; for(uint32 i = 0; i < meshHeader->numMeshes; i++){ Mesh *mesh = &meshHeader->mesh[i]; + Texture *tex = mesh->material->texture; + if(tex){ + Rw::Gl::Raster *raster = (Rw::Gl::Raster*)tex->raster; + if(raster) + raster->bind(0); + else + glBindTexture(GL_TEXTURE_2D, 0); + }else + glBindTexture(GL_TEXTURE_2D, 0); glDrawElements(prim[meshHeader->flags], mesh->numIndices, GL_UNSIGNED_SHORT, (void*)offset); offset += mesh->numIndices*2; @@ -96,10 +105,11 @@ init(void) "uniform mat4 viewMat;" "uniform mat4 worldMat;" "attribute vec3 in_vertex;" - "attribute vec3 in_texColor;" + "attribute vec2 in_texCoord;" "attribute vec3 in_normal;" "attribute vec4 in_color;" "varying vec4 v_color;" + "varying vec2 v_texCoord;" "vec3 lightdir = vec3(0.5, -0.5, -0.70710);" "void main()" "{" @@ -107,13 +117,17 @@ init(void) " vec3 n = mat3(worldMat) * in_normal;" " float l = max(0.0, dot(n, -lightdir));" " v_color = in_color*l;" + " v_texCoord = in_texCoord;" "}\n" "#endif\n" "#ifdef FRAGMENT\n" + "uniform sampler2D u_texture0;" "varying vec4 v_color;" + "varying vec2 v_texCoord;" "void main()" "{" - " gl_FragColor = v_color;" + " vec4 c0 = texture2D(u_texture0, v_texCoord/512.0f);" + " gl_FragColor = v_color*c0;" "}\n" "#endif\n"; const char *srcarr[] = { "#define VERTEX", shadersrc }; @@ -153,6 +167,10 @@ init(void) camera->setTarget(Vec3(0.0f, 0.0f, 0.0f)); camera->setPosition(Vec3(0.0f, 5.0f, 0.0f)); +// Rw::Image::setSearchPath("/home/aap/gamedata/ps2/gtasa/models/gta3_archive/txd_extracted/"); +// Rw::Image::setSearchPath("/home/aap/gamedata/ps2/gtavc/MODELS/gta3_archive/txd_extracted/"); + Rw::Image::setSearchPath("/home/aap/gamedata/ps2/gtavc/MODELS/gta3_archive/txd_extracted/;/home/aap/gamedata/ps2/gtasa/models/gta3_archive/txd_extracted/"); + Rw::Gl::RegisterNativeRaster(); Rw::RegisterMaterialRightsPlugin(); Rw::RegisterMatFXPlugin(); Rw::RegisterAtomicRightsPlugin(); @@ -167,9 +185,6 @@ init(void) Rw::RegisterMeshPlugin(); Rw::StreamFile in; -// in.open("player-vc-ogl.dff", "rb"); -// in.open("player-iii.dff", "rb"); -// in.open("admiral-ogl.dff", "rb"); in.open(filename, "rb"); Rw::FindChunk(&in, Rw::ID_CLUMP, NULL, NULL); clump = Rw::Clump::streamRead(&in);