2020-04-26 10:25:03 +00:00
|
|
|
#if defined RW_D3D9 || defined RWLIBS
|
2019-05-30 11:35:13 +00:00
|
|
|
#define WITHD3D
|
2020-04-26 10:25:03 +00:00
|
|
|
#endif
|
2019-05-15 14:52:37 +00:00
|
|
|
#include "common.h"
|
2020-04-17 13:31:11 +00:00
|
|
|
|
2019-06-30 10:53:39 +00:00
|
|
|
#include "Timecycle.h"
|
2019-06-12 17:05:06 +00:00
|
|
|
#include "skeleton.h"
|
2020-04-23 20:25:18 +00:00
|
|
|
#include "Debug.h"
|
2020-10-31 16:06:25 +00:00
|
|
|
#if !defined(FINAL) || defined(DEBUGMENU)
|
2020-04-14 07:31:00 +00:00
|
|
|
#include "rtcharse.h"
|
2020-10-31 16:06:25 +00:00
|
|
|
#endif
|
|
|
|
#ifndef FINAL
|
2020-04-14 07:31:00 +00:00
|
|
|
RtCharset *debugCharset;
|
|
|
|
#endif
|
|
|
|
|
2020-07-29 12:31:34 +00:00
|
|
|
#ifdef PS2_ALPHA_TEST
|
2020-07-29 12:24:42 +00:00
|
|
|
bool gPS2alphaTest = true;
|
|
|
|
#else
|
|
|
|
bool gPS2alphaTest = false;
|
|
|
|
#endif
|
2021-01-08 00:41:40 +00:00
|
|
|
bool gBackfaceCulling = false; // can we ever enable this in LCS even?
|
2020-04-25 10:16:50 +00:00
|
|
|
|
2020-10-31 16:06:25 +00:00
|
|
|
#if !defined(FINAL) || defined(DEBUGMENU)
|
2020-04-24 11:27:02 +00:00
|
|
|
static bool charsetOpen;
|
|
|
|
void OpenCharsetSafe()
|
|
|
|
{
|
|
|
|
if(!charsetOpen)
|
|
|
|
RtCharsetOpen();
|
|
|
|
charsetOpen = true;
|
|
|
|
}
|
2020-05-09 13:06:13 +00:00
|
|
|
#endif
|
2020-04-24 11:27:02 +00:00
|
|
|
|
2020-04-14 07:31:00 +00:00
|
|
|
void CreateDebugFont()
|
|
|
|
{
|
2020-04-23 20:25:18 +00:00
|
|
|
#ifndef FINAL
|
2020-04-14 07:31:00 +00:00
|
|
|
RwRGBA color = { 255, 255, 128, 255 };
|
|
|
|
RwRGBA colorbg = { 0, 0, 0, 0 };
|
2020-04-24 11:27:02 +00:00
|
|
|
OpenCharsetSafe();
|
2020-04-14 07:31:00 +00:00
|
|
|
debugCharset = RtCharsetCreate(&color, &colorbg);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void DestroyDebugFont()
|
|
|
|
{
|
2020-04-23 20:25:18 +00:00
|
|
|
#ifndef FINAL
|
2020-04-14 07:31:00 +00:00
|
|
|
RtCharsetDestroy(debugCharset);
|
|
|
|
RtCharsetClose();
|
2020-04-24 11:27:02 +00:00
|
|
|
charsetOpen = false;
|
2020-04-14 07:31:00 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObrsPrintfString(const char *str, short x, short y)
|
|
|
|
{
|
2020-04-23 20:25:18 +00:00
|
|
|
#ifndef FINAL
|
|
|
|
RtCharsetPrintBuffered(debugCharset, str, x*8, y*16, true);
|
2020-04-14 07:31:00 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FlushObrsPrintfs()
|
|
|
|
{
|
2020-04-23 20:25:18 +00:00
|
|
|
#ifndef FINAL
|
2020-04-14 07:31:00 +00:00
|
|
|
RtCharsetBufferFlush();
|
|
|
|
#endif
|
|
|
|
}
|
2019-05-15 14:52:37 +00:00
|
|
|
|
2019-05-30 11:35:13 +00:00
|
|
|
void
|
|
|
|
DefinedState(void)
|
|
|
|
{
|
|
|
|
RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSWRAP);
|
|
|
|
RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)TRUE);
|
|
|
|
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
|
|
|
|
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
|
|
|
|
RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD);
|
|
|
|
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
|
|
|
|
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
|
|
|
|
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
|
|
|
|
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
|
2020-07-18 10:30:51 +00:00
|
|
|
//RwRenderStateSet(rwRENDERSTATEALPHAPRIMITIVEBUFFER, (void*)FALSE);
|
2019-05-30 11:35:13 +00:00
|
|
|
RwRenderStateSet(rwRENDERSTATEBORDERCOLOR, (void*)RWRGBALONG(0, 0, 0, 255));
|
|
|
|
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
|
|
|
|
RwRenderStateSet(rwRENDERSTATEFOGCOLOR,
|
|
|
|
(void*)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255));
|
|
|
|
RwRenderStateSet(rwRENDERSTATEFOGTYPE, (void*)rwFOGTYPELINEAR);
|
|
|
|
RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE);
|
|
|
|
|
2020-04-15 12:05:24 +00:00
|
|
|
#ifdef LIBRW
|
2020-04-17 21:55:20 +00:00
|
|
|
rw::SetRenderState(rw::ALPHATESTFUNC, rw::ALPHAGREATEREQUAL);
|
|
|
|
rw::SetRenderState(rw::ALPHATESTREF, 3);
|
2020-04-25 10:16:50 +00:00
|
|
|
|
|
|
|
rw::SetRenderState(rw::GSALPHATEST, gPS2alphaTest);
|
2020-04-15 12:05:24 +00:00
|
|
|
#else
|
2019-05-30 11:35:13 +00:00
|
|
|
// D3D stuff
|
|
|
|
RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
|
|
|
|
RwD3D8SetRenderState(D3DRS_ALPHAREF, 2);
|
2020-04-15 12:05:24 +00:00
|
|
|
#endif
|
2019-05-30 11:35:13 +00:00
|
|
|
}
|
2019-05-15 14:52:37 +00:00
|
|
|
|
2020-05-11 15:03:32 +00:00
|
|
|
void
|
|
|
|
SetCullMode(uint32 mode)
|
|
|
|
{
|
|
|
|
if(gBackfaceCulling)
|
|
|
|
RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)mode);
|
|
|
|
else
|
|
|
|
RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE);
|
|
|
|
}
|
|
|
|
|
2019-06-12 18:07:37 +00:00
|
|
|
RwFrame*
|
|
|
|
GetFirstFrameCallback(RwFrame *child, void *data)
|
|
|
|
{
|
|
|
|
*(RwFrame**)data = child;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
RwFrame*
|
|
|
|
GetFirstChild(RwFrame *frame)
|
|
|
|
{
|
|
|
|
RwFrame *child;
|
|
|
|
|
|
|
|
child = nil;
|
|
|
|
RwFrameForAllChildren(frame, GetFirstFrameCallback, &child);
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
|
2019-05-15 14:52:37 +00:00
|
|
|
RwObject*
|
|
|
|
GetFirstObjectCallback(RwObject *object, void *data)
|
|
|
|
{
|
|
|
|
*(RwObject**)data = object;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
RwObject*
|
|
|
|
GetFirstObject(RwFrame *frame)
|
|
|
|
{
|
|
|
|
RwObject *obj;
|
|
|
|
|
|
|
|
obj = nil;
|
|
|
|
RwFrameForAllObjects(frame, GetFirstObjectCallback, &obj);
|
|
|
|
return obj;
|
|
|
|
}
|
2019-06-12 17:05:06 +00:00
|
|
|
|
2019-06-12 18:07:37 +00:00
|
|
|
RpAtomic*
|
|
|
|
GetFirstAtomicCallback(RpAtomic *atm, void *data)
|
|
|
|
{
|
|
|
|
*(RpAtomic**)data = atm;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
RpAtomic*
|
|
|
|
GetFirstAtomic(RpClump *clump)
|
|
|
|
{
|
|
|
|
RpAtomic *atm;
|
|
|
|
|
|
|
|
atm = nil;
|
|
|
|
RpClumpForAllAtomics(clump, GetFirstAtomicCallback, &atm);
|
|
|
|
return atm;
|
|
|
|
}
|
|
|
|
|
2019-06-23 17:59:58 +00:00
|
|
|
RwTexture*
|
|
|
|
GetFirstTextureCallback(RwTexture *tex, void *data)
|
|
|
|
{
|
|
|
|
*(RwTexture**)data = tex;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
RwTexture*
|
|
|
|
GetFirstTexture(RwTexDictionary *txd)
|
|
|
|
{
|
|
|
|
RwTexture *tex;
|
|
|
|
|
|
|
|
tex = nil;
|
|
|
|
RwTexDictionaryForAllTextures(txd, GetFirstTextureCallback, &tex);
|
|
|
|
return tex;
|
|
|
|
}
|
|
|
|
|
2020-08-20 10:53:17 +00:00
|
|
|
bool
|
2020-04-23 20:25:18 +00:00
|
|
|
IsClumpSkinned(RpClump *clump)
|
|
|
|
{
|
2020-08-20 10:53:17 +00:00
|
|
|
RpAtomic *atomic = GetFirstAtomic(clump);
|
|
|
|
return atomic ? RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic)) : nil;
|
2020-04-23 20:25:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static RpAtomic*
|
|
|
|
GetAnimHierarchyCallback(RpAtomic *atomic, void *data)
|
|
|
|
{
|
|
|
|
*(RpHAnimHierarchy**)data = RpSkinAtomicGetHAnimHierarchy(atomic);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
RpHAnimHierarchy*
|
|
|
|
GetAnimHierarchyFromSkinClump(RpClump *clump)
|
|
|
|
{
|
|
|
|
RpHAnimHierarchy *hier = nil;
|
|
|
|
RpClumpForAllAtomics(clump, GetAnimHierarchyCallback, &hier);
|
|
|
|
return hier;
|
|
|
|
}
|
|
|
|
|
|
|
|
static RwFrame*
|
|
|
|
GetAnimHierarchyFromClumpCB(RwFrame *frame, void *data)
|
|
|
|
{
|
|
|
|
RpHAnimHierarchy *hier = RpHAnimFrameGetHierarchy(frame);
|
|
|
|
if(hier){
|
|
|
|
*(RpHAnimHierarchy**)data = hier;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
RwFrameForAllChildren(frame, GetAnimHierarchyFromClumpCB, data);
|
|
|
|
return frame;
|
|
|
|
}
|
|
|
|
|
|
|
|
RpHAnimHierarchy*
|
|
|
|
GetAnimHierarchyFromClump(RpClump *clump)
|
|
|
|
{
|
|
|
|
RpHAnimHierarchy *hier = nil;
|
|
|
|
RwFrameForAllChildren(RpClumpGetFrame(clump), GetAnimHierarchyFromClumpCB, &hier);
|
|
|
|
return hier;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SkinGetBonePositionsToTable(RpClump *clump, RwV3d *boneTable)
|
|
|
|
{
|
|
|
|
int i, parent;
|
|
|
|
RpAtomic *atomic;
|
|
|
|
RpSkin *skin;
|
|
|
|
RpHAnimHierarchy *hier;
|
|
|
|
int numBones;
|
|
|
|
RwMatrix m, invmat;
|
|
|
|
int stack[32];
|
|
|
|
int sp;
|
|
|
|
|
|
|
|
if(boneTable == nil)
|
|
|
|
return;
|
|
|
|
|
2020-08-20 10:53:17 +00:00
|
|
|
atomic = GetFirstAtomic(clump); // mobile, also VC
|
2020-04-23 20:25:18 +00:00
|
|
|
assert(atomic);
|
|
|
|
skin = RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic));
|
|
|
|
assert(skin);
|
|
|
|
hier = GetAnimHierarchyFromSkinClump(clump);
|
|
|
|
assert(hier);
|
|
|
|
boneTable[0].x = 0.0f;
|
|
|
|
boneTable[0].y = 0.0f;
|
|
|
|
boneTable[0].z = 0.0f;
|
|
|
|
numBones = RpSkinGetNumBones(skin);
|
|
|
|
parent = 0;
|
|
|
|
sp = 0;
|
|
|
|
#ifdef FIX_BUGS
|
|
|
|
stack[0] = 0; // i think this is ok
|
|
|
|
#endif
|
|
|
|
for(i = 1; i < numBones; i++){
|
|
|
|
RwMatrixCopy(&m, &RpSkinGetSkinToBoneMatrices(skin)[i]);
|
|
|
|
RwMatrixInvert(&invmat, &m);
|
|
|
|
const RwMatrix *x = RpSkinGetSkinToBoneMatrices(skin);
|
|
|
|
RwV3dTransformPoints(&boneTable[i], &invmat.pos, 1, &x[parent]);
|
|
|
|
if(HIERNODEINFO(hier)[i].flags & rpHANIMPUSHPARENTMATRIX)
|
|
|
|
stack[++sp] = parent;
|
|
|
|
if(HIERNODEINFO(hier)[i].flags & rpHANIMPOPPARENTMATRIX)
|
|
|
|
parent = stack[sp--];
|
|
|
|
else
|
|
|
|
parent = i;
|
|
|
|
assert(parent >= 0 && parent < numBones);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RpHAnimAnimation*
|
|
|
|
HAnimAnimationCreateForHierarchy(RpHAnimHierarchy *hier)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
#ifdef FIX_BUGS
|
|
|
|
int numNodes = hier->numNodes*2; // you're supposed to have at least two KFs per node
|
|
|
|
#else
|
|
|
|
int numNodes = hier->numNodes;
|
|
|
|
#endif
|
|
|
|
RpHAnimAnimation *anim = RpHAnimAnimationCreate(rpHANIMSTDKEYFRAMETYPEID, numNodes, 0, 0.0f);
|
|
|
|
if(anim == nil)
|
|
|
|
return nil;
|
2020-06-01 18:28:04 +00:00
|
|
|
RpHAnimStdKeyFrame *frame;
|
2020-04-23 20:25:18 +00:00
|
|
|
for(i = 0; i < numNodes; i++){
|
2020-06-01 18:28:04 +00:00
|
|
|
frame = (RpHAnimStdKeyFrame*)HANIMFRAME(anim, i); // games uses struct size here, not safe
|
2020-04-23 20:25:18 +00:00
|
|
|
frame->q.real = 1.0f;
|
|
|
|
frame->q.imag.x = frame->q.imag.y = frame->q.imag.z = 0.0f;
|
|
|
|
frame->t.x = frame->t.y = frame->t.z = 0.0f;
|
2020-06-01 18:28:04 +00:00
|
|
|
#ifdef FIX_BUGS
|
|
|
|
// times are subtracted and divided giving NaNs
|
|
|
|
// so they can't both be 0
|
|
|
|
frame->time = i/hier->numNodes;
|
|
|
|
#else
|
2020-04-23 20:25:18 +00:00
|
|
|
frame->time = 0.0f;
|
2020-06-01 18:28:04 +00:00
|
|
|
#endif
|
2020-04-23 20:25:18 +00:00
|
|
|
frame->prevFrame = nil;
|
|
|
|
}
|
|
|
|
return anim;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RenderSkeleton(RpHAnimHierarchy *hier)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int sp;
|
|
|
|
int stack[32];
|
|
|
|
int par;
|
|
|
|
CVector p1, p2;
|
|
|
|
int numNodes = hier->numNodes;
|
|
|
|
RwMatrix *mats = RpHAnimHierarchyGetMatrixArray(hier);
|
|
|
|
p1 = mats[0].pos;
|
|
|
|
|
|
|
|
par = 0;
|
|
|
|
sp = 0;
|
|
|
|
stack[sp++] = par;
|
|
|
|
for(i = 1; i < numNodes; i++){
|
|
|
|
p1 = mats[par].pos;
|
|
|
|
p2 = mats[i].pos;
|
|
|
|
CDebug::AddLine(p1, p2, 0xFFFFFFFF, 0xFFFFFFFF);
|
|
|
|
if(HIERNODEINFO(hier)[i].flags & rpHANIMPUSHPARENTMATRIX)
|
|
|
|
stack[sp++] = par;
|
|
|
|
par = i;
|
|
|
|
if(HIERNODEINFO(hier)[i].flags & rpHANIMPOPPARENTMATRIX)
|
|
|
|
par = stack[--sp];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-29 09:17:53 +00:00
|
|
|
|
|
|
|
RwBool Im2DRenderQuad(RwReal x1, RwReal y1, RwReal x2, RwReal y2, RwReal z, RwReal recipCamZ, RwReal uvOffset)
|
|
|
|
{
|
|
|
|
RwIm2DVertex vx[4];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Render an opaque white 2D quad at the given coordinates and
|
|
|
|
* spanning a whole texture.
|
|
|
|
*/
|
|
|
|
|
|
|
|
RwIm2DVertexSetScreenX(&vx[0], x1);
|
|
|
|
RwIm2DVertexSetScreenY(&vx[0], y1);
|
|
|
|
RwIm2DVertexSetScreenZ(&vx[0], z);
|
|
|
|
RwIm2DVertexSetIntRGBA(&vx[0], 255, 255, 255, 255);
|
|
|
|
RwIm2DVertexSetRecipCameraZ(&vx[0], recipCamZ);
|
|
|
|
RwIm2DVertexSetU(&vx[0], uvOffset, recipCamZ);
|
|
|
|
RwIm2DVertexSetV(&vx[0], uvOffset, recipCamZ);
|
|
|
|
|
|
|
|
RwIm2DVertexSetScreenX(&vx[1], x1);
|
|
|
|
RwIm2DVertexSetScreenY(&vx[1], y2);
|
|
|
|
RwIm2DVertexSetScreenZ(&vx[1], z);
|
|
|
|
RwIm2DVertexSetIntRGBA(&vx[1], 255, 255, 255, 255);
|
|
|
|
RwIm2DVertexSetRecipCameraZ(&vx[1], recipCamZ);
|
|
|
|
RwIm2DVertexSetU(&vx[1], uvOffset, recipCamZ);
|
|
|
|
RwIm2DVertexSetV(&vx[1], 1.0f + uvOffset, recipCamZ);
|
|
|
|
|
|
|
|
RwIm2DVertexSetScreenX(&vx[2], x2);
|
|
|
|
RwIm2DVertexSetScreenY(&vx[2], y1);
|
|
|
|
RwIm2DVertexSetScreenZ(&vx[2], z);
|
|
|
|
RwIm2DVertexSetIntRGBA(&vx[2], 255, 255, 255, 255);
|
|
|
|
RwIm2DVertexSetRecipCameraZ(&vx[2], recipCamZ);
|
|
|
|
RwIm2DVertexSetU(&vx[2], 1.0f + uvOffset, recipCamZ);
|
|
|
|
RwIm2DVertexSetV(&vx[2], uvOffset, recipCamZ);
|
|
|
|
|
|
|
|
RwIm2DVertexSetScreenX(&vx[3], x2);
|
|
|
|
RwIm2DVertexSetScreenY(&vx[3], y2);
|
|
|
|
RwIm2DVertexSetScreenZ(&vx[3], z);
|
|
|
|
RwIm2DVertexSetIntRGBA(&vx[3], 255, 255, 255, 255);
|
|
|
|
RwIm2DVertexSetRecipCameraZ(&vx[3], recipCamZ);
|
|
|
|
RwIm2DVertexSetU(&vx[3], 1.0f + uvOffset, recipCamZ);
|
|
|
|
RwIm2DVertexSetV(&vx[3], 1.0f + uvOffset, recipCamZ);
|
|
|
|
|
|
|
|
RwIm2DRenderPrimitive(rwPRIMTYPETRISTRIP, vx, 4);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool b_cbsUseLTM = true;
|
|
|
|
|
|
|
|
RpAtomic *cbsCalcMeanBSphereRadiusCB(RpAtomic *atomic, void *data)
|
|
|
|
{
|
|
|
|
RwV3d atomicPos;
|
|
|
|
|
|
|
|
if ( b_cbsUseLTM )
|
|
|
|
RwV3dTransformPoints(&atomicPos, &RpAtomicGetBoundingSphere(atomic)->center, 1, RwFrameGetLTM(RpClumpGetFrame(atomic->clump)));
|
|
|
|
else
|
|
|
|
RwV3dTransformPoints(&atomicPos, &RpAtomicGetBoundingSphere(atomic)->center, 1, RwFrameGetMatrix(RpClumpGetFrame(atomic->clump)));
|
|
|
|
|
|
|
|
RwV3d temp;
|
|
|
|
RwV3dSub(&temp, &atomicPos, &((RwSphere *)data)->center);
|
|
|
|
RwReal radius = RwV3dLength(&temp) + RpAtomicGetBoundingSphere(atomic)->radius;
|
|
|
|
|
|
|
|
if ( ((RwSphere *)data)->radius < radius )
|
|
|
|
((RwSphere *)data)->radius = radius;
|
|
|
|
|
|
|
|
return atomic;
|
|
|
|
}
|
|
|
|
|
|
|
|
RpAtomic *cbsCalcMeanBSphereCenterCB(RpAtomic *atomic, void *data)
|
|
|
|
{
|
|
|
|
RwV3d atomicPos;
|
|
|
|
|
|
|
|
if ( b_cbsUseLTM )
|
|
|
|
RwV3dTransformPoints(&atomicPos, &RpAtomicGetBoundingSphere(atomic)->center, 1, RwFrameGetLTM(RpClumpGetFrame(atomic->clump)));
|
|
|
|
else
|
|
|
|
RwV3dTransformPoints(&atomicPos, &RpAtomicGetBoundingSphere(atomic)->center, 1, RwFrameGetMatrix(RpClumpGetFrame(atomic->clump)));
|
|
|
|
|
|
|
|
RwV3dAdd(&((RwSphere *)data)->center, &((RwSphere *)data)->center, &atomicPos);
|
|
|
|
|
|
|
|
return atomic;
|
|
|
|
}
|
|
|
|
|
|
|
|
RpClump *RpClumpGetBoundingSphere(RpClump *clump, RwSphere *sphere, bool useLTM)
|
|
|
|
{
|
|
|
|
RwMatrix matrix;
|
|
|
|
RwSphere result = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
|
|
|
|
|
|
b_cbsUseLTM = useLTM;
|
|
|
|
|
2020-07-31 18:21:58 +00:00
|
|
|
if ( clump == nil || sphere == nil )
|
|
|
|
return nil;
|
2020-07-29 09:17:53 +00:00
|
|
|
|
|
|
|
sphere->radius = 0.0f;
|
|
|
|
sphere->center.x = 0.0f;
|
|
|
|
sphere->center.y = 0.0f;
|
|
|
|
sphere->center.z = 0.0f;
|
|
|
|
|
|
|
|
RwInt32 numAtomics = RpClumpGetNumAtomics(clump);
|
|
|
|
if ( numAtomics < 1.0f )
|
2020-07-31 18:21:58 +00:00
|
|
|
return nil;
|
2020-07-29 09:17:53 +00:00
|
|
|
|
|
|
|
RpClumpForAllAtomics(clump, cbsCalcMeanBSphereCenterCB, &result);
|
|
|
|
|
|
|
|
RwV3dScale(&result.center, &result.center, 1.0f/numAtomics);
|
|
|
|
|
|
|
|
RpClumpForAllAtomics(clump, cbsCalcMeanBSphereRadiusCB, &result);
|
|
|
|
|
|
|
|
if ( b_cbsUseLTM )
|
|
|
|
RwMatrixInvert(&matrix, RwFrameGetLTM(RpClumpGetFrame(clump)));
|
|
|
|
else
|
|
|
|
RwMatrixInvert(&matrix, RwFrameGetMatrix(RpClumpGetFrame(clump)));
|
|
|
|
|
|
|
|
RwV3dTransformPoints(&result.center, &result.center, 1, &matrix);
|
|
|
|
|
2020-07-29 09:41:53 +00:00
|
|
|
*sphere = result;
|
2020-07-29 09:17:53 +00:00
|
|
|
|
|
|
|
return clump;
|
|
|
|
}
|
|
|
|
|
2019-06-12 17:05:06 +00:00
|
|
|
void
|
|
|
|
CameraSize(RwCamera * camera, RwRect * rect,
|
|
|
|
RwReal viewWindow, RwReal aspectRatio)
|
|
|
|
{
|
|
|
|
if (camera)
|
|
|
|
{
|
|
|
|
RwVideoMode videoMode;
|
|
|
|
RwRect r;
|
2019-06-13 09:57:43 +00:00
|
|
|
RwRect origSize = { 0, 0, 0, 0 }; // FIX just to make the compier happy
|
2019-06-12 17:05:06 +00:00
|
|
|
RwV2d vw;
|
|
|
|
|
|
|
|
RwEngineGetVideoModeInfo(&videoMode,
|
|
|
|
RwEngineGetCurrentVideoMode());
|
2020-05-11 02:55:57 +00:00
|
|
|
|
2019-06-12 17:05:06 +00:00
|
|
|
origSize.w = RwRasterGetWidth(RwCameraGetRaster(camera));
|
|
|
|
origSize.h = RwRasterGetHeight(RwCameraGetRaster(camera));
|
|
|
|
|
|
|
|
if (!rect)
|
|
|
|
{
|
|
|
|
if (videoMode.flags & rwVIDEOMODEEXCLUSIVE)
|
|
|
|
{
|
|
|
|
/* For full screen applications, resizing the camera just doesn't
|
|
|
|
* make sense, use the video mode size.
|
|
|
|
*/
|
2020-05-11 02:55:57 +00:00
|
|
|
|
2019-06-12 17:05:06 +00:00
|
|
|
r.x = r.y = 0;
|
|
|
|
r.w = videoMode.width;
|
|
|
|
r.h = videoMode.height;
|
|
|
|
rect = &r;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
rect not specified - reuse current values
|
|
|
|
*/
|
|
|
|
r.w = RwRasterGetWidth(RwCameraGetRaster(camera));
|
|
|
|
r.h = RwRasterGetHeight(RwCameraGetRaster(camera));
|
|
|
|
r.x = r.y = 0;
|
|
|
|
rect = &r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-14 15:07:05 +00:00
|
|
|
if (( origSize.w != rect->w ) || ( origSize.h != rect->h ))
|
2019-06-12 17:05:06 +00:00
|
|
|
{
|
|
|
|
RwRaster *raster;
|
|
|
|
RwRaster *zRaster;
|
2020-05-11 02:55:57 +00:00
|
|
|
|
2020-10-14 15:07:05 +00:00
|
|
|
// BUG: game just changes camera raster's sizes, but this is a hack
|
|
|
|
#ifdef FIX_BUGS
|
2019-06-12 17:05:06 +00:00
|
|
|
/*
|
|
|
|
* Destroy rasters...
|
|
|
|
*/
|
2020-05-11 02:55:57 +00:00
|
|
|
|
2019-06-12 17:05:06 +00:00
|
|
|
raster = RwCameraGetRaster(camera);
|
|
|
|
if( raster )
|
|
|
|
{
|
|
|
|
RwRasterDestroy(raster);
|
2020-10-24 18:56:04 +00:00
|
|
|
camera->frameBuffer = nil;
|
2019-06-12 17:05:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
zRaster = RwCameraGetZRaster(camera);
|
|
|
|
if( zRaster )
|
|
|
|
{
|
|
|
|
RwRasterDestroy(zRaster);
|
2020-10-24 18:56:04 +00:00
|
|
|
camera->zBuffer = nil;
|
2019-06-12 17:05:06 +00:00
|
|
|
}
|
2020-05-11 02:55:57 +00:00
|
|
|
|
2019-06-12 17:05:06 +00:00
|
|
|
/*
|
2020-05-11 02:55:57 +00:00
|
|
|
* Create new rasters...
|
2019-06-12 17:05:06 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
raster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA);
|
|
|
|
zRaster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER);
|
2020-05-11 02:55:57 +00:00
|
|
|
|
2019-06-12 17:05:06 +00:00
|
|
|
if( raster && zRaster )
|
2019-06-12 17:08:04 +00:00
|
|
|
{
|
|
|
|
RwCameraSetRaster(camera, raster);
|
|
|
|
RwCameraSetZRaster(camera, zRaster);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( raster )
|
|
|
|
{
|
|
|
|
RwRasterDestroy(raster);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( zRaster )
|
|
|
|
{
|
|
|
|
RwRasterDestroy(zRaster);
|
|
|
|
}
|
|
|
|
|
|
|
|
rect->x = origSize.x;
|
|
|
|
rect->y = origSize.y;
|
2019-06-12 18:07:37 +00:00
|
|
|
rect->w = origSize.w;
|
2019-06-12 17:08:04 +00:00
|
|
|
rect->h = origSize.h;
|
2019-06-12 17:05:06 +00:00
|
|
|
|
2020-05-11 02:55:57 +00:00
|
|
|
/*
|
|
|
|
* Use default values...
|
2019-06-12 17:08:04 +00:00
|
|
|
*/
|
|
|
|
raster =
|
|
|
|
RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA);
|
2019-06-12 17:05:06 +00:00
|
|
|
|
2019-06-12 17:08:04 +00:00
|
|
|
zRaster =
|
|
|
|
RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER);
|
2019-06-12 17:05:06 +00:00
|
|
|
|
2019-06-12 17:08:04 +00:00
|
|
|
RwCameraSetRaster(camera, raster);
|
|
|
|
RwCameraSetZRaster(camera, zRaster);
|
|
|
|
}
|
2020-10-14 15:07:05 +00:00
|
|
|
#else
|
|
|
|
raster = RwCameraGetRaster(camera);
|
|
|
|
zRaster = RwCameraGetZRaster(camera);
|
|
|
|
|
|
|
|
raster->width = zRaster->width = rect->w;
|
|
|
|
raster->height = zRaster->height = rect->h;
|
|
|
|
#endif
|
2019-06-12 17:05:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Figure out the view window */
|
|
|
|
if (videoMode.flags & rwVIDEOMODEEXCLUSIVE)
|
|
|
|
{
|
|
|
|
/* derive ratio from aspect ratio */
|
|
|
|
vw.x = viewWindow;
|
|
|
|
vw.y = viewWindow / aspectRatio;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* derive from pixel ratios */
|
|
|
|
if (rect->w > rect->h)
|
|
|
|
{
|
|
|
|
vw.x = viewWindow;
|
|
|
|
vw.y = (rect->h * viewWindow) / rect->w;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vw.x = (rect->w * viewWindow) / rect->h;
|
|
|
|
vw.y = viewWindow;
|
|
|
|
}
|
|
|
|
}
|
2020-05-11 02:55:57 +00:00
|
|
|
|
2019-06-12 17:05:06 +00:00
|
|
|
RwCameraSetViewWindow(camera, &vw);
|
2020-05-11 02:55:57 +00:00
|
|
|
|
2019-06-12 17:05:06 +00:00
|
|
|
RsGlobal.width = rect->w;
|
|
|
|
RsGlobal.height = rect->h;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CameraDestroy(RwCamera *camera)
|
|
|
|
{
|
|
|
|
RwRaster *raster, *tmpRaster;
|
|
|
|
RwFrame *frame;
|
|
|
|
|
|
|
|
if (camera)
|
|
|
|
{
|
|
|
|
frame = RwCameraGetFrame(camera);
|
|
|
|
if (frame)
|
|
|
|
{
|
|
|
|
RwFrameDestroy(frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
raster = RwCameraGetRaster(camera);
|
|
|
|
if (raster)
|
|
|
|
{
|
|
|
|
tmpRaster = RwRasterGetParent(raster);
|
|
|
|
|
|
|
|
RwRasterDestroy(raster);
|
|
|
|
|
2019-06-30 10:53:39 +00:00
|
|
|
if ((tmpRaster != nil) && (tmpRaster != raster))
|
2019-06-12 17:05:06 +00:00
|
|
|
{
|
|
|
|
RwRasterDestroy(tmpRaster);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
raster = RwCameraGetZRaster(camera);
|
|
|
|
if (raster)
|
|
|
|
{
|
|
|
|
tmpRaster = RwRasterGetParent(raster);
|
|
|
|
|
|
|
|
RwRasterDestroy(raster);
|
|
|
|
|
2019-06-30 10:53:39 +00:00
|
|
|
if ((tmpRaster != nil) && (tmpRaster != raster))
|
2019-06-12 17:05:06 +00:00
|
|
|
{
|
|
|
|
RwRasterDestroy(tmpRaster);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RwCameraDestroy(camera);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RwCamera *
|
|
|
|
CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer)
|
|
|
|
{
|
|
|
|
RwCamera *camera;
|
|
|
|
|
|
|
|
camera = RwCameraCreate();
|
|
|
|
|
|
|
|
if (camera)
|
|
|
|
{
|
|
|
|
RwCameraSetFrame(camera, RwFrameCreate());
|
|
|
|
RwCameraSetRaster(camera,
|
|
|
|
RwRasterCreate(0, 0, 0, rwRASTERTYPECAMERA));
|
|
|
|
|
|
|
|
if (zBuffer)
|
|
|
|
{
|
|
|
|
RwCameraSetZRaster(camera,
|
|
|
|
RwRasterCreate(0, 0, 0,
|
|
|
|
rwRASTERTYPEZBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now check that everything is valid */
|
|
|
|
if (RwCameraGetFrame(camera) &&
|
|
|
|
RwCameraGetRaster(camera) &&
|
|
|
|
RwRasterGetParent(RwCameraGetRaster(camera)) &&
|
|
|
|
(!zBuffer || (RwCameraGetZRaster(camera) &&
|
|
|
|
RwRasterGetParent(RwCameraGetZRaster
|
|
|
|
(camera)))))
|
|
|
|
{
|
|
|
|
/* everything OK */
|
|
|
|
return (camera);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we're here then an error must have occurred so clean up */
|
|
|
|
|
|
|
|
CameraDestroy(camera);
|
2019-06-30 10:53:39 +00:00
|
|
|
return (nil);
|
2019-06-12 17:05:06 +00:00
|
|
|
}
|
|
|
|
|
2020-07-16 11:36:25 +00:00
|
|
|
#ifdef LIBRW
|
|
|
|
#include <rpmatfx.h>
|
|
|
|
#include "VehicleModelInfo.h"
|
|
|
|
|
|
|
|
int32
|
|
|
|
findPlatform(rw::Atomic *a)
|
|
|
|
{
|
|
|
|
rw::Geometry *g = a->geometry;
|
|
|
|
if(g->instData)
|
|
|
|
return g->instData->platform;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Game doesn't read atomic extensions so we never get any other than the default pipe,
|
|
|
|
// but we need it for uninstancing
|
|
|
|
void
|
|
|
|
attachPipe(rw::Atomic *atomic)
|
|
|
|
{
|
|
|
|
if(RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic)))
|
|
|
|
atomic->pipeline = rw::skinGlobals.pipelines[rw::platform];
|
|
|
|
else{
|
|
|
|
int fx = rpMATFXEFFECTNULL;
|
|
|
|
RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), CVehicleModelInfo::GetMatFXEffectMaterialCB, &fx);
|
|
|
|
if(fx != rpMATFXEFFECTNULL)
|
|
|
|
RpMatFXAtomicEnableEffects(atomic);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attach pipes for the platform we have native data for so we can uninstance
|
|
|
|
void
|
|
|
|
switchPipes(rw::Atomic *a, int32 platform)
|
|
|
|
{
|
|
|
|
if(a->pipeline && a->pipeline->platform != platform){
|
|
|
|
uint32 plgid = a->pipeline->pluginID;
|
|
|
|
switch(plgid){
|
|
|
|
// assume default pipe won't be attached explicitly
|
|
|
|
case rw::ID_SKIN:
|
|
|
|
a->pipeline = rw::skinGlobals.pipelines[platform];
|
|
|
|
break;
|
|
|
|
case rw::ID_MATFX:
|
|
|
|
a->pipeline = rw::matFXGlobals.pipelines[platform];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RpAtomic*
|
|
|
|
ConvertPlatformAtomic(RpAtomic *atomic, void *data)
|
|
|
|
{
|
|
|
|
int32 driver = rw::platform;
|
|
|
|
int32 platform = findPlatform(atomic);
|
|
|
|
if(platform != 0 && platform != driver){
|
|
|
|
attachPipe(atomic); // kludge
|
|
|
|
rw::ObjPipeline *origPipe = atomic->pipeline;
|
|
|
|
rw::platform = platform;
|
|
|
|
switchPipes(atomic, rw::platform);
|
|
|
|
if(atomic->geometry->flags & rw::Geometry::NATIVE)
|
|
|
|
atomic->uninstance();
|
|
|
|
// no ADC in this game
|
|
|
|
//rw::ps2::unconvertADC(atomic->geometry);
|
|
|
|
rw::platform = driver;
|
|
|
|
atomic->pipeline = origPipe;
|
|
|
|
}
|
|
|
|
return atomic;
|
|
|
|
}
|
|
|
|
#endif
|
2020-07-29 12:34:57 +00:00
|
|
|
|
2020-07-29 11:56:06 +00:00
|
|
|
#if defined(FIX_BUGS) && defined(GTA_PC)
|
|
|
|
RwUInt32 saved_alphafunc, saved_alpharef;
|
|
|
|
|
|
|
|
void
|
|
|
|
SetAlphaTest(RwUInt32 alpharef)
|
|
|
|
{
|
|
|
|
#ifdef LIBRW
|
|
|
|
saved_alphafunc = rw::GetRenderState(rw::ALPHATESTFUNC);
|
|
|
|
saved_alpharef = rw::GetRenderState(rw::ALPHATESTREF);
|
|
|
|
|
|
|
|
rw::SetRenderState(rw::ALPHATESTFUNC, rw::ALPHAGREATEREQUAL);
|
|
|
|
rw::SetRenderState(rw::ALPHATESTREF, 0);
|
|
|
|
#else
|
|
|
|
RwD3D8GetRenderState(D3DRS_ALPHAFUNC, &saved_alphafunc);
|
|
|
|
RwD3D8GetRenderState(D3DRS_ALPHAREF, &saved_alpharef);
|
|
|
|
|
|
|
|
RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
|
|
|
|
RwD3D8SetRenderState(D3DRS_ALPHAREF, alpharef);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RestoreAlphaTest()
|
|
|
|
{
|
|
|
|
#ifdef LIBRW
|
|
|
|
rw::SetRenderState(rw::ALPHATESTFUNC, saved_alphafunc);
|
|
|
|
rw::SetRenderState(rw::ALPHATESTREF, saved_alpharef);
|
|
|
|
#else
|
|
|
|
RwD3D8SetRenderState(D3DRS_ALPHAFUNC, saved_alphafunc);
|
|
|
|
RwD3D8SetRenderState(D3DRS_ALPHAREF, saved_alpharef);
|
|
|
|
#endif
|
|
|
|
}
|
2020-08-20 10:53:17 +00:00
|
|
|
#endif
|