diff --git a/src/WaterLevel.cpp b/src/WaterLevel.cpp new file mode 100644 index 0000000..799a0b3 --- /dev/null +++ b/src/WaterLevel.cpp @@ -0,0 +1,103 @@ +#include "skygfx.h" + +// ADDRESS +RwTexture *&gpWaterTex = *AddressByVersion(0, 0, 0, 0x77FA58, 0, 0); +RpAtomic *&ms_pWavyAtomic = *AddressByVersion(0, 0, 0, 0xA10860, 0, 0); +RpAtomic *&ms_pMaskAtomic = *AddressByVersion(0, 0, 0, 0xA0D9A8, 0, 0); +float &TEXTURE_ADDU = *AddressByVersion(0, 0, 0, 0x77FA6C, 0, 0); +float &TEXTURE_ADDV = *AddressByVersion(0, 0, 0, 0x77FA70, 0, 0); + +MatFXEnv* +getEnvData(RpMaterial *mat) +{ + MatFX *matfx = *RWPLUGINOFFSET(MatFX*, mat, MatFXMaterialDataOffset); + MatFXEnv *env = &matfx->fx[0]; + if(env->effect == rpMATFXEFFECTENVMAP) + return env; + env = &matfx->fx[1]; + if(env->effect == rpMATFXEFFECTENVMAP) + return env; + return nil; +} + +// Wavy atomic is 32x32 units with 17x17 vertices +// Mask atomic is 64x64 units with 33x33 vertices +// One texture is stretched over 32 units + +bool (*PreCalcWavyMask_orig)(float x, float y, float z, float a4, float a5, float a6, float a7, int _1, int _2, RwRGBA *colour); +bool +PreCalcWavyMask(float x, float y, float z, float a4, float a5, float a6, float a7, int _1, int _2, RwRGBA *colour) +{ + bool ret = PreCalcWavyMask_orig(x, y, z, a4, a5, a6, a7, _1, _2, colour); + + RpGeometry *maskgeo = RpAtomicGetGeometry(ms_pMaskAtomic); + MatFXEnv *env = getEnvData(maskgeo->matList.materials[0]); + env->envCoeff = 0.5f; + + RpGeometryLock(maskgeo, rpGEOMETRYLOCKTEXCOORDS | rpGEOMETRYLOCKPRELIGHT); + + int i, j; + const float ustep = 2.0f / 32.0f; + const float vstep = 2.0f / 32.0f; + const float ustart = TEXTURE_ADDU + (x+16.0f)/32.0f; + const float vstart = TEXTURE_ADDV + (y)/32.0f; + RwTexCoords *uv = maskgeo->texCoords[0]; + + for(i = 0; i < 33; i++) // x + for(j = 0; j < 33; j++){ // y + uv[i*33 + j].u = ustart + ustep*i; + uv[i*33 + j].v = vstart + vstep*j; + } + + const float inc = 1.0f/17.0f; + int ii, jj; + RwRGBA *c = maskgeo->preLitLum; + float fx, fy; + fx = 0.0f; + uchar alpha; + for(i = 0; i < 17; i++){ + fy = 0.0f; + for(j = 0; j < 17; j++){ + ii = 32-i; + jj = 32-j; + alpha = fx*fy*255; + if(alpha > colour->alpha) alpha = colour->alpha; + c[i*33 + j].alpha = alpha; + c[i*33 + jj].alpha = alpha; + c[ii*33 + jj].alpha = alpha; + c[ii*33 + j].alpha = alpha; + + fy += inc; + } + fx += inc; + } + + RpGeometryUnlock(maskgeo); + + + // Wavy test + + ms_pWavyAtomic->geometry->matList.materials[0]->color.alpha = 192; + RpGeometryLock(ms_pWavyAtomic->geometry, rpGEOMETRYLOCKPRELIGHT); + c = ms_pWavyAtomic->geometry->preLitLum; + for(i = 0; i < 17; i++) + for(j = 0; j < 17; j++){ + c[i*17 + j].alpha = colour->alpha; + } + RpGeometryUnlock(ms_pWavyAtomic->geometry); + + + return ret; +} + +void +patchWater(void) +{ + // Replace sandy mask by clearwater + Patch(0x5C2E8C + 1, &gpWaterTex); + + static float maskWaterEnvCoeff = 0.4f; // 0.25 on PC, but later changed to 0.5 anyway... + Patch(0x5C3816 + 2, &maskWaterEnvCoeff); + + InterceptCall(&PreCalcWavyMask_orig, PreCalcWavyMask, 0x5BF977); +} diff --git a/src/main.cpp b/src/main.cpp index 6dd6b06..d685af6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,10 @@ DebugMenuAPI gDebugMenuAPI; char asipath[MAX_PATH]; int gtaversion = -1; + +void enableTrailsSetting(void); +void patchWater(void); + char* getpath(char *path) { @@ -68,14 +72,13 @@ RwImVertexIndex *blurIndices = AddressByVersion(0x5FDD90, 0x5F static addr DefinedState_A = AddressByVersion(0x526330, 0x526570, 0x526500, 0x57F9C0, 0x57F9E0, 0x57F7F0); WRAPPER void DefinedState(void) { VARJMP(DefinedState_A); } -float matFXcoef = 0.7f; - int blendstyle, blendkey; int texgenstyle, texgenkey; int neocarpipe, neocarpipekey; int rimlight, rimlightkey; int neowaterdrops, neoblooddrops; int envMapSize; +int disableColourOverlay; Config config; int dualpass; @@ -118,6 +121,19 @@ d3dtorwmat(RwMatrix *rw, D3DMATRIX *d3d) rw->pos.z = d3d->m[3][2]; } +void +_rwD3D8EnableClippingIfNeeded(void *object, RwUInt8 type) +{ + int clip; + if(type == rpATOMIC) + clip = !RwD3D8CameraIsSphereFullyInsideFrustum((RwCamera*)((RwGlobals*)RwEngineInst)->curCamera, + RpAtomicGetWorldBoundingSphere((RpAtomic*)object)); + else + clip = !RwD3D8CameraIsBBoxFullyInsideFrustum((RwCamera*)((RwGlobals*)RwEngineInst)->curCamera, + &((RpWorldSector*)object)->tightBoundingBox); + RwD3D8SetRenderState(D3DRS_CLIPPING, clip); +} + static addr ApplyEnvMapTextureMatrix_A = AddressByVersion(0x5CFD40, 0x5D0000, 0x5D89E0, 0x6755D0, 0x675620, 0x674580); WRAPPER void ApplyEnvMapTextureMatrix(RwTexture* a1, int a2, RwFrame* a3) { @@ -244,10 +260,8 @@ int rpMatFXD3D8AtomicMatFXDefaultRender(RxD3D8InstanceData *inst, int flags, RwT return 0; } -RwTexture *&pWaterTexReflection = *AddressByVersion(0, 0, 0, 0x77FA5C, 0x77FA5C, 0x77EA5C); - int -rpMatFXD3D8AtomicMatFXEnvRender_dual(RxD3D8InstanceData *inst, int flags, int sel, RwTexture *texture, RwTexture *envMap) +rpMatFXD3D8AtomicMatFXEnvRender_ps2(RxD3D8InstanceData *inst, int flags, int sel, RwTexture *texture, RwTexture *envMap) { MatFX *matfx = *RWPLUGINOFFSET(MatFX*, inst->material, MatFXMaterialDataOffset); MatFXEnv *env = &matfx->fx[sel]; @@ -261,33 +275,29 @@ rpMatFXD3D8AtomicMatFXEnvRender_dual(RxD3D8InstanceData *inst, int flags, int se }else keystate = false; } - // rather ugly way to single out water. more research needed here - if(blendstyle == 1 || isVC() && envMap == pWaterTexReflection) - return rpMatFXD3D8AtomicMatFXEnvRender(inst, flags, sel, texture, envMap); - - static float mult = isIII() ? 2.0f : 4.0f; - float factor = env->envCoeff*mult*255.0f; -//if(factor != 0.0f) factor = matFXcoef*255.0f; -//if(strstr(texture->name, "body")) texture = nil; -//envMap = CarPipe::reflectionTex; - RwUInt8 intens = (RwUInt8)factor; - - if(factor == 0.0f || !envMap){ + + // Render PC envmap + if(blendstyle == 1){ + float oldcoeff = env->envCoeff; + static float carMult = isIII() ? 0.5f : 0.25f; + if(env->envFBalpha == 0) // hacky way to distinguish vehicles from water + env->envCoeff *= carMult; + int ret = rpMatFXD3D8AtomicMatFXEnvRender(inst, flags, sel, texture, envMap); + env->envCoeff = oldcoeff; + return ret; + } + + uchar intens = (uchar)(env->envCoeff*255.0f); + if(intens == 0 || !envMap){ if(sel == 0) return rpMatFXD3D8AtomicMatFXDefaultRender(inst, flags, texture); return 0; } - if(inst->vertexAlpha || inst->material->color.alpha != 0xFFu){ - if(!rwD3D8RenderStateIsVertexAlphaEnable()) - rwD3D8RenderStateVertexAlphaEnable(1); - }else{ - if(rwD3D8RenderStateIsVertexAlphaEnable()) - rwD3D8RenderStateVertexAlphaEnable(0); - } - if(flags & 0x84 && texture) + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF)); + if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture) RwD3D8SetTexture(texture, 0); else - RwD3D8SetTexture(NULL, 0); + RwD3D8SetTexture(nil, 0); RwD3D8SetVertexShader(inst->vertexShader); RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride); RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex); @@ -295,28 +305,33 @@ rpMatFXD3D8AtomicMatFXEnvRender_dual(RxD3D8InstanceData *inst, int flags, int se RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices); else RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices); + + // Effect pass ApplyEnvMapTextureMatrix(envMap, 0, env->envFrame); - if(!rwD3D8RenderStateIsVertexAlphaEnable()) - rwD3D8RenderStateVertexAlphaEnable(1); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)1); RwUInt32 src, dst, lighting, zwrite, fog, fogcol; RwRenderStateGet(rwRENDERSTATESRCBLEND, &src); RwRenderStateGet(rwRENDERSTATEDESTBLEND, &dst); -// RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); + + // This is of course not using framebuffer alpha, + // but if the diffuse texture had no alpha, the result should actually be rather the same + if(env->envFBalpha) + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + else + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting); RwD3D8GetRenderState(D3DRS_ZWRITEENABLE, &zwrite); RwD3D8GetRenderState(D3DRS_FOGENABLE, &fog); RwD3D8SetRenderState(D3DRS_FOGENABLE, 0); -// RwD3D8SetRenderState(D3DRS_LIGHTING, 0); RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, 0); if(fog){ RwD3D8GetRenderState(D3DRS_FOGCOLOR, &fogcol); RwD3D8SetRenderState(D3DRS_FOGCOLOR, 0); } - RwUInt32 texfactor = ((intens | ((intens | (intens << 8)) << 8)) << 8) | intens; + D3DCOLOR texfactor = D3DCOLOR_RGBA(intens, intens, intens, intens); RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, texfactor); RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); RwD3D8SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT); @@ -331,6 +346,8 @@ rpMatFXD3D8AtomicMatFXEnvRender_dual(RxD3D8InstanceData *inst, int flags, int se else RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices); + // Reset states + rwD3D8RenderStateVertexAlphaEnable(0); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)src); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)dst); @@ -499,7 +516,7 @@ CreateTextureFilterFlags(RwRaster *raster) return tex; } -WRAPPER void rpMatFXD3D8AtomicMatFXEnvRender_dual_IIISteam() +WRAPPER void rpMatFXD3D8AtomicMatFXEnvRender_ps2_IIISteam() { __asm { @@ -511,7 +528,7 @@ WRAPPER void rpMatFXD3D8AtomicMatFXEnvRender_dual_IIISteam() mov [esp+0Ch], ecx mov ecx, [esp+28h] mov [esp+10h], ecx - call rpMatFXD3D8AtomicMatFXEnvRender_dual + call rpMatFXD3D8AtomicMatFXEnvRender_ps2 add esp, 20 retn } @@ -733,6 +750,22 @@ footsplash_hook(void) } } +void (*CMBlur__MotionBlurRenderIII_orig)(RwCamera*, RwUInt8, RwUInt8, RwUInt8, RwUInt8, int, int); +void +CMBlur__MotionBlurRenderIII(RwCamera *cam, RwUInt8 red, RwUInt8 green, RwUInt8 blue, RwUInt8 alpha, int type, int bluralpha) +{ + if(!disableColourOverlay) + CMBlur__MotionBlurRenderIII_orig(cam, red, green, blue, alpha, type, bluralpha); +} + +void (*CMBlur__MotionBlurRenderVC_orig)(RwCamera*, RwUInt8, RwUInt8, RwUInt8, RwUInt8, int); +void +CMBlur__MotionBlurRenderVC(RwCamera *cam, RwUInt8 red, RwUInt8 green, RwUInt8 blue, RwUInt8 alpha, int type) +{ + if(!disableColourOverlay) + CMBlur__MotionBlurRenderVC_orig(cam, red, green, blue, alpha, type); +} + // // real time reflection test; III 1.0 // @@ -831,8 +864,13 @@ delayedPatches(int a, int b) DebugMenuAddVarBool32("SkyGFX", "Neo rim light pipe", &rimlight, nil); DebugMenuAddVarBool32("SkyGFX", "Neo world pipe", &config.neoWorldPipe, nil); DebugMenuAddVarBool32("SkyGFX", "Neo gloss pipe", &config.neoGlossPipe, nil); - DebugMenuAddVarBool32("SkyGFX", "Neo water drops", &neowaterdrops, nil); - DebugMenuAddVarBool32("SkyGFX", "Neo-style blood drops", &neoblooddrops, nil); + if(neowaterdrops){ + DebugMenuAddVarBool32("SkyGFX", "Neo water drops", &neowaterdrops, nil); + DebugMenuAddVarBool32("SkyGFX", "Neo-style blood drops", &neoblooddrops, nil); + } + + if(disableColourOverlay >= 0) + DebugMenuAddVarBool32("SkyGFX", "Disable Colour Overlay", &disableColourOverlay, nil); void neoMenu(); neoMenu(); @@ -844,8 +882,6 @@ delayedPatches(int a, int b) DebugMenuAddVar("SkyGFX|ScreenFX", "Cb offset", &ScreenFX::m_cbOffset, nil, 0.004f, -1.0f, 1.0f); DebugMenuAddVar("SkyGFX|ScreenFX", "Cr scale", &ScreenFX::m_crScale, nil, 0.004f, 0.0f, 10.0f); DebugMenuAddVar("SkyGFX|ScreenFX", "Cr offset", &ScreenFX::m_crOffset, nil, 0.004f, -1.0f, 1.0f); - -// DebugMenuAddVar("SkyGFX", "MatFX coeff", &matFXcoef, nil, 0.1f, 0.0f, 1.0f); } return RsEventHandler_orig(a, b); } @@ -887,6 +923,15 @@ patch(void) hookplugins(); } + disableColourOverlay = readint(cfg.get("SkyGfx", "disableColourOverlay", ""), -1); + + if(disableColourOverlay >= 0){ + if(gtaversion == III_10) + InterceptCall(&CMBlur__MotionBlurRenderIII_orig, CMBlur__MotionBlurRenderIII, 0x46F978); + else if(gtaversion == VC_10) + InterceptCall(&CMBlur__MotionBlurRenderVC_orig, CMBlur__MotionBlurRenderVC, 0x46BE0F); + } + blendkey = readhex(cfg.get("SkyGfx", "texblendSwitchKey", "0x0").c_str()); texgenkey = readhex(cfg.get("SkyGfx", "texgenSwitchKey", "0x0").c_str()); neocarpipekey = readhex(cfg.get("SkyGfx", "neoCarPipeKey", "0x0").c_str()); @@ -894,13 +939,22 @@ patch(void) config.neoWorldPipeKey = readhex(cfg.get("SkyGfx", "neoWorldPipeKey", "0x0").c_str()); config.neoGlossPipeKey = readhex(cfg.get("SkyGfx", "neoGlossPipeKey", "0x0").c_str()); + int ps2water = readint(cfg.get("SkyGfx", "ps2Water", ""), 0); + tmp = cfg.get("SkyGfx", "texblendSwitch", ""); if(tmp != ""){ blendstyle = readint(tmp); + + // MatFX env coefficient on cars + static float envCoeff = 1.0f; + Patch(AddressByVersion(0x5217DF, 0, 0, 0x578B7B, 0, 0) + 2, &envCoeff); + if(ps2water && gtaversion == VC_10) + patchWater(); + if (gtaversion != III_STEAM) - InjectHook(AddressByVersion(0x5D0CE8, 0x5D0FA8, 0, 0x6765C8, 0x676618, 0x675578), rpMatFXD3D8AtomicMatFXEnvRender_dual); + InjectHook(AddressByVersion(0x5D0CE8, 0x5D0FA8, 0, 0x6765C8, 0x676618, 0x675578), rpMatFXD3D8AtomicMatFXEnvRender_ps2); else - InjectHook(0x5D8D37, rpMatFXD3D8AtomicMatFXEnvRender_dual_IIISteam); + InjectHook(0x5D8D37, rpMatFXD3D8AtomicMatFXEnvRender_ps2_IIISteam); } blendstyle %= 2; tmp = cfg.get("SkyGfx", "texgenSwitch", ""); @@ -981,9 +1035,11 @@ patch(void) if(readint(cfg.get("SkyGfx", "replaceDefaultPipeline", ""))){ if(gtaversion == III_10){ Patch(0x5DB427 +2, D3D8AtomicDefaultInstanceCallback_fixed); + Patch(0x5DB42D +3, D3D8AtomicDefaultReinstanceCallback_fixed); Patch(0x5DB43B +3, rxD3D8DefaultRenderCallback_xbox); }else if(gtaversion == VC_10){ Patch(0x67BAB7 +2, D3D8AtomicDefaultInstanceCallback_fixed); + Patch(0x67BABD +3, D3D8AtomicDefaultReinstanceCallback_fixed); Patch(0x67BACB +3, rxD3D8DefaultRenderCallback_xbox); } } @@ -1027,6 +1083,22 @@ patch(void) ScreenFX::m_crScale = readfloat(cfg.get("SkyGfx", "CrScale", ""), 1.23f); ScreenFX::m_crOffset = readfloat(cfg.get("SkyGfx", "CrOffset", ""), 0.0f); + enableTrailsSetting(); + +// Nop(0x4A6594, 5); // water +// Nop(0x4A65AE, 5); // transparent water + + // disable inlined RenderOneFlatLargeWaterPoly +// InjectHook(0x5C1265, 0x5C1442, PATCH_JUMP); + // disable RenderOneFlatSmallWaterPolyBlended +// InjectHook(0x5BD0A0, 0x5BD73D, PATCH_JUMP); + // wavy atomic +// Nop(0x5C0C46, 3); +// Nop(0x5C0E15, 3); +// Nop(0x5C0FEB, 3); +// Nop(0x5C11C0, 3); + // mask atomic +// Nop(0x5C1579, 3); #ifdef DEBUG if(gtaversion == III_10){ @@ -1060,6 +1132,9 @@ patch(void) //MemoryVP::InjectHook(0x650ACB, RwTextureRead_VC); InjectHook(0x401000, printf, PATCH_JUMP); + static float lod0dist = 150.0f; + Patch(0x5818A3 + 2, &lod0dist); + // try to reduce timecyc flickering...didn't work //static float s = 0.0f; //Patch(0x4CEA71 + 2, &s); @@ -1067,9 +1142,13 @@ patch(void) // //Patch(0x4CF47D, 0xc031); // xor eax, eax //Nop(0x4CF47D + 2, 2); + + // disable level load screens + Nop(0x40E00E, 5); + Nop(0x40E01C, 5); + Nop(0x40E157, 5); } #endif - } BOOL WINAPI diff --git a/src/neoCarpipe.cpp b/src/neoCarpipe.cpp index 97d2121..a163073 100644 --- a/src/neoCarpipe.cpp +++ b/src/neoCarpipe.cpp @@ -87,7 +87,7 @@ void RenderScene_hook(void) { RenderScene(); -// if(neocarpipe) + if(neocarpipe) CarPipe::RenderEnvTex(); } @@ -525,6 +525,8 @@ CarPipe::RenderCallback(RwResEntry *repEntry, void *object, RwUInt8 type, RwUInt return; } + _rwD3D8EnableClippingIfNeeded(object, type); + RxD3D8ResEntryHeader *header = (RxD3D8ResEntryHeader*)&repEntry[1]; ShaderSetup(RwFrameGetLTM(RpAtomicGetFrame((RpAtomic*)object))); DiffusePass(header); diff --git a/src/neoRimpipe.cpp b/src/neoRimpipe.cpp index 3c865a7..7a2af6a 100644 --- a/src/neoRimpipe.cpp +++ b/src/neoRimpipe.cpp @@ -285,6 +285,8 @@ RimPipe::RenderCallback(RwResEntry *repEntry, void *object, RwUInt8 type, RwUInt rxD3D8DefaultRenderCallback_xbox(repEntry, object, type, flags); return; } + _rwD3D8EnableClippingIfNeeded(object, type); + ShaderSetup(RwFrameGetLTM(RpAtomicGetFrame((RpAtomic*)object))); RxD3D8ResEntryHeader *header = (RxD3D8ResEntryHeader*)&repEntry[1]; diff --git a/src/neoWorldpipe.cpp b/src/neoWorldpipe.cpp index 5066b35..6d18f89 100644 --- a/src/neoWorldpipe.cpp +++ b/src/neoWorldpipe.cpp @@ -322,6 +322,7 @@ WorldPipe::RenderCallback(RwResEntry *repEntry, void *object, RwUInt8 type, RwUI RxD3D8ResEntryHeader *header = (RxD3D8ResEntryHeader*)&repEntry[1]; RxD3D8InstanceData *inst = (RxD3D8InstanceData*)&header[1]; + _rwD3D8EnableClippingIfNeeded(object, type); RenderObjectSetup(flags); for(int i = 0; i < header->numMeshes; i++){ matfx = *RWPLUGINOFFSET(MatFX*, inst->material, MatFXMaterialDataOffset); diff --git a/src/rw.cpp b/src/rw.cpp index 07cc4dd..bdd8ad4 100644 --- a/src/rw.cpp +++ b/src/rw.cpp @@ -20,6 +20,9 @@ WRAPPER RwReal RwV3dLength(const RwV3d*) { VARJMP(RwV3dLength_A); } static uint32_t D3D8AtomicDefaultInstanceCallback_A = AddressByVersion(0x5DB450, 0x5DB710, 0x5EC520, 0x67BAE0, 0, 0); WRAPPER RwBool D3D8AtomicDefaultInstanceCallback(void*, RxD3D8InstanceData*, RwBool) { VARJMP(D3D8AtomicDefaultInstanceCallback_A); } +static uint32_t D3D8AtomicDefaultReinstanceCallback_A = AddressByVersion(0x5DBFB0, 0, 0, 0x67C640, 0, 0); +WRAPPER RwBool D3D8AtomicDefaultReinstanceCallback(void*, RwResEntry*, const RpMeshHeader*, RxD3D8AllInOneInstanceCallBack) { VARJMP(D3D8AtomicDefaultReinstanceCallback_A); } + static uint32_t rwD3D8RWGetRasterStage_A = AddressByVersion(0x5B5390, 0x5B5650, 0x5BA2C0, 0x659840, 0x659890, 0x6587F0); WRAPPER int rwD3D8RWGetRasterStage(int) { VARJMP(rwD3D8RWGetRasterStage_A); } @@ -179,6 +182,11 @@ WRAPPER RwBool RwStreamFindChunk(RwStream*, RwUInt32, RwUInt32*, RwUInt32*) { VA static uint32_t RwTexDictionaryStreamRead_A = AddressByVersion(0x5924A0, 0, 0, 0x61E710, 0, 0); WRAPPER RwTexDictionary *RwTexDictionaryStreamRead(RwStream*) { VARJMP(RwTexDictionaryStreamRead_A); } +static uint32_t RpGeometryLock_A = AddressByVersion(0, 0, 0, 0x64CCD0, 0, 0); +static uint32_t RpGeometryUnlock_A = AddressByVersion(0, 0, 0, 0x64CD00, 0, 0); +WRAPPER RpGeometry *RpGeometryLock(RpGeometry*, RwInt32) { VARJMP(RpGeometryLock_A); } +WRAPPER RpGeometry *RpGeometryUnlock(RpGeometry*) { VARJMP(RpGeometryUnlock_A); } + static uint32_t RwIm2DGetNearScreenZ_A = AddressByVersion(0x5A43A0, 0x5A4660, 0x5A5340, 0x649B80, 0x649BD0, 0x648B30); WRAPPER RwReal RwIm2DGetNearScreenZ(void) { VARJMP(RwIm2DGetNearScreenZ_A); } static uint32_t RwIm2DRenderIndexedPrimitive_A = AddressByVersion(0x5A4440, 0x5A4700, 0x5A5440, 0x649C20, 0x649C70, 0x648BD0); @@ -219,3 +227,4 @@ WRAPPER void rwD3D8AtomicMatFXRenderCallback(RwResEntry*, void*, RwUInt8, RwUInt static uint32_t RpClumpForAllAtomics_A = AddressByVersion(0x59EDD0, 0x59F090, 0x59EFC0, 0x640D00, 0x640D50, 0x63FCB0); WRAPPER RpClump *RpClumpForAllAtomics(RpClump*, RpAtomicCallBack, void*) { VARJMP(RpClumpForAllAtomics_A); } + diff --git a/src/rwfix.cpp b/src/rwfix.cpp index f86aac5..4d0c6d6 100644 --- a/src/rwfix.cpp +++ b/src/rwfix.cpp @@ -16,6 +16,17 @@ D3D8AtomicDefaultInstanceCallback_fixed(void *object, RxD3D8InstanceData *instan return ret; } +RwBool +D3D8AtomicDefaultReinstanceCallback_fixed(void *object, RwResEntry *resEntry, const RpMeshHeader *meshHeader, RxD3D8AllInOneInstanceCallBack instanceCallback) +{ + RpAtomic *atomic = (RpAtomic*)object; + RwUInt32 mod = atomic->geometry->flags & rpGEOMETRYMODULATEMATERIALCOLOR; + atomic->geometry->flags &= ~rpGEOMETRYMODULATEMATERIALCOLOR; + RwBool ret = D3D8AtomicDefaultReinstanceCallback(object, resEntry, meshHeader, instanceCallback); + atomic->geometry->flags |= mod; + return ret; +} + D3DMATERIAL8 d3dmaterial = { { 0.0f, 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.0f, 1.0f }, @@ -133,14 +144,7 @@ RwD3D8SetSurfaceProperties_d3d9(RwRGBA *color, RwSurfaceProperties *surfProps, R void rxD3D8DefaultRenderCallback_d3d9(RwResEntry *repEntry, void *object, RwUInt8 type, RwUInt32 flags) { - int clip; - if(type == rpATOMIC) - clip = !RwD3D8CameraIsSphereFullyInsideFrustum((RwCamera*)((RwGlobals*)RwEngineInst)->curCamera, - RpAtomicGetWorldBoundingSphere((RpAtomic*)object)); - else - clip = !RwD3D8CameraIsBBoxFullyInsideFrustum((RwCamera*)((RwGlobals*)RwEngineInst)->curCamera, - &((RpWorldSector*)object)->tightBoundingBox); - RwD3D8SetRenderState(D3DRS_CLIPPING, clip); + _rwD3D8EnableClippingIfNeeded(object, type); int lighting, dither, shademode; int nocolor = 0; diff --git a/src/silenttrails.cpp b/src/silenttrails.cpp new file mode 100644 index 0000000..3d98433 --- /dev/null +++ b/src/silenttrails.cpp @@ -0,0 +1,65 @@ +#include "skygfx.h" + +// stolen from Silent: +// https://github.com/CookiePLMonster/VC-Trails + +struct SMenuEntry +{ + ushort action; + char description[8]; + uchar style; + uchar targetMenu; + ushort posX; + ushort posY; + ushort align; +}; + +static_assert(sizeof(SMenuEntry) == 0x12, "SMenuEntry error!"); + +const SMenuEntry displaySettingsPatch[] = { + /*Trails*/ + { 9, "FED_TRA", 0, 4, 40, 153, 1 }, + /*Subtitles*/ + { 10, "FED_SUB", 0, 4, 40, 178, 1 }, + /*Widescreen*/ + { 11, "FED_WIS", 0, 4, 40, 202, 1 }, + /*Map Legend*/ + { 31, "MAP_LEG", 0, 4, 40, 228, 1 }, + /*Radar Mode*/ + { 32, "FED_RDR", 0, 4, 40, 253, 1 }, + /*HUD Mode*/ + { 33, "FED_HUD", 0, 4, 40, 278, 1 }, + /*Resolution*/ + { 43, "FED_RES", 0, 4, 40, 303, 1 }, + /*Restore Defaults*/ + { 47, "FET_DEF", 0, 4, 320, 328, 3 }, + /*Back*/ + { 34, "FEDS_TB", 0, 33, 320, 353, 3 } + }; + +void +enableTrailsSetting(void) +{ + if(gtaversion == VC_10){ + int pMenuEntries = *(int*)0x4966A0 + 0x3C8; + uchar *pTrailsOptionEnabled = *(unsigned char**)0x498DEE; + + Patch(0x4902D2, pTrailsOptionEnabled); // write setting + Patch(0x48FF97, pTrailsOptionEnabled); // read setting + memcpy((void*)pMenuEntries, displaySettingsPatch, sizeof(displaySettingsPatch)); + }else if(gtaversion == VC_11){ + int pMenuEntries = *(int*)0x4966B0 + 0x3C8; + uchar *pTrailsOptionEnabled = *(unsigned char**)0x498DFE; + + Patch(0x4902E2, pTrailsOptionEnabled); + // TODO: read + memcpy((void*)pMenuEntries, displaySettingsPatch, sizeof(displaySettingsPatch)); + }else if(gtaversion == VC_STEAM){ + int pMenuEntries = *(int*)0x4965B0 + 0x3C8; + uchar *pTrailsOptionEnabled = *(unsigned char**)0x498CFE; + + Patch(0x4901E2, pTrailsOptionEnabled); + // TODO: read + memcpy((void*)pMenuEntries, displaySettingsPatch, sizeof(displaySettingsPatch)); + } +} \ No newline at end of file diff --git a/src/skygfx.h b/src/skygfx.h index 093dfc6..3e72703 100644 --- a/src/skygfx.h +++ b/src/skygfx.h @@ -174,13 +174,17 @@ extern int &MatFXAtomicDataOffset; void drawDualPass(RxD3D8InstanceData *inst); +void _rwD3D8EnableClippingIfNeeded(void *object, RwUInt8 type); + void rxD3D8DefaultRenderCallback(RwResEntry*, void*, RwUInt8, RwUInt32); void rwD3D8AtomicMatFXRenderCallback(RwResEntry*, void*, RwUInt8, RwUInt32); RwBool rwD3D8RenderStateIsVertexAlphaEnable(void); void rwD3D8RenderStateVertexAlphaEnable(RwBool x); RwBool D3D8AtomicDefaultInstanceCallback(void*, RxD3D8InstanceData*, RwBool); +RwBool D3D8AtomicDefaultReinstanceCallback(void*, RwResEntry*, const RpMeshHeader*, RxD3D8AllInOneInstanceCallBack); RwBool D3D8AtomicDefaultInstanceCallback_fixed(void*, RxD3D8InstanceData*, RwBool); +RwBool D3D8AtomicDefaultReinstanceCallback_fixed(void*, RwResEntry*, const RpMeshHeader*, RxD3D8AllInOneInstanceCallBack); void rxD3D8DefaultRenderCallback_d3d9(RwResEntry*, void*, RwUInt8, RwUInt32); RwBool RwD3D8SetSurfaceProperties_d3d9(RwRGBA*, RwSurfaceProperties*, RwUInt32);