mirror of
https://github.com/aap/librw.git
synced 2024-11-24 20:55:41 +00:00
basic PS2 instancing
This commit is contained in:
parent
e9f638db05
commit
d832570142
139
dumprwtree.cpp
Normal file
139
dumprwtree.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <new>
|
||||
|
||||
#include "rw.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace rw;
|
||||
|
||||
const char *chunks[] = { "None", "Struct", "String", "Extension", "Unknown",
|
||||
"Camera", "Texture", "Material", "Material List", "Atomic Section",
|
||||
"Plane Section", "World", "Spline", "Matrix", "Frame List",
|
||||
"Geometry", "Clump", "Unknown", "Light", "Unicode String", "Atomic",
|
||||
"Texture Native", "Texture Dictionary", "Animation Database",
|
||||
"Image", "Skin Animation", "Geometry List", "Anim Animation",
|
||||
"Team", "Crowd", "Delta Morph Animation", "Right To Render",
|
||||
"MultiTexture Effect Native", "MultiTexture Effect Dictionary",
|
||||
"Team Dictionary", "Platform Independet Texture Dictionary",
|
||||
"Table of Contents", "Particle Standard Global Data", "AltPipe",
|
||||
"Platform Independet Peds", "Patch Mesh", "Chunk Group Start",
|
||||
"Chunk Group End", "UV Animation Dictionary", "Coll Tree"
|
||||
};
|
||||
|
||||
/* From 0x0101 through 0x0135 */
|
||||
const char *toolkitchunks0[] = { "Metrics PLG", "Spline PLG", "Stereo PLG",
|
||||
"VRML PLG", "Morph PLG", "PVS PLG", "Memory Leak PLG", "Animation PLG",
|
||||
"Gloss PLG", "Logo PLG", "Memory Info PLG", "Random PLG",
|
||||
"PNG Image PLG", "Bone PLG", "VRML Anim PLG", "Sky Mipmap Val",
|
||||
"MRM PLG", "LOD Atomic PLG", "ME PLG", "Lightmap PLG",
|
||||
"Refine PLG", "Skin PLG", "Label PLG", "Particles PLG", "GeomTX PLG",
|
||||
"Synth Core PLG", "STQPP PLG",
|
||||
"Part PP PLG", "Collision PLG", "HAnim PLG", "User Data PLG",
|
||||
"Material Effects PLG", "Particle System PLG", "Delta Morph PLG",
|
||||
"Patch PLG", "Team PLG", "Crowd PP PLG", "Mip Split PLG",
|
||||
"Anisotrophy PLG", "Not used", "GCN Material PLG", "Geometric PVS PLG",
|
||||
"XBOX Material PLG", "Multi Texture PLG", "Chain PLG", "Toon PLG",
|
||||
"PTank PLG", "Particle Standard PLG", "PDS PLG", "PrtAdv PLG",
|
||||
"Normal Map PLG", "ADC PLG", "UV Animation PLG"
|
||||
};
|
||||
|
||||
/* From 0x0180 through 0x01c1 */
|
||||
const char *toolkitchunks1[] = {
|
||||
"Character Set PLG", "NOHS World PLG", "Import Util PLG",
|
||||
"Slerp PLG", "Optim PLG", "TL World PLG", "Database PLG",
|
||||
"Raytrace PLG", "Ray PLG", "Library PLG",
|
||||
"Not used", "Not used", "Not used", "Not used", "Not used", "Not used",
|
||||
"2D PLG", "Tile Render PLG", "JPEG Image PLG", "TGA Image PLG",
|
||||
"GIF Image PLG", "Quat PLG", "Spline PVS PLG", "Mipmap PLG",
|
||||
"MipmapK PLG", "2D Font", "Intersection PLG", "TIFF Image PLG",
|
||||
"Pick PLG", "BMP Image PLG", "RAS Image PLG", "Skin FX PLG",
|
||||
"VCAT PLG", "2D Path", "2D Brush", "2D Object", "2D Shape", "2D Scene",
|
||||
"2D Pick Region", "2D Object String", "2D Animation PLG",
|
||||
"2D Animation",
|
||||
"Not used", "Not used", "Not used", "Not used", "Not used", "Not used",
|
||||
"2D Keyframe", "2D Maestro", "Barycentric",
|
||||
"Platform Independent Texture Dictionary TK", "TOC TK", "TPL TK",
|
||||
"AltPipe TK", "Animation TK", "Skin Split Tookit", "Compressed Key TK",
|
||||
"Geometry Conditioning PLG", "Wing PLG", "Generic Pipeline TK",
|
||||
"Lightmap Conversion TK", "Filesystem PLG", "Dictionary TK",
|
||||
"UV Animation Linear", "UV Animation Parameter"
|
||||
};
|
||||
|
||||
const char *RSchunks[] = { "Unused 1", "Unused 2", "Unused 3",
|
||||
"Pipeline Set", "Unused 5", "Unused 6", "Specular Material",
|
||||
"Unused 8", "2dfx", "Night Vertex Colors", "Collision Model",
|
||||
"Unused 12", "Reflection Material", "Mesh Extension", "Frame",
|
||||
"Unused 16"
|
||||
};
|
||||
|
||||
const char*
|
||||
getChunkName(uint32 id)
|
||||
{
|
||||
switch(id){
|
||||
case 0x50E:
|
||||
return "Bin Mesh PLG";
|
||||
case 0x510:
|
||||
return "Native Data PLG";
|
||||
case 0xF21E:
|
||||
return "ZModeler Lock";
|
||||
}
|
||||
|
||||
if(id <= 45)
|
||||
return chunks[id];
|
||||
else if(id <= 0x0253F2FF && id >= 0x0253F2F0)
|
||||
return RSchunks[id-0x0253F2F0];
|
||||
else if(id <= 0x0135 && id >= 0x0101)
|
||||
return toolkitchunks0[id-0x0101];
|
||||
else if(id <= 0x01C0 && id >= 0x0181)
|
||||
return toolkitchunks1[id-0x0181];
|
||||
else
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
void
|
||||
readchunk(StreamFile *s, ChunkHeaderInfo *h, int level)
|
||||
{
|
||||
for(int i = 0; i < level; i++)
|
||||
printf(" ");
|
||||
const char *name = getChunkName(h->type);
|
||||
printf("%s (%x bytes @ 0x%x/0x%x) - [0x%x]\n",
|
||||
name, h->length, s->tell()-12, s->tell(), h->type);
|
||||
|
||||
uint32 end = s->tell() + h->length;
|
||||
while(s->tell() < end){
|
||||
ChunkHeaderInfo nh;
|
||||
readChunkHeaderInfo(s, &nh);
|
||||
if(nh.version == h->version && nh.build == h->build){
|
||||
readchunk(s, &nh, level+1);
|
||||
if(h->type == 0x510)
|
||||
s->seek(end, 0);
|
||||
}else{
|
||||
s->seek(h->length-12);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if(argc < 2){
|
||||
fprintf(stderr, "usage: %s rwStreamFile\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
StreamFile s;
|
||||
s.open(argv[1], "rb");
|
||||
|
||||
ChunkHeaderInfo header;
|
||||
readChunkHeaderInfo(&s, &header);
|
||||
readchunk(&s, &header, 0);
|
||||
|
||||
printf("%x %x %x\n", header.version, header.build,
|
||||
libraryIDPack(header.version, header.build));
|
||||
|
||||
s.close();
|
||||
return 0;
|
||||
}
|
100
insttest.cpp
Normal file
100
insttest.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <new>
|
||||
|
||||
#include "rw.h"
|
||||
#include "src/gtaplg.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace rw;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
rw::version = 0x33002;
|
||||
gta::registerEnvSpecPlugin();
|
||||
rw::registerMatFXPlugin();
|
||||
rw::registerMaterialRightsPlugin();
|
||||
rw::registerAtomicRightsPlugin();
|
||||
rw::registerHAnimPlugin();
|
||||
gta::registerNodeNamePlugin();
|
||||
gta::registerBreakableModelPlugin();
|
||||
gta::registerExtraVertColorPlugin();
|
||||
rw::ps2::registerADCPlugin();
|
||||
rw::registerSkinPlugin();
|
||||
rw::registerNativeDataPlugin();
|
||||
rw::registerMeshPlugin();
|
||||
|
||||
rw::platform = rw::PLATFORM_PS2;
|
||||
|
||||
rw::Pipeline *defpipe = rw::ps2::makeDefaultPipeline();
|
||||
rw::Pipeline *skinpipe = rw::ps2::makeSkinPipeline();
|
||||
// rw::ps2::dumpPipeline(defpipe);
|
||||
// rw::ps2::dumpPipeline(skinpipe);
|
||||
|
||||
int uninstance = 0;
|
||||
int arg = 1;
|
||||
|
||||
if(argc < 2){
|
||||
printf("usage: %s [-u] ps2.dff\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(strcmp(argv[arg], "-u") == 0){
|
||||
uninstance++;
|
||||
arg++;
|
||||
if(argc < 3){
|
||||
printf("usage: %s [-u] ps2.dff\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Clump *c;
|
||||
uint32 len;
|
||||
uint8 *data = getFileContents(argv[arg], &len);
|
||||
assert(data != NULL);
|
||||
StreamMemory in;
|
||||
in.open(data, len);
|
||||
findChunk(&in, ID_CLUMP, NULL, NULL);
|
||||
debugFile = argv[arg];
|
||||
c = Clump::streamRead(&in);
|
||||
assert(c != NULL);
|
||||
|
||||
for(int32 i = 0; i < c->numAtomics; i++){
|
||||
Atomic *a = c->atomicList[i];
|
||||
if(a->pipeline){
|
||||
printf("has pipeline %x %x %x\n",
|
||||
a->pipeline->pluginID,
|
||||
a->pipeline->pluginData,
|
||||
a->pipeline->platform);
|
||||
if(uninstance)
|
||||
a->pipeline->uninstance(a);
|
||||
else
|
||||
a->pipeline->instance(a);
|
||||
}else{
|
||||
printf("default pipeline\n");
|
||||
if(uninstance)
|
||||
defpipe->uninstance(a);
|
||||
else
|
||||
defpipe->instance(a);
|
||||
}
|
||||
}
|
||||
|
||||
data = new rw::uint8[256*1024];
|
||||
rw::StreamMemory out;
|
||||
out.open(data, 0, 256*1024);
|
||||
c->streamWrite(&out);
|
||||
|
||||
FILE *cf = fopen("out.dff", "wb");
|
||||
assert(cf != NULL);
|
||||
fwrite(data, out.getLength(), 1, cf);
|
||||
fclose(cf);
|
||||
out.close();
|
||||
delete[] data;
|
||||
|
||||
delete c;
|
||||
|
||||
return 0;
|
||||
}
|
985
src/image.cpp
985
src/image.cpp
@ -1,492 +1,493 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwplugin.h"
|
||||
#include "rwpipeline.h"
|
||||
#include "rwobjects.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace rw {
|
||||
|
||||
//
|
||||
// TexDictionary
|
||||
//
|
||||
|
||||
TexDictionary *currentTexDictionary;
|
||||
|
||||
TexDictionary::TexDictionary(void)
|
||||
{
|
||||
this->first = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
TexDictionary::add(Texture *tex)
|
||||
{
|
||||
tex->next = this->first;
|
||||
this->first = tex;
|
||||
}
|
||||
|
||||
Texture*
|
||||
TexDictionary::find(const char *name)
|
||||
{
|
||||
for(Texture *tex = this->first; tex; tex = tex->next)
|
||||
if(strncmp(tex->name, name, 32) == 0)
|
||||
return tex;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Texture
|
||||
//
|
||||
|
||||
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->next = NULL;
|
||||
this->constructPlugins();
|
||||
}
|
||||
|
||||
Texture::~Texture(void)
|
||||
{
|
||||
this->destructPlugins();
|
||||
}
|
||||
|
||||
void
|
||||
Texture::decRef(void)
|
||||
{
|
||||
this->refCount--;
|
||||
if(this->refCount)
|
||||
delete this;
|
||||
}
|
||||
|
||||
// TODO: do this properly, pretty ugly right now
|
||||
Texture*
|
||||
Texture::read(const char *name, const char *mask)
|
||||
{
|
||||
(void)mask;
|
||||
Raster *raster = NULL;
|
||||
Texture *tex;
|
||||
|
||||
if(currentTexDictionary && (tex = currentTexDictionary->find(name)))
|
||||
return tex;
|
||||
tex = new Texture;
|
||||
strncpy(tex->name, name, 32);
|
||||
strncpy(tex->mask, mask, 32);
|
||||
char *n = (char*)malloc(strlen(name) + 5);
|
||||
strcpy(n, name);
|
||||
strcat(n, ".tga");
|
||||
Image *img = readTGA(n);
|
||||
free(n);
|
||||
if(img){
|
||||
raster = Raster::createFromImage(img);
|
||||
delete img;
|
||||
}
|
||||
tex->raster = raster;
|
||||
if(currentTexDictionary)
|
||||
currentTexDictionary->add(tex);
|
||||
return tex;
|
||||
}
|
||||
|
||||
Texture*
|
||||
Texture::streamRead(Stream *stream)
|
||||
{
|
||||
uint32 length;
|
||||
char name[32], mask[32];
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
|
||||
uint32 filterAddressing = stream->readU16();
|
||||
// TODO: what is this? (mipmap? i think)
|
||||
stream->seek(2);
|
||||
|
||||
assert(findChunk(stream, ID_STRING, &length, NULL));
|
||||
stream->read(name, length);
|
||||
|
||||
assert(findChunk(stream, ID_STRING, &length, NULL));
|
||||
stream->read(mask, length);
|
||||
|
||||
Texture *tex = Texture::read(name, mask);
|
||||
tex->refCount++;
|
||||
tex->filterAddressing = filterAddressing;
|
||||
|
||||
tex->streamReadPlugins(stream);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
bool
|
||||
Texture::streamWrite(Stream *stream)
|
||||
{
|
||||
int size;
|
||||
writeChunkHeader(stream, ID_TEXTURE, this->streamGetSize());
|
||||
writeChunkHeader(stream, ID_STRUCT, 4);
|
||||
stream->writeU32(this->filterAddressing);
|
||||
|
||||
// TODO: length can't be > 32
|
||||
size = strlen(this->name)+4 & ~3;
|
||||
writeChunkHeader(stream, ID_STRING, size);
|
||||
stream->write(this->name, size);
|
||||
|
||||
size = strlen(this->mask)+4 & ~3;
|
||||
writeChunkHeader(stream, ID_STRING, size);
|
||||
stream->write(this->mask, size);
|
||||
|
||||
this->streamWritePlugins(stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32
|
||||
Texture::streamGetSize(void)
|
||||
{
|
||||
uint32 size = 0;
|
||||
size += 12 + 4;
|
||||
size += 12 + 12;
|
||||
size += strlen(this->name)+4 & ~3;
|
||||
size += strlen(this->mask)+4 & ~3;
|
||||
size += 12 + this->streamGetPluginSize();
|
||||
return size;
|
||||
}
|
||||
|
||||
//
|
||||
// Image
|
||||
//
|
||||
|
||||
Image::Image(int32 width, int32 height, int32 depth)
|
||||
{
|
||||
this->flags = 0;
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->depth = depth;
|
||||
this->stride = 0;
|
||||
this->pixels = NULL;
|
||||
this->palette = NULL;
|
||||
}
|
||||
|
||||
Image::~Image(void)
|
||||
{
|
||||
this->free();
|
||||
}
|
||||
|
||||
void
|
||||
Image::allocate(void)
|
||||
{
|
||||
if(this->pixels == NULL){
|
||||
this->stride = this->width*(this->depth==4 ? 1 : this->depth/8);
|
||||
this->pixels = new uint8[this->stride*this->height];
|
||||
this->flags |= 1;
|
||||
}
|
||||
if(this->palette == NULL){
|
||||
if(this->depth == 4 || this->depth == 8)
|
||||
this->palette = new uint8[(this->depth==4? 16 : 256)*4];
|
||||
this->flags |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Image::free(void)
|
||||
{
|
||||
if(this->flags&1)
|
||||
delete[] this->pixels;
|
||||
if(this->flags&2)
|
||||
delete[] this->palette;
|
||||
}
|
||||
|
||||
void
|
||||
Image::setPixels(uint8 *pixels)
|
||||
{
|
||||
this->pixels = pixels;
|
||||
this->flags |= 1;
|
||||
}
|
||||
|
||||
void
|
||||
Image::setPalette(uint8 *palette)
|
||||
{
|
||||
this->palette = 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
|
||||
//
|
||||
|
||||
#ifndef RW_PS2
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
#define PACKED_STRUCT
|
||||
#else
|
||||
#define PACKED_STRUCT __attribute__((__packed__))
|
||||
#endif
|
||||
struct PACKED_STRUCT TGAHeader
|
||||
{
|
||||
int8 IDlen;
|
||||
int8 colorMapType;
|
||||
int8 imageType;
|
||||
int16 colorMapOrigin;
|
||||
int16 colorMapLength;
|
||||
int8 colorMapDepth;
|
||||
int16 xOrigin, yOrigin;
|
||||
int16 width, height;
|
||||
uint8 depth;
|
||||
uint8 descriptor;
|
||||
};
|
||||
#ifndef RW_PS2
|
||||
#pragma pack(push)
|
||||
#endif
|
||||
|
||||
Image*
|
||||
readTGA(const char *afilename)
|
||||
{
|
||||
TGAHeader header;
|
||||
Image *image;
|
||||
char *filename;
|
||||
int depth = 0, palDepth = 0;
|
||||
filename = Image::getFilename(afilename);
|
||||
if(filename == NULL)
|
||||
return NULL;
|
||||
uint32 length;
|
||||
uint8 *data = getFileContents(filename, &length);
|
||||
assert(data != NULL);
|
||||
free(filename);
|
||||
StreamMemory file;
|
||||
file.open(data, length);
|
||||
file.read(&header, sizeof(header));
|
||||
|
||||
assert(header.imageType == 1 || header.imageType == 2);
|
||||
file.seek(header.IDlen);
|
||||
if(header.colorMapType){
|
||||
assert(header.colorMapOrigin == 0);
|
||||
depth = (header.colorMapLength <= 16) ? 4 : 8;
|
||||
palDepth = header.colorMapDepth;
|
||||
assert(palDepth == 24 || palDepth == 32);
|
||||
}else{
|
||||
depth = header.depth;
|
||||
assert(depth == 24 || depth == 32);
|
||||
}
|
||||
|
||||
image = new Image(header.width, header.height, depth);
|
||||
image->allocate();
|
||||
uint8 *palette = header.colorMapType ? image->palette : NULL;
|
||||
uint8 (*color)[4] = NULL;
|
||||
if(palette){
|
||||
int maxlen = depth == 4 ? 16 : 256;
|
||||
color = (uint8(*)[4])palette;
|
||||
int i;
|
||||
for(i = 0; i < header.colorMapLength; i++){
|
||||
color[i][2] = file.readU8();
|
||||
color[i][1] = file.readU8();
|
||||
color[i][0] = file.readU8();
|
||||
color[i][3] = 0xFF;
|
||||
if(palDepth == 32)
|
||||
color[i][3] = file.readU8();
|
||||
}
|
||||
for(; i < maxlen; i++){
|
||||
color[i][0] = color[i][1] = color[i][2] = 0;
|
||||
color[i][3] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 *pixels = image->pixels;
|
||||
if(!(header.descriptor & 0x20))
|
||||
pixels += (image->height-1)*image->stride;
|
||||
for(int y = 0; y < image->height; y++){
|
||||
uint8 *line = pixels;
|
||||
for(int x = 0; x < image->width; x++){
|
||||
if(palette)
|
||||
*line++ = file.readU8();
|
||||
else{
|
||||
line[2] = file.readU8();
|
||||
line[1] = file.readU8();
|
||||
line[0] = file.readU8();
|
||||
line += 3;
|
||||
if(depth == 32)
|
||||
*line++ = file.readU8();
|
||||
}
|
||||
}
|
||||
pixels += (header.descriptor&0x20) ?
|
||||
image->stride : -image->stride;
|
||||
}
|
||||
|
||||
file.close();
|
||||
delete[] data;
|
||||
return image;
|
||||
}
|
||||
|
||||
void
|
||||
writeTGA(Image *image, const char *filename)
|
||||
{
|
||||
TGAHeader header;
|
||||
StreamFile file;
|
||||
assert(file.open(filename, "wb"));
|
||||
header.IDlen = 0;
|
||||
header.imageType = image->palette != NULL ? 1 : 2;
|
||||
header.colorMapType = image->palette != NULL;
|
||||
header.colorMapOrigin = 0;
|
||||
header.colorMapLength = image->depth == 4 ? 16 :
|
||||
image->depth == 8 ? 256 : 0;
|
||||
header.colorMapDepth = image->palette ? 32 : 0;
|
||||
header.xOrigin = 0;
|
||||
header.yOrigin = 0;
|
||||
header.width = image->width;
|
||||
header.height = image->height;
|
||||
header.depth = image->depth == 4 ? 8 : image->depth;
|
||||
header.descriptor = 0x20 | (image->depth == 32 ? 8 : 0);
|
||||
file.write(&header, sizeof(header));
|
||||
|
||||
uint8 *pixels = image->pixels;
|
||||
uint8 *palette = header.colorMapType ? image->palette : NULL;
|
||||
uint8 (*color)[4] = (uint8(*)[4])palette;;
|
||||
if(palette)
|
||||
for(int i = 0; i < header.colorMapLength; i++){
|
||||
file.writeU8(color[i][2]);
|
||||
file.writeU8(color[i][1]);
|
||||
file.writeU8(color[i][0]);
|
||||
file.writeU8(color[i][3]);
|
||||
}
|
||||
|
||||
for(int y = 0; y < image->height; y++){
|
||||
uint8 *line = pixels;
|
||||
for(int x = 0; x < image->width; x++){
|
||||
if(palette)
|
||||
file.writeU8(*line++);
|
||||
else{
|
||||
file.writeU8(line[2]);
|
||||
file.writeU8(line[1]);
|
||||
file.writeU8(line[0]);
|
||||
line += 3;
|
||||
if(image->depth == 32)
|
||||
file.writeU8(*line++);
|
||||
}
|
||||
}
|
||||
pixels += image->stride;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwplugin.h"
|
||||
#include "rwpipeline.h"
|
||||
#include "rwobjects.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace rw {
|
||||
|
||||
//
|
||||
// TexDictionary
|
||||
//
|
||||
|
||||
TexDictionary *currentTexDictionary;
|
||||
|
||||
TexDictionary::TexDictionary(void)
|
||||
{
|
||||
this->first = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
TexDictionary::add(Texture *tex)
|
||||
{
|
||||
tex->next = this->first;
|
||||
this->first = tex;
|
||||
}
|
||||
|
||||
Texture*
|
||||
TexDictionary::find(const char *name)
|
||||
{
|
||||
for(Texture *tex = this->first; tex; tex = tex->next)
|
||||
if(strncmp(tex->name, name, 32) == 0)
|
||||
return tex;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Texture
|
||||
//
|
||||
|
||||
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->next = NULL;
|
||||
this->constructPlugins();
|
||||
}
|
||||
|
||||
Texture::~Texture(void)
|
||||
{
|
||||
this->destructPlugins();
|
||||
}
|
||||
|
||||
void
|
||||
Texture::decRef(void)
|
||||
{
|
||||
this->refCount--;
|
||||
if(this->refCount)
|
||||
delete this;
|
||||
}
|
||||
|
||||
// TODO: do this properly, pretty ugly right now
|
||||
Texture*
|
||||
Texture::read(const char *name, const char *mask)
|
||||
{
|
||||
(void)mask;
|
||||
Raster *raster = NULL;
|
||||
Texture *tex;
|
||||
|
||||
if(currentTexDictionary && (tex = currentTexDictionary->find(name)))
|
||||
return tex;
|
||||
tex = new Texture;
|
||||
strncpy(tex->name, name, 32);
|
||||
strncpy(tex->mask, mask, 32);
|
||||
char *n = (char*)malloc(strlen(name) + 5);
|
||||
strcpy(n, name);
|
||||
strcat(n, ".tga");
|
||||
Image *img = readTGA(n);
|
||||
free(n);
|
||||
if(img){
|
||||
raster = Raster::createFromImage(img);
|
||||
delete img;
|
||||
}
|
||||
tex->raster = raster;
|
||||
if(currentTexDictionary)
|
||||
currentTexDictionary->add(tex);
|
||||
return tex;
|
||||
}
|
||||
|
||||
Texture*
|
||||
Texture::streamRead(Stream *stream)
|
||||
{
|
||||
uint32 length;
|
||||
char name[32], mask[32];
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
|
||||
uint32 filterAddressing = stream->readU16();
|
||||
// TODO: what is this? (mipmap? i think)
|
||||
stream->seek(2);
|
||||
|
||||
assert(findChunk(stream, ID_STRING, &length, NULL));
|
||||
stream->read(name, length);
|
||||
|
||||
assert(findChunk(stream, ID_STRING, &length, NULL));
|
||||
stream->read(mask, length);
|
||||
|
||||
Texture *tex = Texture::read(name, mask);
|
||||
tex->refCount++;
|
||||
tex->filterAddressing = filterAddressing;
|
||||
|
||||
tex->streamReadPlugins(stream);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
bool
|
||||
Texture::streamWrite(Stream *stream)
|
||||
{
|
||||
int size;
|
||||
writeChunkHeader(stream, ID_TEXTURE, this->streamGetSize());
|
||||
writeChunkHeader(stream, ID_STRUCT, 4);
|
||||
stream->writeU32(this->filterAddressing);
|
||||
|
||||
// TODO: length can't be > 32
|
||||
size = strlen(this->name)+4 & ~3;
|
||||
writeChunkHeader(stream, ID_STRING, size);
|
||||
stream->write(this->name, size);
|
||||
|
||||
size = strlen(this->mask)+4 & ~3;
|
||||
writeChunkHeader(stream, ID_STRING, size);
|
||||
stream->write(this->mask, size);
|
||||
|
||||
this->streamWritePlugins(stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32
|
||||
Texture::streamGetSize(void)
|
||||
{
|
||||
uint32 size = 0;
|
||||
size += 12 + 4;
|
||||
size += 12 + 12;
|
||||
size += strlen(this->name)+4 & ~3;
|
||||
size += strlen(this->mask)+4 & ~3;
|
||||
size += 12 + this->streamGetPluginSize();
|
||||
return size;
|
||||
}
|
||||
|
||||
//
|
||||
// Image
|
||||
//
|
||||
|
||||
Image::Image(int32 width, int32 height, int32 depth)
|
||||
{
|
||||
this->flags = 0;
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->depth = depth;
|
||||
this->stride = 0;
|
||||
this->pixels = NULL;
|
||||
this->palette = NULL;
|
||||
}
|
||||
|
||||
Image::~Image(void)
|
||||
{
|
||||
this->free();
|
||||
}
|
||||
|
||||
void
|
||||
Image::allocate(void)
|
||||
{
|
||||
if(this->pixels == NULL){
|
||||
this->stride = this->width*(this->depth==4 ? 1 : this->depth/8);
|
||||
this->pixels = new uint8[this->stride*this->height];
|
||||
this->flags |= 1;
|
||||
}
|
||||
if(this->palette == NULL){
|
||||
if(this->depth == 4 || this->depth == 8)
|
||||
this->palette = new uint8[(this->depth==4? 16 : 256)*4];
|
||||
this->flags |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Image::free(void)
|
||||
{
|
||||
if(this->flags&1)
|
||||
delete[] this->pixels;
|
||||
if(this->flags&2)
|
||||
delete[] this->palette;
|
||||
}
|
||||
|
||||
void
|
||||
Image::setPixels(uint8 *pixels)
|
||||
{
|
||||
this->pixels = pixels;
|
||||
this->flags |= 1;
|
||||
}
|
||||
|
||||
void
|
||||
Image::setPalette(uint8 *palette)
|
||||
{
|
||||
this->palette = 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
|
||||
//
|
||||
|
||||
// TODO: fuck pakced structs
|
||||
#ifndef RW_PS2
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
#define PACKED_STRUCT
|
||||
#else
|
||||
#define PACKED_STRUCT __attribute__((__packed__))
|
||||
#endif
|
||||
struct PACKED_STRUCT TGAHeader
|
||||
{
|
||||
int8 IDlen;
|
||||
int8 colorMapType;
|
||||
int8 imageType;
|
||||
int16 colorMapOrigin;
|
||||
int16 colorMapLength;
|
||||
int8 colorMapDepth;
|
||||
int16 xOrigin, yOrigin;
|
||||
int16 width, height;
|
||||
uint8 depth;
|
||||
uint8 descriptor;
|
||||
};
|
||||
#ifndef RW_PS2
|
||||
#pragma pack(push)
|
||||
#endif
|
||||
|
||||
Image*
|
||||
readTGA(const char *afilename)
|
||||
{
|
||||
TGAHeader header;
|
||||
Image *image;
|
||||
char *filename;
|
||||
int depth = 0, palDepth = 0;
|
||||
filename = Image::getFilename(afilename);
|
||||
if(filename == NULL)
|
||||
return NULL;
|
||||
uint32 length;
|
||||
uint8 *data = getFileContents(filename, &length);
|
||||
assert(data != NULL);
|
||||
free(filename);
|
||||
StreamMemory file;
|
||||
file.open(data, length);
|
||||
file.read(&header, sizeof(header));
|
||||
|
||||
assert(header.imageType == 1 || header.imageType == 2);
|
||||
file.seek(header.IDlen);
|
||||
if(header.colorMapType){
|
||||
assert(header.colorMapOrigin == 0);
|
||||
depth = (header.colorMapLength <= 16) ? 4 : 8;
|
||||
palDepth = header.colorMapDepth;
|
||||
assert(palDepth == 24 || palDepth == 32);
|
||||
}else{
|
||||
depth = header.depth;
|
||||
assert(depth == 24 || depth == 32);
|
||||
}
|
||||
|
||||
image = new Image(header.width, header.height, depth);
|
||||
image->allocate();
|
||||
uint8 *palette = header.colorMapType ? image->palette : NULL;
|
||||
uint8 (*color)[4] = NULL;
|
||||
if(palette){
|
||||
int maxlen = depth == 4 ? 16 : 256;
|
||||
color = (uint8(*)[4])palette;
|
||||
int i;
|
||||
for(i = 0; i < header.colorMapLength; i++){
|
||||
color[i][2] = file.readU8();
|
||||
color[i][1] = file.readU8();
|
||||
color[i][0] = file.readU8();
|
||||
color[i][3] = 0xFF;
|
||||
if(palDepth == 32)
|
||||
color[i][3] = file.readU8();
|
||||
}
|
||||
for(; i < maxlen; i++){
|
||||
color[i][0] = color[i][1] = color[i][2] = 0;
|
||||
color[i][3] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 *pixels = image->pixels;
|
||||
if(!(header.descriptor & 0x20))
|
||||
pixels += (image->height-1)*image->stride;
|
||||
for(int y = 0; y < image->height; y++){
|
||||
uint8 *line = pixels;
|
||||
for(int x = 0; x < image->width; x++){
|
||||
if(palette)
|
||||
*line++ = file.readU8();
|
||||
else{
|
||||
line[2] = file.readU8();
|
||||
line[1] = file.readU8();
|
||||
line[0] = file.readU8();
|
||||
line += 3;
|
||||
if(depth == 32)
|
||||
*line++ = file.readU8();
|
||||
}
|
||||
}
|
||||
pixels += (header.descriptor&0x20) ?
|
||||
image->stride : -image->stride;
|
||||
}
|
||||
|
||||
file.close();
|
||||
delete[] data;
|
||||
return image;
|
||||
}
|
||||
|
||||
void
|
||||
writeTGA(Image *image, const char *filename)
|
||||
{
|
||||
TGAHeader header;
|
||||
StreamFile file;
|
||||
assert(file.open(filename, "wb"));
|
||||
header.IDlen = 0;
|
||||
header.imageType = image->palette != NULL ? 1 : 2;
|
||||
header.colorMapType = image->palette != NULL;
|
||||
header.colorMapOrigin = 0;
|
||||
header.colorMapLength = image->depth == 4 ? 16 :
|
||||
image->depth == 8 ? 256 : 0;
|
||||
header.colorMapDepth = image->palette ? 32 : 0;
|
||||
header.xOrigin = 0;
|
||||
header.yOrigin = 0;
|
||||
header.width = image->width;
|
||||
header.height = image->height;
|
||||
header.depth = image->depth == 4 ? 8 : image->depth;
|
||||
header.descriptor = 0x20 | (image->depth == 32 ? 8 : 0);
|
||||
file.write(&header, sizeof(header));
|
||||
|
||||
uint8 *pixels = image->pixels;
|
||||
uint8 *palette = header.colorMapType ? image->palette : NULL;
|
||||
uint8 (*color)[4] = (uint8(*)[4])palette;;
|
||||
if(palette)
|
||||
for(int i = 0; i < header.colorMapLength; i++){
|
||||
file.writeU8(color[i][2]);
|
||||
file.writeU8(color[i][1]);
|
||||
file.writeU8(color[i][0]);
|
||||
file.writeU8(color[i][3]);
|
||||
}
|
||||
|
||||
for(int y = 0; y < image->height; y++){
|
||||
uint8 *line = pixels;
|
||||
for(int x = 0; x < image->width; x++){
|
||||
if(palette)
|
||||
file.writeU8(*line++);
|
||||
else{
|
||||
file.writeU8(line[2]);
|
||||
file.writeU8(line[1]);
|
||||
file.writeU8(line[0]);
|
||||
line += 3;
|
||||
if(image->depth == 32)
|
||||
file.writeU8(*line++);
|
||||
}
|
||||
}
|
||||
pixels += image->stride;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
54
src/pipeline.cpp
Normal file
54
src/pipeline.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwplugin.h"
|
||||
#include "rwpipeline.h"
|
||||
#include "rwobjects.h"
|
||||
#include "rwps2.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace rw {
|
||||
|
||||
Pipeline::Pipeline(uint32 platform)
|
||||
{
|
||||
this->pluginID = 0;
|
||||
this->pluginData = 0;
|
||||
this->platform = platform;
|
||||
for(int i = 0; i < 10; i++)
|
||||
this->attribs[i] = NULL;
|
||||
}
|
||||
|
||||
Pipeline::Pipeline(Pipeline *)
|
||||
{
|
||||
assert(0 && "Can't copy pipeline");
|
||||
}
|
||||
|
||||
Pipeline::~Pipeline(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Pipeline::instance(Atomic *atomic)
|
||||
{
|
||||
fprintf(stderr, "This pipeline can't instance\n");
|
||||
}
|
||||
|
||||
void
|
||||
Pipeline::uninstance(Atomic *atomic)
|
||||
{
|
||||
fprintf(stderr, "This pipeline can't uninstance\n");
|
||||
}
|
||||
|
||||
void
|
||||
Pipeline::render(Atomic *atomic)
|
||||
{
|
||||
fprintf(stderr, "This pipeline can't render\n");
|
||||
}
|
||||
|
||||
}
|
@ -554,7 +554,8 @@ registerSkinPlugin(void)
|
||||
defpipe->pluginData = 1;
|
||||
for(uint i = 0; i < nelem(matFXGlobals.pipelines); i++)
|
||||
skinGlobals.pipelines[i] = defpipe;
|
||||
|
||||
skinGlobals.pipelines[platformIdx[PLATFORM_PS2]] =
|
||||
ps2::makeSkinPipeline();
|
||||
|
||||
skinGlobals.offset = Geometry::registerPlugin(sizeof(Skin*), ID_SKIN,
|
||||
createSkin,
|
||||
@ -883,6 +884,8 @@ registerMatFXPlugin(void)
|
||||
defpipe->pluginData = 0;
|
||||
for(uint i = 0; i < nelem(matFXGlobals.pipelines); i++)
|
||||
matFXGlobals.pipelines[i] = defpipe;
|
||||
matFXGlobals.pipelines[platformIdx[PLATFORM_PS2]] =
|
||||
ps2::makeMatFXPipeline();
|
||||
|
||||
matFXGlobals.atomicOffset =
|
||||
Atomic::registerPlugin(sizeof(int32), ID_MATFX,
|
||||
|
352
src/ps2.cpp
352
src/ps2.cpp
@ -126,7 +126,7 @@ fixDmaOffsets(InstanceData *inst)
|
||||
// DMAref
|
||||
case 0x30000000:
|
||||
// fix address and jump to next
|
||||
tag[1] = base + tag[1]*0x10;
|
||||
tag[1] = base + tag[1]<<4;
|
||||
tag += 4;
|
||||
break;
|
||||
|
||||
@ -165,7 +165,7 @@ unfixDmaOffsets(InstanceData *inst)
|
||||
// DMAref
|
||||
case 0x30000000:
|
||||
// unfix address and jump to next
|
||||
tag[1] = (tag[1] - base)/0x10;
|
||||
tag[1] = (tag[1] - base)>>4;
|
||||
tag += 4;
|
||||
break;
|
||||
|
||||
@ -203,9 +203,8 @@ enum PS2Attribs {
|
||||
enum PS2AttibTypes {
|
||||
AT_XYZ = 0,
|
||||
AT_UV = 1,
|
||||
AT_UV2 = 2,
|
||||
AT_RGBA = 3,
|
||||
AT_NORMAL = 4
|
||||
AT_RGBA = 2,
|
||||
AT_NORMAL = 3
|
||||
};
|
||||
|
||||
PipeAttribute attribXYZ = {
|
||||
@ -241,6 +240,301 @@ PipeAttribute attribWeights = {
|
||||
Pipeline::Pipeline(uint32 platform)
|
||||
: rw::Pipeline(platform) { }
|
||||
|
||||
static uint32
|
||||
attribSize(uint32 unpack)
|
||||
{
|
||||
static uint32 size[] = { 32, 16, 8, 16 };
|
||||
return ((unpack>>26 & 3)+1)*size[unpack>>24 & 3]/8;
|
||||
}
|
||||
|
||||
#define QWC(x) (((x)+0xF)>>4)
|
||||
|
||||
static uint32
|
||||
getBatchSize(Pipeline *pipe, uint32 vertCount)
|
||||
{
|
||||
PipeAttribute *a;
|
||||
uint32 size = 1;
|
||||
for(uint i = 0; i < nelem(pipe->attribs); i++)
|
||||
if((a = pipe->attribs[i]) && (a->attrib & AT_RW) == 0){
|
||||
size++;
|
||||
size += QWC(vertCount*attribSize(a->attrib));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32*
|
||||
instanceXYZ(uint32 *p, Geometry *g, Mesh *m, uint32 idx, uint32 n)
|
||||
{
|
||||
uint16 j;
|
||||
uint32 *d = (uint32*)g->morphTargets[0].vertices;
|
||||
for(uint32 i = idx; i < idx+n; i++){
|
||||
j = m->indices[i];
|
||||
*p++ = d[j*3+0];
|
||||
*p++ = d[j*3+1];
|
||||
*p++ = d[j*3+2];
|
||||
}
|
||||
while((uintptr)p % 0x10)
|
||||
*p++ = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
uint32*
|
||||
instanceUV(uint32 *p, Geometry *g, Mesh *m, uint32 idx, uint32 n)
|
||||
{
|
||||
uint16 j;
|
||||
uint32 *d = (uint32*)g->texCoords[0];
|
||||
if((g->geoflags & Geometry::TEXTURED) ||
|
||||
(g->geoflags & Geometry::TEXTURED2))
|
||||
for(uint32 i = idx; i < idx+n; i++){
|
||||
j = m->indices[i];
|
||||
*p++ = d[j*2+0];
|
||||
*p++ = d[j*2+1];
|
||||
}
|
||||
else
|
||||
for(uint32 i = idx; i < idx+n; i++){
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
}
|
||||
while((uintptr)p % 0x10)
|
||||
*p++ = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
uint32*
|
||||
instanceRGBA(uint32 *p, Geometry *g, Mesh *m, uint32 idx, uint32 n)
|
||||
{
|
||||
uint16 j;
|
||||
uint32 *d = (uint32*)g->colors;
|
||||
if((g->geoflags & Geometry::PRELIT))
|
||||
for(uint32 i = idx; i < idx+n; i++){
|
||||
j = m->indices[i];
|
||||
*p++ = d[j];
|
||||
}
|
||||
else
|
||||
for(uint32 i = idx; i < idx+n; i++)
|
||||
*p++ = 0xFF000000;
|
||||
while((uintptr)p % 0x10)
|
||||
*p++ = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
uint32*
|
||||
instanceNormal(uint32 *wp, Geometry *g, Mesh *m, uint32 idx, uint32 n)
|
||||
{
|
||||
uint16 j;
|
||||
float *d = g->morphTargets[0].normals;
|
||||
uint8 *p = (uint8*)wp;
|
||||
if((g->geoflags & Geometry::NORMALS))
|
||||
for(uint32 i = idx; i < idx+n; i++){
|
||||
j = m->indices[i];
|
||||
*p++ = d[j*3+0]*127.0f;
|
||||
*p++ = d[j*3+1]*127.0f;
|
||||
*p++ = d[j*3+2]*127.0f;
|
||||
}
|
||||
else
|
||||
for(uint32 i = idx; i < idx+n; i++){
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
}
|
||||
while((uintptr)p % 0x10)
|
||||
*p++ = 0;
|
||||
return (uint32*)p;
|
||||
}
|
||||
|
||||
uint32 markcnt = 0xf790;
|
||||
|
||||
static void
|
||||
instanceMat(Pipeline *pipe, Geometry *g, InstanceData *inst, Mesh *m)
|
||||
{
|
||||
PipeAttribute *a;
|
||||
uint32 numAttribs = 0;
|
||||
uint32 numBrokenAttribs = 0;
|
||||
for(uint i = 0; i < nelem(pipe->attribs); i++)
|
||||
if(a = pipe->attribs[i])
|
||||
if(a->attrib & AT_RW)
|
||||
numBrokenAttribs++;
|
||||
else
|
||||
numAttribs++;
|
||||
uint32 numBatches = 0;
|
||||
uint32 totalVerts = 0;
|
||||
uint32 batchVertCount, lastBatchVertCount;
|
||||
if(g->meshHeader->flags == 1){ // tristrip
|
||||
for(uint i = 0; i < m->numIndices; i += pipe->triStripCount-2){
|
||||
numBatches++;
|
||||
totalVerts += m->numIndices-i < pipe->triStripCount ?
|
||||
m->numIndices-i : pipe->triStripCount;
|
||||
}
|
||||
batchVertCount = pipe->triStripCount;
|
||||
lastBatchVertCount = totalVerts%pipe->triStripCount;
|
||||
}else{ // trilist
|
||||
numBatches = (m->numIndices+pipe->triListCount-1) /
|
||||
pipe->triListCount;
|
||||
totalVerts = m->numIndices;
|
||||
batchVertCount = pipe->triListCount;
|
||||
lastBatchVertCount = totalVerts%pipe->triListCount;
|
||||
}
|
||||
|
||||
uint32 batchSize = getBatchSize(pipe, batchVertCount);
|
||||
uint32 lastBatchSize = getBatchSize(pipe, lastBatchVertCount);
|
||||
uint32 size = 0;
|
||||
if(numBrokenAttribs == 0)
|
||||
size = 1 + batchSize*(numBatches-1) + lastBatchSize;
|
||||
else
|
||||
size = 2*numBatches +
|
||||
(1+batchSize)*(numBatches-1) + 1+lastBatchSize;
|
||||
|
||||
/* figure out size and addresses of broken out sections */
|
||||
uint32 attribPos[nelem(pipe->attribs)];
|
||||
uint32 size2 = 0;
|
||||
for(uint i = 0; i < nelem(pipe->attribs); i++)
|
||||
if((a = pipe->attribs[i]) && a->attrib & AT_RW){
|
||||
attribPos[i] = size2 + size;
|
||||
size2 += QWC(m->numIndices*attribSize(a->attrib));
|
||||
}
|
||||
|
||||
/*
|
||||
printf("attribs: %d %d\n", numAttribs, numBrokenAttribs);
|
||||
printf("numIndices: %d\n", m->numIndices);
|
||||
printf("%d %d, %x %x\n", numBatches, totalVerts,
|
||||
batchVertCount, lastBatchVertCount);
|
||||
printf("%x %x\n", batchSize, lastBatchSize);
|
||||
printf("size: %x, %x\n", size, size2);
|
||||
*/
|
||||
|
||||
inst->dataSize = (size+size2)<<4;
|
||||
inst->arePointersFixed = numBrokenAttribs == 0;
|
||||
// TODO: force alignment
|
||||
inst->data = new uint8[inst->dataSize];
|
||||
|
||||
uint32 idx = 0;
|
||||
uint32 *p = (uint32*)inst->data;
|
||||
if(numBrokenAttribs == 0){
|
||||
*p++ = 0x60000000 | size-1;
|
||||
*p++ = 0;
|
||||
*p++ = 0x11000000; // FLUSH
|
||||
*p++ = 0x06000000; // MSKPATH3; SA: FLUSH
|
||||
}
|
||||
for(uint32 j = 0; j < numBatches; j++){
|
||||
uint32 nverts, bsize;
|
||||
if(j < numBatches-1){
|
||||
bsize = batchSize;
|
||||
nverts = batchVertCount;
|
||||
}else{
|
||||
bsize = lastBatchSize;
|
||||
nverts = lastBatchVertCount;
|
||||
}
|
||||
for(uint i = 0; i < nelem(pipe->attribs); i++)
|
||||
if((a = pipe->attribs[i]) && a->attrib & AT_RW){
|
||||
uint32 atsz = attribSize(a->attrib);
|
||||
*p++ = 0x30000000 | QWC(nverts*atsz);
|
||||
*p++ = attribPos[i];
|
||||
*p++ = 0x01000100 |
|
||||
pipe->inputStride; // STCYCL
|
||||
*p++ = (a->attrib&0xFF004000)
|
||||
| 0x8000 | nverts << 16 | i; // UNPACK
|
||||
|
||||
*p++ = 0x10000000;
|
||||
*p++ = 0x0;
|
||||
*p++ = 0x0;
|
||||
*p++ = 0x0;
|
||||
|
||||
attribPos[i] += g->meshHeader->flags == 1 ?
|
||||
QWC((batchVertCount-2)*atsz) :
|
||||
QWC(batchVertCount*atsz);
|
||||
}
|
||||
if(numBrokenAttribs){
|
||||
*p++ = (j < numBatches-1 ? 0x10000000 : 0x60000000) |
|
||||
bsize;
|
||||
*p++ = 0x0;
|
||||
*p++ = 0x0;
|
||||
*p++ = 0x0;
|
||||
}
|
||||
|
||||
for(uint i = 0; i < nelem(pipe->attribs); i++)
|
||||
if((a = pipe->attribs[i]) && (a->attrib & AT_RW) == 0){
|
||||
*p++ = 0x07000000 | markcnt++; // MARK (SA: NOP)
|
||||
*p++ = 0x05000000; // STMOD
|
||||
*p++ = 0x01000100 |
|
||||
pipe->inputStride; // STCYCL
|
||||
*p++ = (a->attrib&0xFF004000)
|
||||
| 0x8000 | nverts << 16 | i; // UNPACK
|
||||
|
||||
// TODO: instance
|
||||
switch(i){
|
||||
case 0:
|
||||
p = instanceXYZ(p, g, m, idx, nverts);
|
||||
break;
|
||||
case 1:
|
||||
p = instanceUV(p, g, m, idx, nverts);
|
||||
break;
|
||||
case 2:
|
||||
p = instanceRGBA(p, g, m, idx, nverts);
|
||||
break;
|
||||
case 3:
|
||||
p = instanceNormal(p,g, m, idx, nverts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
idx += g->meshHeader->flags == 1
|
||||
? batchVertCount-2 : batchVertCount;
|
||||
|
||||
*p++ = 0x04000000 | nverts; // ITOP
|
||||
*p++ = j == 0 ? 0x15000000 : 0x17000000;
|
||||
if(j < numBatches-1){
|
||||
*p++ = 0x0;
|
||||
*p++ = 0x0;
|
||||
}else{
|
||||
*p++ = 0x11000000; // FLUSH
|
||||
*p++ = 0x06000000; // MSKPATH3; SA: FLUSH
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
FILE *f = fopen("out.bin", "w");
|
||||
fwrite(inst->data, inst->dataSize, 1, f);
|
||||
fclose(f);
|
||||
*/
|
||||
}
|
||||
|
||||
#undef QWC
|
||||
|
||||
void
|
||||
Pipeline::instance(Atomic *atomic)
|
||||
{
|
||||
Geometry *geometry = atomic->geometry;
|
||||
InstanceDataHeader *header = new InstanceDataHeader;
|
||||
geometry->instData = header;
|
||||
header->platform = PLATFORM_PS2;
|
||||
assert(geometry->meshHeader != NULL);
|
||||
header->numMeshes = geometry->meshHeader->numMeshes;
|
||||
header->instanceMeshes = new InstanceData[header->numMeshes];
|
||||
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||
Mesh *mesh = &geometry->meshHeader->mesh[i];
|
||||
InstanceData *instance = &header->instanceMeshes[i];
|
||||
// TODO: should depend on material pipeline
|
||||
instanceMat(this, geometry, instance, mesh);
|
||||
//printf("\n");
|
||||
}
|
||||
geometry->geoflags |= Geometry::NATIVE;
|
||||
}
|
||||
|
||||
// Only a dummy right now
|
||||
void
|
||||
Pipeline::uninstance(Atomic *atomic)
|
||||
{
|
||||
Geometry *geometry = atomic->geometry;
|
||||
assert(geometry->instData->platform == PLATFORM_PS2);
|
||||
assert(geometry->instData != NULL);
|
||||
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
||||
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||
Mesh *mesh = &geometry->meshHeader->mesh[i];
|
||||
InstanceData *instance = &header->instanceMeshes[i];
|
||||
printf("numIndices: %d\n", mesh->numIndices);
|
||||
printDMA(instance);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Pipeline::setTriBufferSizes(uint32 inputStride,
|
||||
uint32 stripCount, uint32 listCount)
|
||||
@ -277,6 +571,8 @@ Pipeline*
|
||||
makeSkinPipeline(void)
|
||||
{
|
||||
Pipeline *pipe = new Pipeline(PLATFORM_PS2);
|
||||
pipe->pluginID = ID_SKIN;
|
||||
pipe->pluginData = 1;
|
||||
pipe->attribs[AT_XYZ] = &attribXYZ;
|
||||
pipe->attribs[AT_UV] = &attribUV;
|
||||
pipe->attribs[AT_RGBA] = &attribRGBA;
|
||||
@ -288,6 +584,24 @@ makeSkinPipeline(void)
|
||||
return pipe;
|
||||
}
|
||||
|
||||
Pipeline*
|
||||
makeMatFXPipeline(void)
|
||||
{
|
||||
Pipeline *pipe = new Pipeline(PLATFORM_PS2);
|
||||
pipe->pluginID = ID_MATFX;
|
||||
pipe->pluginData = 0;
|
||||
pipe->attribs[AT_XYZ] = &attribXYZ;
|
||||
pipe->attribs[AT_UV] = &attribUV;
|
||||
pipe->attribs[AT_RGBA] = &attribRGBA;
|
||||
pipe->attribs[AT_NORMAL] = &attribNormal;
|
||||
// TODO: not correct
|
||||
uint32 vertCount = Pipeline::getVertCount(VU_Lights, 4, 3, 2);
|
||||
pipe->setTriBufferSizes(4, vertCount, vertCount/3);
|
||||
pipe->triStripCount = 0x38;
|
||||
pipe->vifOffset = pipe->inputStride*vertCount;
|
||||
return pipe;
|
||||
}
|
||||
|
||||
void
|
||||
dumpPipeline(rw::Pipeline *rwpipe)
|
||||
{
|
||||
@ -454,6 +768,32 @@ registerADCPlugin(void)
|
||||
|
||||
// misc stuff
|
||||
|
||||
void
|
||||
printDMA(InstanceData *inst)
|
||||
{
|
||||
uint32 *tag = (uint32*)inst->data;
|
||||
for(;;){
|
||||
switch(tag[0]&0x70000000){
|
||||
// DMAcnt
|
||||
case 0x10000000:
|
||||
printf("%08x %08x\n", tag[0], tag[1]);
|
||||
tag += (1+(tag[0]&0xFFFF))*4;
|
||||
break;
|
||||
|
||||
// DMAref
|
||||
case 0x30000000:
|
||||
printf("%08x %08x\n", tag[0], tag[1]);
|
||||
tag += 4;
|
||||
break;
|
||||
|
||||
// DMAret
|
||||
case 0x60000000:
|
||||
printf("%08x %08x\n", tag[0], tag[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to specifically walk geometry chains */
|
||||
void
|
||||
walkDMA(InstanceData *inst, void (*f)(uint32 *data, int32 size))
|
||||
@ -471,7 +811,7 @@ walkDMA(InstanceData *inst, void (*f)(uint32 *data, int32 size))
|
||||
break;
|
||||
|
||||
// DMAref
|
||||
case 0x3000000:
|
||||
case 0x30000000:
|
||||
f(base + tag[1]*4, (tag[0]&0xFFFF)*4);
|
||||
tag += 4;
|
||||
break;
|
||||
|
@ -18,7 +18,7 @@ int version = 0x36003;
|
||||
int build = 0xFFFF;
|
||||
#ifdef RW_PS2
|
||||
int platform = PLATFORM_PS2;
|
||||
#elseif RW_OPENGL
|
||||
#elif RW_OPENGL
|
||||
int platform = PLATFORM_OPENGL;
|
||||
#else
|
||||
int platform = PLATFORM_NULL;
|
||||
|
27
src/rwpipeline.h
Normal file
27
src/rwpipeline.h
Normal file
@ -0,0 +1,27 @@
|
||||
namespace rw {
|
||||
|
||||
struct PipeAttribute
|
||||
{
|
||||
const char *name;
|
||||
uint32 attrib;
|
||||
};
|
||||
|
||||
struct Atomic;
|
||||
|
||||
struct Pipeline
|
||||
{
|
||||
uint32 pluginID;
|
||||
uint32 pluginData;
|
||||
|
||||
uint32 platform;
|
||||
PipeAttribute *attribs[10];
|
||||
|
||||
Pipeline(uint32 platform);
|
||||
Pipeline(Pipeline *p);
|
||||
~Pipeline(void);
|
||||
virtual void instance(Atomic *atomic);
|
||||
virtual void uninstance(Atomic *atomic);
|
||||
virtual void render(Atomic *atomic);
|
||||
};
|
||||
|
||||
}
|
@ -29,6 +29,7 @@ void writeNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||
int32 getSizeNativeData(void *object, int32, int32);
|
||||
void registerNativeDataPlugin(void);
|
||||
|
||||
void printDMA(InstanceData *inst);
|
||||
void walkDMA(InstanceData *inst, void (*f)(uint32 *data, int32 size));
|
||||
void sizedebug(InstanceData *inst);
|
||||
|
||||
@ -49,12 +50,16 @@ struct Pipeline : rw::Pipeline
|
||||
}
|
||||
|
||||
Pipeline(uint32 platform);
|
||||
virtual void instance(Atomic *atomic);
|
||||
virtual void uninstance(Atomic *atomic);
|
||||
// virtual void render(Atomic *atomic);
|
||||
void setTriBufferSizes(uint32 inputStride,
|
||||
uint32 stripCount, uint32 listCount);
|
||||
};
|
||||
|
||||
Pipeline *makeDefaultPipeline(void);
|
||||
Pipeline *makeSkinPipeline(void);
|
||||
Pipeline *makeMatFXPipeline(void);
|
||||
void dumpPipeline(rw::Pipeline *pipe);
|
||||
|
||||
// Skin plugin
|
||||
|
@ -109,10 +109,18 @@ dumpRasterPacket(int n)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
rw::Pipeline *defpipe;
|
||||
|
||||
void
|
||||
drawAtomic(rw::Atomic *atomic)
|
||||
{
|
||||
rw::Geometry *geo = atomic->geometry;
|
||||
if(!(geo->geoflags & rw::Geometry::NATIVE)){
|
||||
if(atomic->pipeline)
|
||||
atomic->pipeline->instance(atomic);
|
||||
else
|
||||
defpipe->instance(atomic);
|
||||
}
|
||||
assert(geo->instData != NULL);
|
||||
rw::ps2::InstanceDataHeader *instData =
|
||||
(rw::ps2::InstanceDataHeader*)geo->instData;
|
||||
@ -178,10 +186,10 @@ draw(void)
|
||||
gsClear();
|
||||
|
||||
matMakeIdentity(viewMat);
|
||||
matTranslate(viewMat, 0.0f, 0.0f, -34.0f);
|
||||
// matTranslate(viewMat, 0.0f, 0.0f, -34.0f);
|
||||
// matTranslate(viewMat, 0.0f, 0.0f, -10.0f);
|
||||
// matTranslate(viewMat, 0.0f, 0.0f, -8.0f);
|
||||
// matTranslate(viewMat, 0.0f, 0.0f, -4.0f);
|
||||
matTranslate(viewMat, 0.0f, 0.0f, -4.0f);
|
||||
matRotateX(viewMat, rot);
|
||||
matRotateY(viewMat, rot);
|
||||
matRotateZ(viewMat, rot);
|
||||
@ -199,7 +207,7 @@ draw(void)
|
||||
matCopy(vuMat, m);
|
||||
}
|
||||
|
||||
rot += 0.01f;
|
||||
rot += 0.001f;
|
||||
if(rot > 2*M_PI)
|
||||
rot -= 2*M_PI;
|
||||
}
|
||||
@ -233,9 +241,14 @@ main()
|
||||
// rw::ps2::registerNativeDataPlugin();
|
||||
rw::registerMeshPlugin();
|
||||
|
||||
defpipe = rw::ps2::makeDefaultPipeline();
|
||||
|
||||
printf("platform: %d\n", rw::platform);
|
||||
|
||||
rw::uint32 len;
|
||||
// rw::uint8 *data = rw::getFileContents("host:player-vc-ps2.dff", &len);
|
||||
rw::uint8 *data = rw::getFileContents("host:od_newscafe_dy-ps2.dff", &len);
|
||||
rw::uint8 *data = rw::getFileContents("host:player_pc.dff", &len);
|
||||
// rw::uint8 *data = rw::getFileContents("host:od_newscafe_dy-ps2.dff", &len);
|
||||
// rw::uint8 *data = rw::getFileContents("host:admiral-ps2.dff", &len);
|
||||
rw::StreamMemory in;
|
||||
in.open(data, len);
|
||||
|
Loading…
Reference in New Issue
Block a user