#include #include #include #include #include #include #include #include using namespace std; using namespace rw; #include "rsl.h" char *argv0; int32 atmOffset; void RslStream::relocate(void) { uint32 off = (uint32)(uintptr)this->data; off -= 0x20; *(uint32*)&this->reloc += off; *(uint32*)&this->hashTab += off; uint8 **rel = (uint8**)this->reloc; for(uint32 i = 0; i < this->relocSize; i++){ rel[i] += off; *this->reloc[i] += off; } } RslFrame *dumpFrameCB(RslFrame *frame, void *data) { printf(" frm: %x %s %x\n", frame->nodeId, frame->name, frame->hierId); RslFrameForAllChildren(frame, dumpFrameCB, data); return frame; } RslMaterial *dumpMaterialCB(RslMaterial *material, void*) { printf(" mat: %d %d %d %d %s %x\n", material->color.red, material->color.green, material->color.blue, material->color.alpha, material->texname, material->refCount); if(material->matfx){ RslMatFX *fx = material->matfx; printf(" matfx: %d", fx->effectType); if(fx->effectType == 2) printf("env[%s %f] ", fx->env.texname, fx->env.intensity); printf("\n"); } return material; } RslAtomic *dumpAtomicCB(RslAtomic *atomic, void*) { printf(" atm: %x %x %x %p\n", atomic->unk1, atomic->unk2, atomic->unk3, atomic->hier); RslGeometry *g = atomic->geometry; RslGeometryForAllMaterials(g, dumpMaterialCB, NULL); return atomic; } int32 mapID(int32 id) { if(id == 255) return -1; if(id > 0x80) id |= 0x1300; return id; } static RslFrame* findFrame(RslFrame *f, int32 id) { if(f == NULL) return NULL; if((f->nodeId & 0xFF) == (id & 0xFF)) return f; RslFrame *ff = findFrame(f->next, id); if(ff) return ff; return findFrame(f->child, id); } static RslFrame* findChild(RslFrame *f) { for(RslFrame *c = f->child; c; c = c->next) if(c->nodeId < 0) return c; return NULL; } int32 nextId; struct Node { int32 id; int32 parent; }; Frame* convertFrame(RslFrame *f) { Frame *rwf = Frame::create(); rwf->matrix[0] = f->modelling.right.x; rwf->matrix[1] = f->modelling.right.y; rwf->matrix[2] = f->modelling.right.z; rwf->matrix[4] = f->modelling.up.x; rwf->matrix[5] = f->modelling.up.y; rwf->matrix[6] = f->modelling.up.z; rwf->matrix[8] = f->modelling.at.x; rwf->matrix[9] = f->modelling.at.y; rwf->matrix[10] = f->modelling.at.z; rwf->matrix[12] = f->modelling.pos.x; rwf->matrix[13] = f->modelling.pos.y; rwf->matrix[14] = f->modelling.pos.z; if(f->name) strncpy(gta::getNodeName(rwf), f->name, 24); HAnimData *hanim = PLUGINOFFSET(HAnimData, rwf, hAnimOffset); hanim->id = f->nodeId; if(f->hier){ int32 numNodes = f->hier->numNodes; int32 *nodeFlags = new int32[numNodes]; int32 *nodeIDs = new int32[numNodes]; nextId = 2000; Node *nodehier = new Node[numNodes]; int32 stack[100]; int32 sp = 0; stack[sp] = -1; // Match up nodes with frames to fix and assign IDs // NOTE: assignment can only work reliably when not more // than one child node needs an ID for(int32 i = 0; i < numNodes; i++){ RslHAnimNodeInfo *ni = &f->hier->pNodeInfo[i]; Node *n = &nodehier[i]; n->parent = stack[sp]; if(ni->flags & HAnimHierarchy::PUSH) sp++; stack[sp] = i; RslFrame *ff = findFrame(f, (uint8)ni->id); n->id = ff->nodeId; if(n->id < 0){ ff = findFrame(f, nodehier[n->parent].id); ff = findChild(ff); n->id = ff->nodeId = nextId++; } //printf("%d %s %d %d\n", i, ff->name, n->id, n->parent); if(ni->flags & HAnimHierarchy::POP) sp--; nodeFlags[i] = ni->flags; nodeIDs[i] = n->id; } HAnimHierarchy *hier = HAnimHierarchy::create(numNodes, nodeFlags, nodeIDs, f->hier->flags, f->hier->maxKeyFrameSize); hanim->hierarchy = hier; delete[] nodeFlags; delete[] nodeIDs; delete[] nodehier; } return rwf; } Texture* convertTexture(RslTexture *t) { Texture *tex = Texture::read(t->name, t->mask); //tex->refCount++; // ?? if(tex->refCount == 1) tex->filterAddressing = (Texture::WRAP << 12) | (Texture::WRAP << 8) | Texture::LINEAR; return tex; } Material* convertMaterial(RslMaterial *m) { Material *rwm; rwm = Material::create(); rwm->color = m->color; if(m->texture) rwm->texture = convertTexture(m->texture); if(m->matfx){ MatFX *matfx = new MatFX; matfx->setEffects(m->matfx->effectType); matfx->setEnvCoefficient(m->matfx->env.intensity); if(m->matfx->env.texture) matfx->setEnvTexture(convertTexture(m->matfx->env.texture)); *PLUGINOFFSET(MatFX*, rwm, matFXGlobals.materialOffset) = matfx; } return rwm; } static uint32 unpackSize(uint32 unpack) { if((unpack&0x6F000000) == 0x6F000000) return 2; static uint32 size[] = { 32, 16, 8, 16 }; return ((unpack>>26 & 3)+1)*size[unpack>>24 & 3]/8; } static uint32* skipUnpack(uint32 *p) { int32 n = (p[0] >> 16) & 0xFF; return p + (n*unpackSize(p[0])+3 >> 2) + 1; } void convertMesh(Geometry *rwg, RslGeometry *g, int32 ii) { RslPS2ResEntryHeader *resHeader = (RslPS2ResEntryHeader*)(g+1); RslPS2InstanceData *inst = (RslPS2InstanceData*)(resHeader+1); int32 numInst = resHeader->size >> 20; uint8 *p = (uint8*)(inst+numInst); inst += ii; p += inst->dmaPacket; Mesh *m = &rwg->meshHeader->mesh[inst->matID]; ps2::SkinVertex v; uint32 mask = 0x1001; // tex coords, vertices if(rwg->geoflags & Geometry::NORMALS) mask |= 0x10; if(rwg->geoflags & Geometry::PRELIT) mask |= 0x100; Skin *skin = *PLUGINOFFSET(Skin*, rwg, skinGlobals.offset); if(skin) mask |= 0x10000; int16 *vuVerts = NULL; int8 *vuNorms = NULL; uint8 *vuTex = NULL; uint16 *vuCols = NULL; uint32 *vuSkin = NULL; uint32 *w = (uint32*)p; uint32 *end = (uint32*)(p + ((w[0] & 0xFFFF) + 1)*0x10); w += 4; int32 nvert; bool first = 1; while(w < end){ /* Get data pointers */ // GIFtag probably assert(w[0] == 0x6C018000); // UNPACK nvert = w[4] & 0x7FFF; if(!first) nvert -=2; w += 5; // positions assert(w[0] == 0x20000000); // STMASK w += 2; assert(w[0] == 0x30000000); // STROW w += 5; assert((w[0] & 0xFF004000) == 0x79000000); vuVerts = (int16*)(w+1); if(!first) vuVerts += 2*3; w = skipUnpack(w); // tex coords assert(w[0] == 0x20000000); // STMASK w += 2; assert(w[0] == 0x30000000); // STROW w += 5; assert((w[0] & 0xFF004000) == 0x76004000); vuTex = (uint8*)(w+1); if(!first) vuTex += 2*2; w = skipUnpack(w); if(rwg->geoflags & Geometry::NORMALS){ assert((w[0] & 0xFF004000) == 0x6A000000); vuNorms = (int8*)(w+1); if(!first) vuNorms += 2*3; w = skipUnpack(w); } if(rwg->geoflags & Geometry::PRELIT){ assert((w[0] & 0xFF004000) == 0x6F000000); vuCols = (uint16*)(w+1); if(!first) vuCols += 2; w = skipUnpack(w); } if(skin){ assert((w[0] & 0xFF004000) == 0x6C000000); vuSkin = w+1; if(!first) vuSkin += 2*4; w = skipUnpack(w); } assert(w[0] == 0x14000006); // MSCAL w++; while(w[0] == 0) w++; /* Insert Data */ for(int32 i = 0; i < nvert; i++){ v.p[0] = vuVerts[0]/32768.0f*resHeader->scale[0] + resHeader->pos[0]; v.p[1] = vuVerts[1]/32768.0f*resHeader->scale[1] + resHeader->pos[1]; v.p[2] = vuVerts[2]/32768.0f*resHeader->scale[2] + resHeader->pos[2]; v.t[0] = vuTex[0]/128.0f*inst->uvScale[0]; v.t[1] = vuTex[1]/128.0f*inst->uvScale[1]; if(mask & 0x10){ v.n[0] = vuNorms[0]/127.0f; v.n[1] = vuNorms[1]/127.0f; v.n[2] = vuNorms[2]/127.0f; } if(mask & 0x100){ v.c[0] = (vuCols[0] & 0x1f) * 255 / 0x1F; v.c[1] = (vuCols[0]>>5 & 0x1f) * 255 / 0x1F; v.c[2] = (vuCols[0]>>10 & 0x1f) * 255 / 0x1F; v.c[3] = vuCols[0]&0x8000 ? 0xFF : 0; } if(mask & 0x10000){ for(int j = 0; j < 4; j++){ ((uint32*)v.w)[j] = vuSkin[j] & ~0x3FF; v.i[j] = vuSkin[j] >> 2; //if(v.i[j]) v.i[j]--; if(v.w[j] == 0.0f) v.i[j] = 0; } } int32 idx = ps2::findVertexSkin(rwg, NULL, mask, &v); if(idx < 0) idx = rwg->numVertices++; /* Insert mesh joining indices when we get the index of the first vertex * in the first VU chunk of a non-first RslMesh. */ if(i == 0 && first && ii != 0 && inst[-1].matID == inst->matID){ m->indices[m->numIndices] = m->indices[m->numIndices-1]; m->numIndices++; m->indices[m->numIndices++] = idx; if(inst[-1].numTriangles % 2) m->indices[m->numIndices++] = idx; } m->indices[m->numIndices++] = idx; ps2::insertVertexSkin(rwg, idx, mask, &v); vuVerts += 3; vuTex += 2; vuNorms += 3; vuCols++; vuSkin += 4; } first = 0; } } Atomic* convertAtomic(RslAtomic *atomic) { Atomic *rwa = Atomic::create(); RslGeometry *g = atomic->geometry; Geometry *rwg = Geometry::create(0, 0, 0); rwa->geometry = rwg; *PLUGINOFFSET(RslAtomic*, rwa, atmOffset) = atomic; rwg->numMaterials = g->matList.numMaterials; rwg->materialList = new Material*[rwg->numMaterials]; for(int32 i = 0; i < rwg->numMaterials; i++) rwg->materialList[i] = convertMaterial(g->matList.materials[i]); rwg->meshHeader = new MeshHeader; rwg->meshHeader->flags = 1; rwg->meshHeader->numMeshes = rwg->numMaterials; rwg->meshHeader->mesh = new Mesh[rwg->meshHeader->numMeshes]; rwg->meshHeader->totalIndices = 0; Mesh *meshes = rwg->meshHeader->mesh; for(uint32 i = 0; i < rwg->meshHeader->numMeshes; i++) meshes[i].numIndices = 0; RslPS2ResEntryHeader *resHeader = (RslPS2ResEntryHeader*)(g+1); RslPS2InstanceData *inst = (RslPS2InstanceData*)(resHeader+1); int32 numInst = resHeader->size >> 20; int32 lastId = -1; for(int32 i = 0; i < numInst; i++){ Mesh *m = &meshes[inst[i].matID]; rwg->numVertices += inst[i].numTriangles+2; m->numIndices += inst[i].numTriangles+2; // Extra indices since we're merging tristrip // meshes with the same material. // Be careful with face winding. if(lastId == inst[i].matID) m->numIndices += inst[i-1].numTriangles % 2 ? 3 : 2; lastId = inst[i].matID; } for(uint32 i = 0; i < rwg->meshHeader->numMeshes; i++){ rwg->meshHeader->mesh[i].material = rwg->materialList[i]; rwg->meshHeader->totalIndices += meshes[i].numIndices; } rwg->geoflags = Geometry::TRISTRIP | Geometry::POSITIONS | /* 0x01 ? */ Geometry::TEXTURED | /* 0x04 ? */ Geometry::LIGHT; if(rwg->hasColoredMaterial()) rwg->geoflags |= Geometry::MODULATE; if(resHeader->flags & 0x2) rwg->geoflags |= Geometry::NORMALS; if(resHeader->flags & 0x8) rwg->geoflags |= Geometry::PRELIT; rwg->numTexCoordSets = 1; rwg->allocateData(); rwg->meshHeader->allocateIndices(); Skin *skin = NULL; if(resHeader->flags & 0x10) assert(g->skin); if(g->skin){ skin = new Skin; *PLUGINOFFSET(Skin*, rwg, skinGlobals.offset) = skin; skin->init(g->skin->numBones, g->skin->numBones, rwg->numVertices); memcpy(skin->inverseMatrices, g->skin->invMatrices, skin->numBones*64); } for(uint32 i = 0; i < rwg->meshHeader->numMeshes; i++) meshes[i].numIndices = 0; rwg->meshHeader->totalIndices = rwg->numVertices = 0; for(int32 i = 0; i < numInst; i++) convertMesh(rwg, g, i); for(uint32 i = 0; i < rwg->meshHeader->numMeshes; i++) rwg->meshHeader->totalIndices += meshes[i].numIndices; if(skin){ skin->findNumWeights(rwg->numVertices); skin->findUsedBones(rwg->numVertices); } rwg->calculateBoundingSphere(); rwg->generateTriangles(); return rwa; } RslAtomic* collectAtomics(RslAtomic *atomic, void *data) { RslAtomic ***alist = (RslAtomic***)data; *(*alist)++ = atomic; return atomic; } Clump* convertClump(RslClump *c) { Clump *rwc; Frame *rwf; Atomic *rwa; rslFrameList frameList; rwc = Clump::create(); rslFrameListInitialize(&frameList, (RslFrame*)c->object.parent); Frame **rwframes = new Frame*[frameList.numFrames]; for(int32 i = 0; i < frameList.numFrames; i++){ rwf = convertFrame(frameList.frames[i]); rwframes[i] = rwf; void *par = frameList.frames[i]->object.parent; int32 parent = findPointer(par, (void**)frameList.frames, frameList.numFrames); if(parent >= 0) rwframes[parent]->addChild(rwf); } rwc->object.parent = rwframes[0]; int32 numAtomics = RslClumpGetNumAtomics(c); RslAtomic **alist = new RslAtomic*[numAtomics]; RslAtomic **ap = &alist[0]; RslClumpForAllAtomics(c, collectAtomics, &ap); for(int32 i = 0; i < numAtomics; i++){ rwa = convertAtomic(alist[i]); int32 fi = findPointer(alist[i]->object.object.parent, (void**)frameList.frames, frameList.numFrames); rwa->setFrame(rwframes[fi]); rwc->addAtomic(rwa); } delete[] alist; delete[] rwframes; delete[] frameList.frames; return rwc; } RslAtomic* makeTextures(RslAtomic *atomic, void*) { RslGeometry *g = atomic->geometry; RslMaterial *m; for(int32 i = 0; i < g->matList.numMaterials; i++){ m = g->matList.materials[i]; if(m->texname){ RslTexture *tex = RslTextureCreate(NULL); strncpy(tex->name, m->texname, 32); strncpy(tex->mask, m->texname, 32); m->texture = tex; } if(m->matfx && m->matfx->effectType == MatFX::ENVMAP && m->matfx->env.texname){ RslTexture *tex = RslTextureCreate(NULL); strncpy(tex->name, m->matfx->env.texname, 32); strncpy(tex->mask, m->matfx->env.texname, 32); m->matfx->env.texture = tex; } } return atomic; } void moveAtomics(Frame *f) { static char *names[] = { "", "hi_ok", "hi_dam" }; if(f == NULL) return; int n = f->objectList.count(); if(n > 1){ char *oldname = gta::getNodeName(f); ObjectWithFrame **objs = new ObjectWithFrame*[n]; int i = 0; FORLIST(lnk, f->objectList){ ObjectWithFrame *obj = ObjectWithFrame::fromFrame(lnk); assert(obj->type == Atomic::ID); objs[i] = obj; obj->setFrame(NULL); i++; } for(i = 0; i < n; i++){ Frame *ff = Frame::create(); RslAtomic *rsla = *PLUGINOFFSET(RslAtomic*, objs[i], atmOffset); char *name = gta::getNodeName(ff); strncpy(name, oldname, 24); char *end = strrchr(name, '_'); if(end){ *(++end) = '\0'; strcat(end, names[rsla->unk3&3]); } f->addChild(ff); objs[i]->setFrame(ff); } delete[] objs; } moveAtomics(f->next); moveAtomics(f->child); } uint8* getPalettePS2(RslRaster *raster) { uint32 f = raster->ps2.flags; uint32 w = 1 << (f & 0x3F); uint32 h = 1 << (f>>6 & 0x3F); uint32 d = f>>12 & 0xFF; uint32 mip = f>>20 & 0xF; uint8 *data = raster->ps2.data; if(d > 8) return NULL; while(mip--){ data += w*h*d/8; w /= 2; h /= 2; } return data; } uint8* getTexelPS2(RslRaster *raster, int32 n) { uint32 f = raster->ps2.flags; uint32 w = 1 << (f & 0x3F); uint32 h = 1 << (f>>6 & 0x3F); uint32 d = f>>12 & 0xFF; uint8 *data = raster->ps2.data; for(int32 i = 0; i < n; i++){ data += w*h*d/8; w /= 2; h /= 2; } return data; } void convertCLUT(uint8 *texels, uint32 w, uint32 h) { static uint8 map[4] = { 0x00, 0x10, 0x08, 0x18 }; for (uint32 i = 0; i < w*h; i++) texels[i] = (texels[i] & ~0x18) | map[(texels[i] & 0x18) >> 3]; } void unswizzle8(uint8 *dst, uint8 *src, uint32 w, uint32 h) { for (uint32 y = 0; y < h; y++) for (uint32 x = 0; x < w; x++) { int32 block_loc = (y&(~0xF))*w + (x&(~0xF))*2; uint32 swap_sel = (((y+2)>>2)&0x1)*4; int32 ypos = (((y&(~3))>>1) + (y&1))&0x7; int32 column_loc = ypos*w*2 + ((x+swap_sel)&0x7)*4; int32 byte_sum = ((y>>1)&1) + ((x>>2)&2); uint32 swizzled = block_loc + column_loc + byte_sum; dst[y*w+x] = src[swizzled]; } } void unswizzle16(uint16 *dst, uint16 *src, int32 w, int32 h) { for(int y = 0; y < h; y++) for(int x = 0; x < w; x++){ int32 pageX = x & (~0x3f); int32 pageY = y & (~0x3f); int32 pages_horz = (w+63)/64; int32 pages_vert = (h+63)/64; int32 page_number = (pageY/64)*pages_horz + (pageX/64); int32 page32Y = (page_number/pages_vert)*32; int32 page32X = (page_number%pages_vert)*64; int32 page_location = (page32Y*h + page32X)*2; int32 locX = x & 0x3f; int32 locY = y & 0x3f; int32 block_location = (locX&(~0xf))*h + (locY&(~0x7))*2; int32 column_location = ((y&0x7)*h + (x&0x7))*2; int32 short_num = (x>>3)&1; // 0,1 uint32 swizzled = page_location + block_location + column_location + short_num; dst[y*w+x] = src[swizzled]; } } bool32 unswizzle = 1; void convertTo32(uint8 *out, uint8 *pal, uint8 *tex, uint32 w, uint32 h, uint32 d, bool32 swiz) { uint32 x; if(d == 32){ //uint32 *dat = new uint32[w*h]; //if(swiz && unswizzle) // unswizzle8_hack(dat, (uint32*)tex, w, h); //else // memcpy(dat, tex, w*h*4); //tex = (uint8*)dat; for(uint32 i = 0; i < w*h; i++){ out[i*4+0] = tex[i*4+0]; out[i*4+1] = tex[i*4+1]; out[i*4+2] = tex[i*4+2]; out[i*4+3] = tex[i*4+3]*255/128; } //delete[] dat; } if(d == 16) return; // TODO if(d == 8){ uint8 *dat = new uint8[w*h]; if(swiz && unswizzle) unswizzle8(dat, tex, w, h); else memcpy(dat, tex, w*h); tex = dat; convertCLUT(tex, w, h); for(uint32 i = 0; i < h; i++) for(uint32 j = 0; j < w; j++){ x = *tex++; *out++ = pal[x*4+0]; *out++ = pal[x*4+1]; *out++ = pal[x*4+2]; *out++ = pal[x*4+3]*255/128; } delete[] dat; } if(d == 4){ uint8 *dat = new uint8[w*h]; for(uint32 i = 0; i < w*h/2; i++){ dat[i*2+0] = tex[i] & 0xF; dat[i*2+1] = tex[i] >> 4; } if(swiz && unswizzle){ uint8 *tmp = new uint8[w*h]; unswizzle8(tmp, dat, w, h); delete[] dat; dat = tmp; } tex = dat; for(uint32 i = 0; i < h; i++) for(uint32 j = 0; j < w; j++){ x = *tex++; *out++ = pal[x*4+0]; *out++ = pal[x*4+1]; *out++ = pal[x*4+2]; *out++ = pal[x*4+3]*255/128; } delete[] dat; } } RslTexture *dumpTextureCB(RslTexture *texture, void*) { uint32 f = texture->raster->ps2.flags; uint32 w = 1 << (f & 0x3F); uint32 h = 1 << (f>>6 & 0x3F); uint32 d = f>>12 & 0xFF; uint32 mip = f>>20 & 0xF; uint32 swizmask = f>>24; uint8 *palette = getPalettePS2(texture->raster); uint8 *texels = getTexelPS2(texture->raster, 0); printf(" %x %x %x %x %x %s\n", w, h, d, mip, swizmask, texture->name); Image *img = Image::create(w, h, 32); img->allocate(); convertTo32(img->pixels, palette, texels, w, h, d, swizmask&1); char *name = new char[strlen(texture->name)+5]; strcpy(name, texture->name); strcat(name, ".tga"); writeTGA(img, name); img->destroy(); delete[] name; return texture; } RslTexture* convertTexturePS2(RslTexture *texture, void *pData) { TexDictionary *rwtxd = (TexDictionary*)pData; Texture *rwtex = Texture::create(NULL); RslRasterPS2 *ras = &texture->raster->ps2; strncpy(rwtex->name, texture->name, 32); strncpy(rwtex->mask, texture->mask, 32); rwtex->filterAddressing = 0x1102; uint32 f = ras->flags; uint32 w = 1 << (f & 0x3F); uint32 h = 1 << (f>>6 & 0x3F); uint32 d = f>>12 & 0xFF; //uint32 mip = f>>20 & 0xF; uint32 swizmask = f>>24; uint8 *palette = getPalettePS2(texture->raster); uint8 *texels = getTexelPS2(texture->raster, 0); int32 hasAlpha = 0; uint8 *convtex = NULL; if(d == 4){ convtex = new uint8[w*h]; for(uint32 i = 0; i < w*h/2; i++){ int32 a = texels[i] & 0xF; int32 b = texels[i] >> 4; if(palette[a*4+3] != 0x80) hasAlpha = 1; if(palette[b*4+3] != 0x80) hasAlpha = 1; convtex[i*2+0] = a; convtex[i*2+1] = b; } if(swizmask & 1 && unswizzle){ uint8 *tmp = new uint8[w*h]; unswizzle8(tmp, convtex, w, h); delete[] convtex; convtex = tmp; } }else if(d == 8){ convtex = new uint8[w*h]; if(swizmask & 1 && unswizzle) unswizzle8(convtex, texels, w, h); else memcpy(convtex, texels, w*h); convertCLUT(convtex, w, h); for(uint32 i = 0; i < w*h; i++) if(palette[convtex[i]*4+3] != 0x80){ hasAlpha = 1; break; } } int32 format = 0; switch(d){ case 4: case 8: format |= Raster::PAL8; goto alpha32; case 32: for(uint32 i = 0; i < w*h; i++) if(texels[i*4+3] != 0x80){ hasAlpha = 1; break; } alpha32: if(hasAlpha) format |= Raster::C8888; else format |= Raster::C888; break; default: fprintf(stderr, "unsupported depth %d\n", d); return NULL; } Raster *rwras = Raster::create(w, h, d == 4 ? 8 : d, format | 4, PLATFORM_D3D8); d3d::D3dRaster *d3dras = PLUGINOFFSET(d3d::D3dRaster, rwras, d3d::nativeRasterOffset); int32 pallen = d == 4 ? 16 : d == 8 ? 256 : 0; if(pallen){ uint8 *p = new uint8[256*4]; for(int32 i = 0; i < pallen; i++){ p[i*4+0] = palette[i*4+0]; p[i*4+1] = palette[i*4+1]; p[i*4+2] = palette[i*4+2]; p[i*4+3] = palette[i*4+3]*255/128; } memcpy(d3dras->palette, p, 256*4); delete[] p; } uint8 *data = rwras->lock(0); if(d == 4 || d == 8) memcpy(data, convtex, w*h); else if(d == 32){ // texture is fucked, but pretend it isn't for(uint32 i = 0; i < w*h; i++){ data[i*4+2] = texels[i*4+0]; data[i*4+1] = texels[i*4+1]; data[i*4+0] = texels[i*4+2]; data[i*4+3] = texels[i*4+3]*255/128; } }else memcpy(data, texels, w*h*d/8); rwras->unlock(0); rwtex->raster = rwras; delete[] convtex; rwtxd->add(rwtex); return texture; } TexDictionary* convertTXD(RslTexDictionary *txd) { TexDictionary *rwtxd = TexDictionary::create(); RslTexDictionaryForAllTextures(txd, convertTexturePS2, rwtxd); return rwtxd; } void usage(void) { fprintf(stderr, "%s [-v version] [-x] [-s] input [output.{txd|dff}]\n", argv0); fprintf(stderr, "\t-v RW version, e.g. 33004 for 3.3.0.4\n"); fprintf(stderr, "\t-x extract textures to tga\n"); fprintf(stderr, "\t-s don't unswizzle textures\n"); fprintf(stderr, "\t-a fix Atomics placement inside hierarchy (mdl files)\n"); exit(1); } int main(int argc, char *argv[]) { gta::attachPlugins(); atmOffset = Atomic::registerPlugin(sizeof(void*), 0x1000000, NULL, NULL, NULL); rw::version = 0x34003; rw::platform = PLATFORM_D3D8; assert(sizeof(void*) == 4); int extract = 0; int fixAtomics = 0; ARGBEGIN{ case 'v': sscanf(EARGF(usage()), "%x", &rw::version); break; case 's': unswizzle = 0; break; case 'x': extract++; break; case 'a': fixAtomics++; break; default: usage(); }ARGEND; if(argc < 1) usage(); World *world = NULL; Sector *sector = NULL; RslClump *clump = NULL; RslAtomic *atomic = NULL; RslTexDictionary *txd = NULL; StreamFile stream; assert(stream.open(argv[0], "rb")); uint32 ident = stream.readU32(); stream.seek(0, 0); if(ident == ID_TEXDICTIONARY){ findChunk(&stream, ID_TEXDICTIONARY, NULL, NULL); txd = RslTexDictionaryStreamRead(&stream); stream.close(); assert(txd); goto writeTxd; } if(ident == ID_CLUMP){ findChunk(&stream, ID_CLUMP, NULL, NULL); clump = RslClumpStreamRead(&stream); stream.close(); assert(clump); goto writeDff; } RslStream *rslstr; rslstr = new RslStream; stream.read(rslstr, 0x20); rslstr->data = new uint8[rslstr->fileSize-0x20]; stream.read(rslstr->data, rslstr->fileSize-0x20); stream.close(); rslstr->relocate(); bool32 largefile; largefile = rslstr->dataSize > 0x1000000; if(rslstr->ident == WRLD_IDENT && largefile){ // hack world = (World*)rslstr->data; int len = strlen(argv[0])+1; char filename[1024]; strncpy(filename, argv[0], len); filename[len-3] = 'i'; filename[len-2] = 'm'; filename[len-1] = 'g'; filename[len] = '\0'; assert(stream.open(filename, "rb")); filename[len-4] = '\\'; filename[len-3] = '\0'; char name[1024]; uint8 *data; StreamFile outf; RslStreamHeader *h; uint32 i = 0; for(h = world->sectors->sector; h->ident == WRLD_IDENT; h++){ sprintf(name, "world%04d.wrld", i++); strcat(filename, name); assert(outf.open(filename, "wb")); data = new uint8[h->fileEnd]; memcpy(data, h, 0x20); stream.seek(h->root, 0); stream.read(data+0x20, h->fileEnd-0x20); outf.write(data, h->fileEnd); outf.close(); filename[len-3] = '\0'; } // radar textures h = world->textures; for(i = 0; i < world->numTextures; i++){ sprintf(name, "txd%04d.chk", i); strcat(filename, name); assert(outf.open(filename, "wb")); data = new uint8[h->fileEnd]; memcpy(data, h, 0x20); stream.seek(h->root, 0); stream.read(data+0x20, h->fileEnd-0x20); outf.write(data, h->fileEnd); outf.close(); filename[len-3] = '\0'; h++; } stream.close(); }else if(rslstr->ident == WRLD_IDENT){ // sector sector = (Sector*)rslstr->data; fprintf(stderr, "%d\n",sector->unk1); //printf("resources\n"); //for(uint32 i = 0; i < sector->numResources; i++){ // OverlayResource *r = §or->resources[i]; // printf(" %d %p\n", r->id, r->raw); //} //printf("placement\n"); if(sector->unk1 == 0) return 0; Placement *p; //for(p = sector->sectionA; p < sector->sectionEnd; p++){ // printf(" %d, %d, %f %f %f\n", p->id &0x7FFF, p->resId, p->matrix[12], p->matrix[13], p->matrix[14]); //} for(p = sector->sectionA; p < sector->sectionEnd; p++) printf("%f %f %f\n", p->matrix[12], p->matrix[13], p->matrix[14]); }else if(rslstr->ident == MDL_IDENT){ uint8 *p; p = *rslstr->hashTab; p -= 0x24; atomic = (RslAtomic*)p; clump = atomic->clump; Clump *rwc; if(clump){ RslClumpForAllAtomics(clump, makeTextures, NULL); //RslClumpForAllAtomics(clump, dumpAtomicCB, NULL); //RslFrameForAllChildren(RslClumpGetFrame(clump), dumpFrameCB, NULL); }else{ makeTextures(atomic, NULL); clump = RslClumpCreate(); RslAtomicSetFrame(atomic, RslFrameCreate()); RslClumpSetFrame(clump, RslAtomicGetFrame(atomic)); RslClumpAddAtomic(clump, atomic); //dumpAtomicCB(a, NULL); //RslFrameForAllChildren(RslAtomicGetFrame(atomic), dumpFrameCB, NULL); } writeDff: rwc = convertClump(clump); if(fixAtomics) moveAtomics(rwc->getFrame()); if(argc > 1) assert(stream.open(argv[1], "wb")); else assert(stream.open("out.dff", "wb")); rwc->streamWrite(&stream); stream.close(); }else if(rslstr->ident == TEX_IDENT){ txd = (RslTexDictionary*)rslstr->data; writeTxd: if(extract) RslTexDictionaryForAllTextures(txd, dumpTextureCB, NULL); TexDictionary *rwtxd = convertTXD(txd); if(argc > 1) assert(stream.open(argv[1], "wb")); else assert(stream.open("out.txd", "wb")); rwtxd->streamWrite(&stream); stream.close(); } return 0; }