implemented leeds dff stream read

This commit is contained in:
aap 2016-01-09 22:01:21 +01:00
parent fab7f20c6d
commit a42bfb90ac
10 changed files with 844 additions and 248 deletions

View File

@ -76,7 +76,6 @@ Global
{85F56A7D-6EA2-4B9B-806A-87AF6C577FDF}.Release|x64.ActiveCfg = Release|x64 {85F56A7D-6EA2-4B9B-806A-87AF6C577FDF}.Release|x64.ActiveCfg = Release|x64
{85F56A7D-6EA2-4B9B-806A-87AF6C577FDF}.Release|x64.Build.0 = Release|x64 {85F56A7D-6EA2-4B9B-806A-87AF6C577FDF}.Release|x64.Build.0 = Release|x64
{2592ED29-F258-4949-AB45-7B873BF697F7}.Debug - null|Win32.ActiveCfg = Debug - null|Win32 {2592ED29-F258-4949-AB45-7B873BF697F7}.Debug - null|Win32.ActiveCfg = Debug - null|Win32
{2592ED29-F258-4949-AB45-7B873BF697F7}.Debug - null|Win32.Build.0 = Debug - null|Win32
{2592ED29-F258-4949-AB45-7B873BF697F7}.Debug - null|x64.ActiveCfg = Debug - null|x64 {2592ED29-F258-4949-AB45-7B873BF697F7}.Debug - null|x64.ActiveCfg = Debug - null|x64
{2592ED29-F258-4949-AB45-7B873BF697F7}.Debug|Win32.ActiveCfg = Debug|Win32 {2592ED29-F258-4949-AB45-7B873BF697F7}.Debug|Win32.ActiveCfg = Debug|Win32
{2592ED29-F258-4949-AB45-7B873BF697F7}.Debug|x64.ActiveCfg = Debug|x64 {2592ED29-F258-4949-AB45-7B873BF697F7}.Debug|x64.ActiveCfg = Debug|x64
@ -96,7 +95,6 @@ Global
{E5D477C8-4CAF-43BF-B7E3-6689503D469F}.Release|x64.ActiveCfg = Release|x64 {E5D477C8-4CAF-43BF-B7E3-6689503D469F}.Release|x64.ActiveCfg = Release|x64
{E5D477C8-4CAF-43BF-B7E3-6689503D469F}.Release|x64.Build.0 = Release|x64 {E5D477C8-4CAF-43BF-B7E3-6689503D469F}.Release|x64.Build.0 = Release|x64
{403C35A9-6D06-4261-B305-9ED000F00136}.Debug - null|Win32.ActiveCfg = Debug - null|Win32 {403C35A9-6D06-4261-B305-9ED000F00136}.Debug - null|Win32.ActiveCfg = Debug - null|Win32
{403C35A9-6D06-4261-B305-9ED000F00136}.Debug - null|Win32.Build.0 = Debug - null|Win32
{403C35A9-6D06-4261-B305-9ED000F00136}.Debug - null|x64.ActiveCfg = Debug - null|x64 {403C35A9-6D06-4261-B305-9ED000F00136}.Debug - null|x64.ActiveCfg = Debug - null|x64
{403C35A9-6D06-4261-B305-9ED000F00136}.Debug|Win32.ActiveCfg = Debug|Win32 {403C35A9-6D06-4261-B305-9ED000F00136}.Debug|Win32.ActiveCfg = Debug|Win32
{403C35A9-6D06-4261-B305-9ED000F00136}.Debug|x64.ActiveCfg = Debug|x64 {403C35A9-6D06-4261-B305-9ED000F00136}.Debug|x64.ActiveCfg = Debug|x64
@ -106,6 +104,7 @@ Global
{403C35A9-6D06-4261-B305-9ED000F00136}.Release|x64.ActiveCfg = Release|x64 {403C35A9-6D06-4261-B305-9ED000F00136}.Release|x64.ActiveCfg = Release|x64
{403C35A9-6D06-4261-B305-9ED000F00136}.Release|x64.Build.0 = Release|x64 {403C35A9-6D06-4261-B305-9ED000F00136}.Release|x64.Build.0 = Release|x64
{27ECE916-900F-49B2-8E9F-95E6B347E161}.Debug - null|Win32.ActiveCfg = Debug - null|Win32 {27ECE916-900F-49B2-8E9F-95E6B347E161}.Debug - null|Win32.ActiveCfg = Debug - null|Win32
{27ECE916-900F-49B2-8E9F-95E6B347E161}.Debug - null|Win32.Build.0 = Debug - null|Win32
{27ECE916-900F-49B2-8E9F-95E6B347E161}.Debug - null|x64.ActiveCfg = Debug - null|Win32 {27ECE916-900F-49B2-8E9F-95E6B347E161}.Debug - null|x64.ActiveCfg = Debug - null|Win32
{27ECE916-900F-49B2-8E9F-95E6B347E161}.Debug|Win32.ActiveCfg = Debug - null|Win32 {27ECE916-900F-49B2-8E9F-95E6B347E161}.Debug|Win32.ActiveCfg = Debug - null|Win32
{27ECE916-900F-49B2-8E9F-95E6B347E161}.Debug|Win32.Build.0 = Debug - null|Win32 {27ECE916-900F-49B2-8E9F-95E6B347E161}.Debug|Win32.Build.0 = Debug - null|Win32

View File

@ -400,7 +400,9 @@ Material::Material(void)
{ {
this->texture = NULL; this->texture = NULL;
memset(this->color, 0xFF, 4); memset(this->color, 0xFF, 4);
surfaceProps[0] = surfaceProps[1] = surfaceProps[2] = 1.0f; surfaceProps.ambient = 1.0f;
surfaceProps.specular = 1.0f;
surfaceProps.diffuse = 1.0f;
this->pipeline = NULL; this->pipeline = NULL;
this->refCount = 1; this->refCount = 1;
this->constructPlugins(); this->constructPlugins();
@ -412,9 +414,9 @@ Material::Material(Material *m)
this->color[1] = m->color[1]; this->color[1] = m->color[1];
this->color[2] = m->color[2]; this->color[2] = m->color[2];
this->color[3] = m->color[3]; this->color[3] = m->color[3];
this->surfaceProps[0] = m->surfaceProps[0]; this->surfaceProps.ambient = m->surfaceProps.ambient;
this->surfaceProps[1] = m->surfaceProps[1]; this->surfaceProps.specular = m->surfaceProps.specular;
this->surfaceProps[2] = m->surfaceProps[2]; this->surfaceProps.diffuse = m->surfaceProps.diffuse;
this->texture = m->texture; this->texture = m->texture;
if(this->texture) if(this->texture)
this->texture->refCount++; this->texture->refCount++;
@ -463,15 +465,15 @@ Material::streamRead(Stream *stream)
mat->color[2] = buf.color[2]; mat->color[2] = buf.color[2];
mat->color[3] = buf.color[3]; mat->color[3] = buf.color[3];
if(version < 0x30400){ if(version < 0x30400){
mat->surfaceProps[0] = 1.0f; mat->surfaceProps.ambient = 1.0f;
mat->surfaceProps[1] = 1.0f; mat->surfaceProps.specular = 1.0f;
mat->surfaceProps[2] = 1.0f; mat->surfaceProps.diffuse = 1.0f;
}else{ }else{
float32 surfaceProps[3]; float32 surfaceProps[3];
stream->read(surfaceProps, sizeof(surfaceProps)); stream->read(surfaceProps, sizeof(surfaceProps));
mat->surfaceProps[0] = surfaceProps[0]; mat->surfaceProps.ambient = surfaceProps[0];
mat->surfaceProps[1] = surfaceProps[1]; mat->surfaceProps.specular = surfaceProps[1];
mat->surfaceProps[2] = surfaceProps[2]; mat->surfaceProps.diffuse = surfaceProps[2];
} }
if(buf.textured){ if(buf.textured){
assert(findChunk(stream, ID_TEXTURE, &length, NULL)); assert(findChunk(stream, ID_TEXTURE, &length, NULL));
@ -505,9 +507,9 @@ Material::streamWrite(Stream *stream)
if(rw::version >= 0x30400){ if(rw::version >= 0x30400){
float32 surfaceProps[3]; float32 surfaceProps[3];
surfaceProps[0] = this->surfaceProps[0]; surfaceProps[0] = this->surfaceProps.ambient;
surfaceProps[1] = this->surfaceProps[1]; surfaceProps[1] = this->surfaceProps.specular;
surfaceProps[2] = this->surfaceProps[2]; surfaceProps[2] = this->surfaceProps.diffuse;
stream->write(surfaceProps, sizeof(surfaceProps)); stream->write(surfaceProps, sizeof(surfaceProps));
} }

View File

@ -374,10 +374,10 @@ geometryStreamReadRsl(Stream *stream)
for(int32 i = 0; i < g->numMaterials; i++){ for(int32 i = 0; i < g->numMaterials; i++){
assert(findChunk(stream, ID_MATERIAL, NULL, NULL)); assert(findChunk(stream, ID_MATERIAL, NULL, NULL));
g->materialList[i] = Material::streamRead(stream); g->materialList[i] = Material::streamRead(stream);
// fucked somehow // unimplemented by Rsl
g->materialList[i]->surfaceProps[0] = 1.0f; g->materialList[i]->surfaceProps.ambient = 1.0f;
g->materialList[i]->surfaceProps[1] = 1.0f; g->materialList[i]->surfaceProps.specular = 1.0f;
g->materialList[i]->surfaceProps[2] = 1.0f; g->materialList[i]->surfaceProps.diffuse = 1.0f;
} }
g->streamReadPlugins(stream); g->streamReadPlugins(stream);

View File

@ -791,17 +791,17 @@ clearMatFX(MatFX *matfx)
} }
void void
MatFX::setEffects(uint32 flags) MatFX::setEffects(uint32 type)
{ {
if(this->flags != 0 && this->flags != flags) if(this->type != 0 && this->type != type)
clearMatFX(this); clearMatFX(this);
this->flags = flags; this->type = type;
switch(flags){ switch(type){
case BUMPMAP: case BUMPMAP:
case ENVMAP: case ENVMAP:
case DUAL: case DUAL:
case UVTRANSFORM: case UVTRANSFORM:
this->fx[0].type = flags; this->fx[0].type = type;
this->fx[1].type = NOTHING; this->fx[1].type = NOTHING;
break; break;
@ -889,7 +889,7 @@ readMaterialMatFX(Stream *stream, int32, void *object, int32 offset, int32)
*PLUGINOFFSET(MatFX*, object, offset) = matfx; *PLUGINOFFSET(MatFX*, object, offset) = matfx;
matfx->setEffects(stream->readU32()); matfx->setEffects(stream->readU32());
if(matfx->flags == MatFX::BUMPMAP && matFXGlobals.hack){ if(matfx->type == MatFX::BUMPMAP && matFXGlobals.hack){
stream->seek(12); stream->seek(12);
return; return;
} }
@ -961,7 +961,7 @@ writeMaterialMatFX(Stream *stream, int32, void *object, int32 offset, int32)
{ {
MatFX *matfx = *PLUGINOFFSET(MatFX*, object, offset); MatFX *matfx = *PLUGINOFFSET(MatFX*, object, offset);
stream->writeU32(matfx->flags); stream->writeU32(matfx->type);
for(int i = 0; i < 2; i++){ for(int i = 0; i < 2; i++){
stream->writeU32(matfx->fx[i].type); stream->writeU32(matfx->fx[i].type);
switch(matfx->fx[i].type){ switch(matfx->fx[i].type){

View File

@ -1515,24 +1515,24 @@ ps2MinSize(int32 psm, int32 flags, int32 *minw, int32 *minh)
{ {
*minh = 1; *minh = 1;
switch(psm){ switch(psm){
case 0x00: case 0x00:
case 0x30: case 0x30:
*minw = 2; // 32 bit *minw = 2; // 32 bit
break; break;
case 0x02: case 0x02:
case 0x0A: case 0x0A:
case 0x32: case 0x32:
case 0x3A: case 0x3A:
*minw = 4; // 16 bit *minw = 4; // 16 bit
break; break;
case 0x01: case 0x01:
case 0x13: case 0x13:
case 0x14: case 0x14:
case 0x1B: case 0x1B:
case 0x24: case 0x24:
case 0x2C: case 0x2C:
case 0x31: case 0x31:
*minw = 8; // everything else *minw = 8; // everything else
break; break;
} }
if(flags & 0x2 && psm == 0x13){ // PSMT8 if(flags & 0x2 && psm == 0x13){ // PSMT8
@ -1896,21 +1896,21 @@ registerNativeRaster(void)
Texture::registerPluginStream(ID_SKYMIPMAP, readMipmap, writeMipmap, getSizeMipmap); Texture::registerPluginStream(ID_SKYMIPMAP, readMipmap, writeMipmap, getSizeMipmap);
} }
struct StreamRasterExt struct StreamRasterExt
{ {
int32 width; int32 width;
int32 height; int32 height;
int32 depth; int32 depth;
uint16 rasterFormat; uint16 rasterFormat;
int16 type; int16 type;
uint32 tex0[2]; uint32 tex0[2];
uint32 tex1[2]; uint32 tex1[2];
uint32 miptbp1[2]; uint32 miptbp1[2];
uint32 miptbp2[2]; uint32 miptbp2[2];
uint32 texelSize; uint32 texelSize;
uint32 paletteSize; uint32 paletteSize;
uint32 gsSize; uint32 gsSize;
uint32 mipmapVal; uint32 mipmapVal;
}; };
Texture* Texture*

View File

@ -199,11 +199,18 @@ struct Texture : PluginBase<Texture>
}; };
}; };
struct SurfaceProperties
{
float32 ambient;
float32 specular;
float32 diffuse;
};
struct Material : PluginBase<Material> struct Material : PluginBase<Material>
{ {
Texture *texture; Texture *texture;
uint8 color[4]; uint8 color[4];
float32 surfaceProps[3]; SurfaceProperties surfaceProps;
Pipeline *pipeline; Pipeline *pipeline;
int32 refCount; int32 refCount;
@ -220,7 +227,7 @@ void registerMaterialRightsPlugin(void);
struct MatFX struct MatFX
{ {
enum Flags { enum {
NOTHING = 0, NOTHING = 0,
BUMPMAP, BUMPMAP,
ENVMAP, ENVMAP,
@ -259,7 +266,7 @@ struct MatFX
UVtransform uvtransform; UVtransform uvtransform;
}; };
} fx[2]; } fx[2];
uint32 flags; uint32 type;
void setEffects(uint32 flags); void setEffects(uint32 flags);
int32 getEffectIndex(uint32 type); int32 getEffectIndex(uint32 type);

671
tools/rsltest/rsl.cpp Normal file
View File

@ -0,0 +1,671 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <new>
#include <args.h>
#include <rw.h>
#include <src/gtaplg.h>
using namespace std;
using namespace rw;
#include "rsl.h"
void rslMaterialListStreamRead(Stream *stream, RslMaterialList *matlist);
void hanimRead(Stream *stream, RslFrame *f);
void matfxRead(Stream *stream, RslMaterial *mat);
void
RslMatrixSetIdentity(RslMatrix *matrix)
{
memset(matrix, 0, sizeof(RslMatrix));
matrix->right.x = 1.0f;
matrix->up.y = 1.0f;
matrix->at.z = 1.0f;
}
void
rslObjectHasFrameSetFrame(RslObjectHasFrame *object, RslFrame *f)
{
if(object->object.parent){
object->lFrame.prev->next = object->lFrame.next;
object->lFrame.next->prev = object->lFrame.prev;
}
object->object.parent = f;
if(f){
object->lFrame.prev = &f->objectList.link;
object->lFrame.next = f->objectList.link.next;
f->objectList.link.next->prev = &object->lFrame;
f->objectList.link.next = &object->lFrame;
f->root->object.privateFlags |= 1;
f->object.privateFlags |= 2;
}
}
RslFrame*
RslFrameCreate(void)
{
RslFrame *f = new RslFrame;
rslObjectInitialize(&f->object, 0, 0);
f->objectList.link.prev = &f->objectList.link;
f->objectList.link.next = &f->objectList.link;
RslMatrixSetIdentity(&f->modelling);
RslMatrixSetIdentity(&f->ltm);
f->child = NULL;
f->next = NULL;
f->root = f;
f->nodeId = -1;
f->hier = NULL;
f->name = NULL;
f->hierId = 0;
return f;
}
RslFrame*
RslFrameAddChild(RslFrame *parent, RslFrame *child)
{
RslFrame *p = (RslFrame*)child->object.parent;
assert(p == NULL);
child->next = parent->child;
parent->child = child;
child->object.parent = parent;
child->root = parent->root;
child->root->object.privateFlags |= 1;
child->object.privateFlags |= 2;
return parent;
}
RslFrame*
RslFrameForAllChildren(RslFrame *frame, RslFrameCallBack callBack, void *data)
{
for(RslFrame *child = frame->child;
child;
child = child->next)
if(callBack(child, data) == NULL)
break;
return frame;
}
struct StreamFrame
{
RslV3d right, up, at, pos;
int32 parent;
int32 flags;
};
void
rwFrameListStreamRead(Stream *stream, rslFrameList *framelist)
{
uint32 length;
StreamFrame strfrm;
RslFrame *f;
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
stream->read(&framelist->numFrames, 4);
framelist->frames = new RslFrame*[framelist->numFrames];
for(int32 i = 0; i < framelist->numFrames; i++){
stream->read(&strfrm, sizeof(strfrm));
f = RslFrameCreate();
f->modelling.right = strfrm.right;
f->modelling.up = strfrm.up;
f->modelling.at = strfrm.at;
f->modelling.pos = strfrm.pos;
framelist->frames[i] = f;
if(strfrm.parent >= 0)
RslFrameAddChild(framelist->frames[strfrm.parent], f);
}
ChunkHeaderInfo header;
for(int32 i = 0; i < framelist->numFrames; i++){
f = framelist->frames[i];
assert(findChunk(stream, ID_EXTENSION, &length, NULL));
while(length){
readChunkHeaderInfo(stream, &header);
if(header.type == ID_HANIMPLUGIN){
hanimRead(stream, f);
}else if(header.type == gta::ID_NODENAME){
f->name = new char[header.length+1];
memset(f->name, 0, header.length+1);
stream->read(f->name, header.length);
f->name[header.length] = '\0';
}else{
stream->seek(header.length);
}
length -= 12 + header.length;
}
}
}
RslHAnimHierarchy*
RslHAnimHierarchyCreate(int32 numNodes, uint32 *nodeFlags, int32 *nodeIDs, int32 flags, int32 maxKeySize)
{
RslHAnimHierarchy *hier = new RslHAnimHierarchy;
memset(hier, 0, sizeof(RslHAnimHierarchy));
if(maxKeySize < 0x24)
maxKeySize = 0x24;
hier->flags = flags;
hier->numNodes = numNodes;
hier->parentFrame = 0;
hier->maxKeyFrameSize = maxKeySize;
hier->currentKeyFrameSize = 0x24;
int32 msz = numNodes*0x40 + 0x3f;
uint8 *p = new uint8[msz];
memset(p, 0, msz);
hier->pMatrixArrayUnaligned = p;
uintptr ip = (uintptr)p;
ip &= ~0x3f;
hier->pMatrixArray = (float32*)ip;
hier->pNodeInfo = new RslHAnimNodeInfo[numNodes];
for(int32 i = 0; i < numNodes; i++){
hier->pNodeInfo[i].id = nodeIDs[i];
hier->pNodeInfo[i].index = i;
hier->pNodeInfo[i].flags = nodeFlags[i];
hier->pNodeInfo[i].frame = NULL;
}
hier->parentHierarchy = hier;
return hier;
}
static void
hanimRead(Stream *stream, RslFrame *f)
{
int32 version;
int32 id;
int32 numNodes;
int32 flags;
int32 maxKeySize;
uint32 *nodeFlags;
int32 *nodeIDs;
version = stream->readI32();
assert(version == 0x100);
id = stream->readI32();
f->nodeId = id;
numNodes = stream->readI32();
if(numNodes == 0)
return;
flags = stream->readI32();
maxKeySize = stream->readI32();
nodeFlags = new uint32[numNodes];
nodeIDs = new int32[numNodes];
memset(nodeFlags, 0, numNodes*4);
memset(nodeIDs, 0, numNodes*4);
for(int32 i = 0; i < numNodes; i++){
nodeIDs[i] = stream->readI32();
stream->readI32();
nodeFlags[i] = stream->readI32();
}
f->hier = RslHAnimHierarchyCreate(numNodes, nodeFlags,
nodeIDs, flags, maxKeySize);
delete[] nodeFlags;
delete[] nodeIDs;
}
RslAtomic*
RslAtomicCreate(void)
{
RslAtomic *a = new RslAtomic;
memset(a, 0, sizeof(RslAtomic));
rslObjectInitialize(&a->object, 1, 0);
a->object.object.flags = 5;
a->object.object.privateFlags |= 1;
rslObjectHasFrameSetFrame(&a->object, NULL);
return a;
}
RslAtomic*
RslAtomicSetFrame(RslAtomic *atomic, RslFrame *frame)
{
rslObjectHasFrameSetFrame(&atomic->object, frame);
return atomic;
}
RslAtomic*
RslAtomicStreamRead(Stream *stream, rslFrameList *framelist)
{
uint32 length;
int32 buf[4];
RslAtomic *a;
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
stream->read(buf, 16);
a = RslAtomicCreate();
a->object.object.flags = buf[2];
assert(findChunk(stream, ID_GEOMETRY, NULL, NULL));
RslPS2ResEntryHeader res, *rp;
stream->read(&res, sizeof(RslPS2ResEntryHeader));
RslGeometry *g = RslGeometryCreatePS2(res.size & 0xFFFFF);
rp = (RslPS2ResEntryHeader*)(g+1);
*rp++ = res;
stream->read(rp, (res.size&0xFFFFF)-sizeof(RslPS2ResEntryHeader));
rslMaterialListStreamRead(stream, &g->matList);
a->geometry = g;
RslAtomicSetFrame(a, framelist->frames[buf[0]]);
// This is not how it's done in LCS, they got extensions wrong :(
// Geometry
ChunkHeaderInfo header;
assert(findChunk(stream, ID_EXTENSION, &length, NULL));
while(length){
readChunkHeaderInfo(stream, &header);
if(header.type == ID_SKIN){
g->skin = RslSkinStreamRead(stream, g);
}else
stream->seek(header.length);
length -= 12 + header.length;
}
// Atomic
assert(findChunk(stream, ID_EXTENSION, &length, NULL));
while(length){
readChunkHeaderInfo(stream, &header);
stream->seek(header.length);
length -= 12 + header.length;
}
return a;
}
RslSkin*
RslSkinStreamRead(Stream *stream, RslGeometry *g)
{
uint32 info;
RslSkin *skin = new RslSkin;
memset(skin, 0, sizeof(RslSkin));
info = stream->readU32();
// LCS is different here, doesn't matter
info &= 0xFF;
skin->numBones = info;
skin->numUsedBones = info;
skin->invMatrices = new float[skin->numBones*16];
stream->read(skin->invMatrices, skin->numBones*16*4);
return skin;
}
RslClump*
RslClumpCreate(void)
{
RslClump *clump = new RslClump;
rslObjectInitialize(&clump->object, 2, 0);
clump->atomicList.link.prev = &clump->atomicList.link;
clump->atomicList.link.next = &clump->atomicList.link;
return clump;
}
RslClump*
RslClumpStreamRead(Stream *stream)
{
uint32 version, length;
int32 buf[3];
int32 numAtomics;
rslFrameList framelist;
RslClump *clump;
assert(findChunk(stream, ID_STRUCT, NULL, &version));
if(version > 0x33000){
stream->read(buf, 12);
numAtomics = buf[0];
}else
stream->read(&numAtomics, 4);
clump = RslClumpCreate();
assert(findChunk(stream, ID_FRAMELIST, NULL, NULL));
rwFrameListStreamRead(stream, &framelist);
clump->object.parent = framelist.frames[0];
for(int32 i = 0; i < numAtomics; i++){
assert(findChunk(stream, ID_ATOMIC, NULL, &version));
RslAtomic *a = RslAtomicStreamRead(stream, &framelist);
RslClumpAddAtomic(clump, a);
}
ChunkHeaderInfo header;
assert(findChunk(stream, ID_EXTENSION, &length, NULL));
while(length){
readChunkHeaderInfo(stream, &header);
stream->seek(header.length);
length -= 12 + header.length;
}
return clump;
}
RslClump*
RslClumpAddAtomic(RslClump *clump, RslAtomic *a)
{
a->inClumpLink.prev = &clump->atomicList.link;
a->inClumpLink.next = clump->atomicList.link.next;
clump->atomicList.link.next->prev = &a->inClumpLink;
clump->atomicList.link.next = &a->inClumpLink;
a->clump = clump;
return clump;
}
RslClump*
RslClumpForAllAtomics(RslClump *clump, RslAtomicCallBack callback, void *pData)
{
RslAtomic *a;
RslLLLink *link;
for(link = rslLLLinkGetNext(&clump->atomicList.link);
link != &clump->atomicList.link;
link = link->next){
a = rslLLLinkGetData(link, RslAtomic, inClumpLink);
if(callback(a, pData) == NULL)
break;
}
return clump;
}
RslGeometry*
RslGeometryCreatePS2(uint32 sz)
{
sz += sizeof(RslGeometry);
RslGeometry *g = (RslGeometry*)new uint8[sz];
memset(g, 0, sz);
rslObjectInitialize(&g->object, 8, 0);
g->refCount = 1;
return g;
}
RslGeometry*
RslGeometryForAllMaterials(RslGeometry *geometry, RslMaterialCallBack fpCallBack, void *pData)
{
for(int32 i = 0; i < geometry->matList.numMaterials; i++)
if(fpCallBack(geometry->matList.materials[i], pData) == NULL)
break;
return geometry;
}
struct RslMaterialChunkInfo
{
int32 flags;
RslRGBA color; // used
int32 unused;
bool32 textured; // used
SurfaceProperties surfaceProps;
};
RslMaterial*
RslMaterialCreate(void)
{
RslMaterial *mat = new RslMaterial;
mat->texture = NULL;
mat->color = RslRGBA{255, 255, 255, 255};
mat->refCount = 1;
mat->matfx = NULL;
return mat;
}
RslMaterial*
RslMaterialStreamRead(Stream *stream)
{
uint32 length;
RslMaterialChunkInfo chunk;
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
stream->read(&chunk, sizeof(chunk));
RslMaterial *mat = RslMaterialCreate();
mat->color = chunk.color;
if(chunk.textured)
mat->texture = RslTextureStreamRead(stream);
ChunkHeaderInfo header;
assert(findChunk(stream, ID_EXTENSION, &length, NULL));
while(length){
readChunkHeaderInfo(stream, &header);
if(header.type == ID_MATFX)
matfxRead(stream, mat);
else
stream->seek(header.length);
length -= 12 + header.length;
}
return mat;
}
void
RslMatFXMaterialSetEffects(RslMaterial *mat, int32 effect)
{
if(effect != MatFX::NOTHING){
if(mat->matfx == NULL){
mat->matfx = new RslMatFX;
memset(mat->matfx, 0, sizeof(RslMatFX));
}
mat->matfx->effectType = effect;
}else{
RslMatFX *matfx = mat->matfx;
if(matfx->env.texture)
RslTextureDestroy(matfx->env.texture);
delete matfx;
mat->matfx = NULL;
}
}
void
matfxRead(Stream *stream, RslMaterial *mat)
{
int32 effect = stream->readI32();
RslMatFXMaterialSetEffects(mat, effect);
if(effect == MatFX::BUMPMAP){
stream->seek(12);
return;
}
RslMatFX *mfx = mat->matfx;
int32 type = stream->readI32();
float32 coef;
int32 fbalpha;
switch(type){
case MatFX::ENVMAP:
coef = stream->readF32();
fbalpha = stream->readI32();
mfx->env.frame = NULL;
mfx->env.texture = RslTextureStreamRead(stream);
mfx->env.intensity = coef;
break;
case MatFX::BUMPMAP:
coef = stream->readF32();
break;
}
}
void
rpMaterialListAppendMaterial(RslMaterialList *matlist, RslMaterial *mat)
{
if(matlist->space <= matlist->numMaterials){
matlist->space += 16;
RslMaterial **mats = matlist->materials;
matlist->materials = new RslMaterial*[matlist->space];
if(matlist->space-16)
memcpy(matlist->materials, mats, (matlist->space+16)*sizeof(RslMaterial*));
delete[] mats;
}
matlist->materials[matlist->numMaterials++] = mat;
}
void
rslMaterialListStreamRead(Stream *stream, RslMaterialList *matlist)
{
int32 numMaterials;
RslMaterial *mat;
assert(findChunk(stream, ID_MATLIST, NULL, NULL));
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
numMaterials = stream->readI32();
int32 *refs = new int32[numMaterials];
stream->read(refs, 4*numMaterials);
for(int32 i = 0; i < numMaterials; i++){
assert(refs[i] < 0);
assert(findChunk(stream, ID_MATERIAL, NULL, NULL));
mat = RslMaterialStreamRead(stream);
rpMaterialListAppendMaterial(matlist, mat);
}
delete[] refs;
}
RslTexDictionary*
RslTexDictionaryCreate(void)
{
RslTexDictionary *dict = new RslTexDictionary;
memset(dict, 0, sizeof(RslTexDictionary));
rslObjectInitialize(&dict->object, 6, 0);
dict->texturesInDict.link.prev = &dict->texturesInDict.link;
dict->texturesInDict.link.next = &dict->texturesInDict.link;
return dict;
}
RslTexture*
RslTexDictionaryAddTexture(RslTexDictionary *dict, RslTexture *tex)
{
if(tex->dict){
tex->lInDictionary.prev->next = tex->lInDictionary.next;
tex->lInDictionary.next->prev = tex->lInDictionary.prev;
}
tex->dict = dict;
tex->lInDictionary.prev = &dict->texturesInDict.link;
tex->lInDictionary.next = dict->texturesInDict.link.next;
dict->texturesInDict.link.next->prev = &tex->lInDictionary;
dict->texturesInDict.link.next = &tex->lInDictionary;
return tex;
}
RslTexDictionary*
RslTexDictionaryForAllTextures(RslTexDictionary *dict, RslTextureCallBack fpCallBack, void *pData)
{
RslTexture *t;
RslLLLink *link;
for(link = rslLLLinkGetNext(&dict->texturesInDict.link);
link != &dict->texturesInDict.link;
link = link->next){
t = rslLLLinkGetData(link, RslTexture, lInDictionary);
if(fpCallBack(t, pData) == NULL)
break;
}
return dict;
}
// TODO!
void
RslTextureDestroy(RslTexture *texture)
{
delete texture;
}
RslTexture*
RslTextureCreate(RslRaster *raster)
{
RslTexture *tex = new RslTexture;
memset(tex, 0, sizeof(RslTexture));
tex->raster = raster;
return tex;
}
RslTexture*
RslTextureStreamRead(Stream *stream)
{
uint32 length;
RslTexture *tex = RslTextureCreate(NULL);
assert(findChunk(stream, ID_TEXTURE, NULL, NULL));
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
stream->readI32(); // filter addressing
assert(findChunk(stream, ID_STRING, &length, NULL));
stream->read(tex->name, length);
assert(findChunk(stream, ID_STRING, &length, NULL));
stream->read(tex->mask, length);
ChunkHeaderInfo header;
assert(findChunk(stream, ID_EXTENSION, &length, NULL));
while(length){
readChunkHeaderInfo(stream, &header);
stream->seek(header.length);
length -= 12 + header.length;
}
return tex;
}
static uint32
guessSwizzling(uint32 w, uint32 h, uint32 d, uint32 mipmaps)
{
uint32 swiz = 0;
for(uint32 i = 0; i < mipmaps; i++){
switch(d){
case 4:
if(w >= 32 && h >= 16)
swiz |= 1<<i;
break;
case 8:
if(w >= 16 && h >= 4)
swiz |= 1<<i;
break;
}
w /= 2;
h /= 2;
}
return swiz;
}
RslRaster*
RslCreateRasterPS2(uint32 w, uint32 h, uint32 d, uint32 mipmaps)
{
RslRasterPS2 *r;
r = new RslRasterPS2;
uint32 tmp, logw = 0, logh = 0;
for(tmp = 1; tmp < w; tmp <<= 1)
logw++;
for(tmp = 1; tmp < h; tmp <<= 1)
logh++;
r->flags = 0;
r->flags |= logw&0x3F;
r->flags |= (logh&0x3F)<<6;
r->flags |= d << 12;
r->flags |= mipmaps << 20;
uint32 swiz = guessSwizzling(w, h, d, mipmaps);
r->flags |= swiz << 24;
return (RslRaster*)r;
}
RslTexture*
RslReadNativeTexturePS2(Stream *stream)
{
RslPs2StreamRaster rasterInfo;
uint32 len;
uint32 buf[2];
RslTexture *tex = RslTextureCreate(NULL);
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
stream->read(buf, sizeof(buf));
assert(buf[0] == 0x00505350); /* "PSP\0" */
assert(findChunk(stream, ID_STRING, &len, NULL));
stream->read(tex->name, len);
assert(findChunk(stream, ID_STRING, &len, NULL));
stream->read(tex->mask, len);
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
assert(findChunk(stream, ID_STRUCT, &len, NULL));
stream->read(&rasterInfo, sizeof(rasterInfo));
assert(findChunk(stream, ID_STRUCT, &len, NULL));
tex->raster = RslCreateRasterPS2(rasterInfo.width,
rasterInfo.height, rasterInfo.depth, rasterInfo.mipmaps);
tex->raster->ps2.data = new uint8[len];
stream->read(tex->raster->ps2.data, len);
assert(findChunk(stream, ID_EXTENSION, &len, NULL));
stream->seek(len);
return tex;
}
RslTexDictionary*
RslTexDictionaryStreamRead(Stream *stream)
{
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
int32 numTex = stream->readI32();
RslTexDictionary *txd = RslTexDictionaryCreate();
for(int32 i = 0; i < numTex; i++){
assert(findChunk(stream, ID_TEXTURENATIVE, NULL, NULL));
RslTexture *tex = RslReadNativeTexturePS2(stream);
RslTexDictionaryAddTexture(txd, tex);
}
return txd;
}

View File

@ -42,12 +42,41 @@ typedef RslAtomic *(*RslAtomicCallBack)(RslAtomic *atomic, void *data);
typedef RslMaterial *(*RslMaterialCallBack)(RslMaterial *material, void *data); typedef RslMaterial *(*RslMaterialCallBack)(RslMaterial *material, void *data);
typedef RslTexture *(*RslTextureCallBack)(RslTexture *texture, void *pData); typedef RslTexture *(*RslTextureCallBack)(RslTexture *texture, void *pData);
struct RslLLLink { struct RslRGBA
{
uint8 red;
uint8 green;
uint8 blue;
uint8 alpha;
};
struct RslV3d
{
float32 x, y, z;
};
struct RslMatrix
{
RslV3d right;
uint32 flags;
RslV3d up;
uint32 pad1;
RslV3d at;
uint32 pad2;
RslV3d pos;
uint32 pad3;
};
void RslMatrixSetIdentity(RslMatrix *matrix);
struct RslLLLink
{
RslLLLink *next; RslLLLink *next;
RslLLLink *prev; RslLLLink *prev;
}; };
struct RslLinkList { struct RslLinkList
{
RslLLLink link; RslLLLink link;
}; };
@ -68,20 +97,31 @@ struct RslLinkList {
((linkvar)->next) ((linkvar)->next)
struct RslObject { struct RslObject {
uint8 type; uint8 type;
uint8 subType; uint8 subType;
uint8 flags; uint8 flags;
uint8 privateFlags; uint8 privateFlags;
void *parent; void *parent;
}; };
#define rslObjectInitialize(o, t, s) \
{ \
((RslObject*)(o))->type = (uint8)(t); \
((RslObject*)(o))->subType = (uint8)(s); \
((RslObject*)(o))->flags = 0; \
((RslObject*)(o))->privateFlags = 0; \
((RslObject*)(o))->parent = NULL; \
}
#define rslObjectGetParent(object) (((const RslObject *)(object))->parent)
struct RslObjectHasFrame { struct RslObjectHasFrame {
RslObject object; RslObject object;
RslLLLink lFrame; RslLLLink lFrame;
void (*sync)(); void (*sync)();
}; };
#define rslObjectGetParent(object) (((const RslObject *)(object))->parent) void rslObjectHasFrameSetFrame(RslObjectHasFrame *object, RslFrame *f);
struct RslRasterPS2 { struct RslRasterPS2 {
uint8 *data; uint8 *data;
@ -110,6 +150,8 @@ union RslRaster {
RslRasterPSP psp; RslRasterPSP psp;
}; };
RslRaster *RslCreateRasterPS2(uint32 w, uint32 h, uint32 d, uint32 mipmaps);
struct RslTexDictionary { struct RslTexDictionary {
RslObject object; RslObject object;
RslLinkList texturesInDict; RslLinkList texturesInDict;
@ -119,6 +161,7 @@ struct RslTexDictionary {
RslTexDictionary *RslTexDictionaryStreamRead(Stream *stream); RslTexDictionary *RslTexDictionaryStreamRead(Stream *stream);
RslTexDictionary *RslTexDictionaryCreate(void); RslTexDictionary *RslTexDictionaryCreate(void);
RslTexture *RslTexDictionaryAddTexture(RslTexDictionary *dict, RslTexture *tex); RslTexture *RslTexDictionaryAddTexture(RslTexDictionary *dict, RslTexture *tex);
RslTexDictionary *RslTexDictionaryForAllTextures(RslTexDictionary *dict, RslTextureCallBack fpCallBack, void *pData);
struct RslTexture { struct RslTexture {
RslRaster *raster; RslRaster *raster;
@ -129,13 +172,16 @@ struct RslTexture {
}; };
RslTexture *RslTextureCreate(RslRaster *raster); RslTexture *RslTextureCreate(RslRaster *raster);
void RslTextureDestroy(RslTexture *texture);
RslTexture *RslTextureStreamRead(Stream *stream);
RslTexture *RslReadNativeTexturePS2(Stream *stream);
struct RslFrame { struct RslFrame {
RslObject object; RslObject object;
RslLLLink inDirtyListLink; // ? RslLinkList objectList;
float32 modelling[16]; RslMatrix modelling;
float32 ltm[16]; RslMatrix ltm;
RslFrame *child; RslFrame *child;
RslFrame *next; RslFrame *next;
RslFrame *root; RslFrame *root;
@ -149,6 +195,16 @@ struct RslFrame {
int32 hierId; int32 hierId;
}; };
RslFrame *RslFrameCreate(void);
RslFrame *RslFrameAddChild(RslFrame *parent, RslFrame *child);
RslFrame *RslFrameForAllChildren(RslFrame *frame, RslFrameCallBack callBack, void *data);
struct rslFrameList
{
RslFrame **frames;
int32 numFrames;
};
struct RslClump { struct RslClump {
RslObject object; RslObject object;
RslLinkList atomicList; RslLinkList atomicList;
@ -157,6 +213,10 @@ struct RslClump {
#define RslClumpGetFrame(_clump) \ #define RslClumpGetFrame(_clump) \
((RslFrame *) rslObjectGetParent(_clump)) ((RslFrame *) rslObjectGetParent(_clump))
RslClump *RslClumpStreamRead(Stream *stream);
RslClump *RslClumpAddAtomic(RslClump *clump, RslAtomic *a);
RslClump *RslClumpForAllAtomics(RslClump *clump, RslAtomicCallBack callback, void *pData);
struct RslAtomic { struct RslAtomic {
RslObjectHasFrame object; RslObjectHasFrame object;
RslGeometry *geometry; RslGeometry *geometry;
@ -176,6 +236,10 @@ struct RslAtomic {
#define RslAtomicGetFrame(_atomic) \ #define RslAtomicGetFrame(_atomic) \
((RslFrame *) rslObjectGetParent(_atomic)) ((RslFrame *) rslObjectGetParent(_atomic))
RslAtomic *RslAtomicCreate(void);
RslAtomic *RslAtomicSetFrame(RslAtomic *atomic, RslFrame *frame);
RslAtomic *RslAtomicStreamRead(Stream *stream, rslFrameList *framelist);
struct RslMaterialList { struct RslMaterialList {
RslMaterial **materials; RslMaterial **materials;
int32 numMaterials; int32 numMaterials;
@ -193,9 +257,15 @@ struct RslGeometry {
uint32 pad2; // 0xAAAAAAAA uint32 pad2; // 0xAAAAAAAA
}; };
RslGeometry *RslGeometryCreatePS2(uint32 sz);
RslGeometry *RslGeometryForAllMaterials(RslGeometry *geometry, RslMaterialCallBack fpCallBack, void *pData);
struct RslMatFXEnv { struct RslMatFXEnv {
RslFrame *frame; RslFrame *frame;
char *texname; union {
char *texname;
RslTexture *texture;
};
float32 intensity; float32 intensity;
}; };
@ -207,12 +277,18 @@ struct RslMatFX {
}; };
struct RslMaterial { struct RslMaterial {
char *texname; union {
uint32 color; char *texname;
RslTexture *texture;
};
RslRGBA color;
uint32 refCount; uint32 refCount;
RslMatFX *matfx; RslMatFX *matfx;
}; };
RslMaterial *RslMaterialCreate(void);
RslMaterial *RslMaterialStreamRead(Stream *stream);
struct RslHAnimNodeInfo { struct RslHAnimNodeInfo {
int8 id; int8 id;
int8 index; int8 index;
@ -262,6 +338,8 @@ struct RslSkin {
void *data; // NULL void *data; // NULL
}; };
RslSkin *RslSkinStreamRead(Stream *stream, RslGeometry *g);
struct RslPS2ResEntryHeader { struct RslPS2ResEntryHeader {
float32 bound[4]; float32 bound[4];
uint32 size; // and numMeshes uint32 size; // and numMeshes
@ -275,9 +353,9 @@ struct RslPS2ResEntryHeader {
}; };
struct RslPS2InstanceData { struct RslPS2InstanceData {
float32 bound[4]; // ? float32 bound[4];
float32 uvScale[2]; float32 uvScale[2];
int32 unk1; int32 unknown;
uint32 dmaPacket; uint32 dmaPacket;
uint16 numTriangles; uint16 numTriangles;
int16 matID; int16 matID;

View File

@ -29,174 +29,6 @@ RslStream::relocate(void)
} }
} }
RslFrame*
RslFrameForAllChildren(RslFrame *frame, RslFrameCallBack callBack, void *data)
{
for(RslFrame *child = frame->child;
child;
child = child->next)
if(callBack(child, data) == NULL)
break;
return frame;
}
RslClump*
RslClumpForAllAtomics(RslClump *clump, RslAtomicCallBack callback, void *pData)
{
RslAtomic *a;
RslLLLink *link;
for(link = rslLLLinkGetNext(&clump->atomicList.link);
link != &clump->atomicList.link;
link = link->next){
a = rslLLLinkGetData(link, RslAtomic, inClumpLink);
if(callback(a, pData) == NULL)
break;
}
return clump;
}
RslGeometry*
RslGeometryForAllMaterials(RslGeometry *geometry, RslMaterialCallBack fpCallBack, void *pData)
{
for(int32 i = 0; i < geometry->matList.numMaterials; i++)
if(fpCallBack(geometry->matList.materials[i], pData) == NULL)
break;
return geometry;
}
RslTexDictionary*
RslTexDictionaryCreate(void)
{
RslTexDictionary *dict = new RslTexDictionary;
memset(dict, 0, sizeof(RslTexDictionary));
dict->object.type = 6;
dict->texturesInDict.link.prev = &dict->texturesInDict.link;
dict->texturesInDict.link.next = &dict->texturesInDict.link;
return dict;
}
RslTexture*
RslTexDictionaryAddTexture(RslTexDictionary *dict, RslTexture *tex)
{
if(tex->dict){
tex->lInDictionary.prev->next = tex->lInDictionary.next;
tex->lInDictionary.next->prev = tex->lInDictionary.prev;
}
tex->dict = dict;
tex->lInDictionary.prev = &dict->texturesInDict.link;
tex->lInDictionary.next = dict->texturesInDict.link.next;
dict->texturesInDict.link.next->prev = &tex->lInDictionary;
dict->texturesInDict.link.next = &tex->lInDictionary;
return tex;
}
RslTexDictionary*
RslTexDictionaryForAllTextures(RslTexDictionary *dict, RslTextureCallBack fpCallBack, void *pData)
{
RslTexture *t;
RslLLLink *link;
for(link = rslLLLinkGetNext(&dict->texturesInDict.link);
link != &dict->texturesInDict.link;
link = link->next){
t = rslLLLinkGetData(link, RslTexture, lInDictionary);
if(fpCallBack(t, pData) == NULL)
break;
}
return dict;
}
uint32
guessSwizzling(uint32 w, uint32 h, uint32 d, uint32 mipmaps)
{
uint32 swiz = 0;
for(uint32 i = 0; i < mipmaps; i++){
switch(d){
case 4:
if(w >= 32 && h >= 16)
swiz |= 1<<i;
break;
case 8:
if(w >= 16 && h >= 4)
swiz |= 1<<i;
break;
}
w /= 2;
h /= 2;
}
return swiz;
}
RslRaster*
RslCreateRasterPS2(uint32 w, uint32 h, uint32 d, uint32 mipmaps)
{
RslRasterPS2 *r;
r = new RslRasterPS2;
uint32 tmp, logw = 0, logh = 0;
for(tmp = 1; tmp < w; tmp <<= 1)
logw++;
for(tmp = 1; tmp < h; tmp <<= 1)
logh++;
r->flags = 0;
r->flags |= logw&0x3F;
r->flags |= (logh&0x3F)<<6;
r->flags |= d << 12;
r->flags |= mipmaps << 20;
uint32 swiz = guessSwizzling(w, h, d, mipmaps);
r->flags |= swiz << 24;
return (RslRaster*)r;
}
RslTexture*
RslReadNativeTexturePS2(Stream *stream)
{
RslPs2StreamRaster rasterInfo;
uint32 len;
uint32 buf[2];
RslTexture *tex = RslTextureCreate(NULL);
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
stream->read(buf, sizeof(buf));
assert(buf[0] == 0x00505350); /* "PSP\0" */
assert(findChunk(stream, ID_STRING, &len, NULL));
stream->read(tex->name, len);
assert(findChunk(stream, ID_STRING, &len, NULL));
stream->read(tex->mask, len);
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
assert(findChunk(stream, ID_STRUCT, &len, NULL));
stream->read(&rasterInfo, sizeof(rasterInfo));
assert(findChunk(stream, ID_STRUCT, &len, NULL));
tex->raster = RslCreateRasterPS2(rasterInfo.width,
rasterInfo.height, rasterInfo.depth, rasterInfo.mipmaps);
tex->raster->ps2.data = new uint8[len];
stream->read(tex->raster->ps2.data, len);
assert(findChunk(stream, ID_EXTENSION, &len, NULL));
stream->seek(len);
return tex;
}
RslTexDictionary*
RslTexDictionaryStreamRead(Stream *stream)
{
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
int32 numTex = stream->readI32();
RslTexDictionary *txd = RslTexDictionaryCreate();
for(int32 i = 0; i < numTex; i++){
assert(findChunk(stream, ID_TEXTURENATIVE, NULL, NULL));
RslTexture *tex = RslReadNativeTexturePS2(stream);
RslTexDictionaryAddTexture(txd, tex);
}
return txd;
}
RslTexture*
RslTextureCreate(RslRaster *raster)
{
RslTexture *tex = new RslTexture;
memset(tex, 0, sizeof(RslTexture));
tex->raster = raster;
return tex;
}
RslFrame *dumpFrameCB(RslFrame *frame, void *data) RslFrame *dumpFrameCB(RslFrame *frame, void *data)
@ -569,13 +401,19 @@ main(int argc, char *argv[])
uint32 ident = stream.readU32(); uint32 ident = stream.readU32();
stream.seek(0, 0); stream.seek(0, 0);
if(ident == 0x16){ if(ident == ID_TEXDICTIONARY){
findChunk(&stream, ID_TEXDICTIONARY, NULL, NULL); findChunk(&stream, ID_TEXDICTIONARY, NULL, NULL);
txd = RslTexDictionaryStreamRead(&stream); txd = RslTexDictionaryStreamRead(&stream);
stream.close(); stream.close();
assert(txd); assert(txd);
goto writeTxd; goto writeTxd;
} }
if(ident == 0x10){
findChunk(&stream, ID_CLUMP, NULL, NULL);
clump = RslClumpStreamRead(&stream);
stream.close();
return 0;
}
RslStream *rslstr = new RslStream; RslStream *rslstr = new RslStream;
stream.read(rslstr, 0x20); stream.read(rslstr, 0x20);

View File

@ -80,6 +80,7 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="rsl.cpp" />
<ClCompile Include="rsltest.cpp" /> <ClCompile Include="rsltest.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>