diff --git a/src/core/config.h b/src/core/config.h index 6e0a17f7..822cf83f 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -246,6 +246,7 @@ enum Config { #ifdef LIBRW //#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) //#define EXTENDED_PIPELINES // custom render pipelines (includes Neo) +//#define NEW_RENDERER // leeds-like world rendering, needs librw #endif //#define MULTISAMPLING // adds MSAA option TODO diff --git a/src/core/main.cpp b/src/core/main.cpp index 64b3a63f..6560cbda 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -107,6 +107,13 @@ void TheGame(void); void DebugMenuPopulate(void); #endif +#ifdef NEW_RENDERER +bool gbNewRenderer; +#define CLEARMODE (rwCAMERACLEARZ | rwCAMERACLEARSTENCIL) +#else +#define CLEARMODE (rwCAMERACLEARZ) +#endif + void ValidateVersion() { @@ -151,7 +158,7 @@ DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomR CDraw::CalculateAspectRatio(); CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO); CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &TopColor.rwRGBA, rwCAMERACLEARZ); + RwCameraClear(Scene.camera, &TopColor.rwRGBA, CLEARMODE); if(!RsCameraBeginUpdate(Scene.camera)) return false; @@ -170,7 +177,7 @@ DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 CDraw::CalculateAspectRatio(); CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO); CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + RwCameraClear(Scene.camera, &gColourTop, CLEARMODE); if(!RsCameraBeginUpdate(Scene.camera)) return false; @@ -849,9 +856,130 @@ DisplayGameDebugText() } #endif +#ifdef NEW_RENDERER +bool gbRenderRoads = true; +bool gbRenderEverythingBarRoads = true; +bool gbRenderFadingInUnderwaterEntities = true; +bool gbRenderFadingInEntities = true; +bool gbRenderWater = true; +bool gbRenderBoats = true; +bool gbRenderVehicles = true; +bool gbRenderWorld0 = true; +bool gbRenderWorld1 = true; +bool gbRenderWorld2 = true; + +void +MattRenderScene(void) +{ + // this calls CMattRenderer::Render + CWorld::AdvanceCurrentScanCode(); + // CMattRenderer::ResetRenderStates + CRenderer::ClearForFrame(); + // CClock::CalcEnvMapTimeMultiplicator + CWaterLevel::RenderWater(); // actually CMattRenderer::RenderWater + // CClock::ms_EnvMapTimeMultiplicator = 1.0f; + // cWorldStream::ClearDynamics + CRenderer::ConstructRenderList(); +if(gbRenderWorld0) + CRenderer::RenderWorld(0); // roads + // CMattRenderer::ResetRenderStates + CRenderer::PreRender(); + CCoronas::RenderReflections(); +if(gbRenderWorld1) + CRenderer::RenderWorld(1); // opaque +if(gbRenderRoads) + CRenderer::RenderRoads(); + + // not sure where to put these since LCS has no underwater entities +if(gbRenderBoats) + CRenderer::RenderBoats(); +if(gbRenderFadingInUnderwaterEntities) + CRenderer::RenderFadingInUnderwaterEntities(); +if(gbRenderWater) + CRenderer::RenderTransparentWater(); + +if(gbRenderEverythingBarRoads) + CRenderer::RenderEverythingBarRoads(); + // get env map here? + // moved this: + // CRenderer::RenderFadingInEntities(); +} + +void +RenderScene_new(void) +{ + CClouds::Render(); + DoRWRenderHorizon(); + + MattRenderScene(); + DefinedState(); + // CMattRenderer::ResetRenderStates + // moved CRenderer::RenderBoats to before transparent water +} + +// TODO +bool FredIsInFirstPersonCam(void) { return true; } // this seems to give the best result in all cases + +void +RenderEffects_new(void) +{ + CRenderer::RenderPeds(); + + CShadows::RenderStaticShadows(); + // CRenderer::GenerateEnvironmentMap + CShadows::RenderStoredShadows(); + CSkidmarks::Render(); + CRubbish::Render(); + + // these aren't really effects + DefinedState(); + if(FredIsInFirstPersonCam()){ + DefinedState(); + C3dMarkers::Render(); // normally rendered in CSpecialFX::Render() +if(gbRenderWorld2) + CRenderer::RenderWorld(2); // transparent +if(gbRenderVehicles) + CRenderer::RenderVehicles(); + }else{ +if(gbRenderVehicles) + CRenderer::RenderVehicles(); +if(gbRenderWorld2) + CRenderer::RenderWorld(2); // transparent + } + // better render these after transparent world +if(gbRenderFadingInEntities) + CRenderer::RenderFadingInEntities(); + + // actual effects here + CGlass::Render(); + // CMattRenderer::ResetRenderStates + DefinedState(); + CCoronas::RenderSunReflection(); + CWeather::RenderRainStreaks(); + // CWeather::AddSnow + CWaterCannons::Render(); + CAntennas::Render(); + CSpecialFX::Render(); + CRopes::Render(); + CCoronas::Render(); + CParticle::Render(); + CPacManPickups::Render(); + CWeaponEffects::Render(); + CPointLights::RenderFogEffect(); + CMovingThings::Render(); + CRenderer::RenderFirstPersonVehicle(); +} +#endif + void RenderScene(void) { +#ifdef NEW_RENDERER + if(gbNewRenderer){ + RenderScene_new(); + return; + } +#endif CClouds::Render(); DoRWRenderHorizon(); CRenderer::RenderRoads(); @@ -885,6 +1013,12 @@ RenderDebugShit(void) void RenderEffects(void) { +#ifdef NEW_RENDERER + if(gbNewRenderer){ + RenderEffects_new(); + return; + } +#endif CGlass::Render(); CWaterCannons::Render(); CSpecialFX::Render(); @@ -1061,6 +1195,10 @@ Idle(void *arg) pos.y = SCREEN_HEIGHT / 2.0f; RsMouseSetPos(&pos); #endif +#ifdef NEW_RENDERER + if(!gbNewRenderer) +#endif +{ tbStartTimer(0, "CnstrRenderList"); #ifdef PC_WATER CWaterLevel::PreCalcWaterGeometry(); @@ -1071,6 +1209,7 @@ Idle(void *arg) tbStartTimer(0, "PreRender"); CRenderer::PreRender(); tbEndTimer("PreRender"); +} #ifdef FIX_BUGS RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE); // TODO: temp? this fixes OpenGL render but there should be a better place for this @@ -1125,7 +1264,7 @@ Idle(void *arg) CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, DEFAULT_ASPECT_RATIO); #endif CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + RwCameraClear(Scene.camera, &gColourTop, CLEARMODE); if(!RsCameraBeginUpdate(Scene.camera)) return; } @@ -1174,7 +1313,7 @@ FrontendIdle(void) CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO); CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + RwCameraClear(Scene.camera, &gColourTop, CLEARMODE); if(!RsCameraBeginUpdate(Scene.camera)) return; @@ -1450,7 +1589,7 @@ void TheGame(void) { CameraSize(Scene.camera, NULL, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO); CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + RwCameraClear(Scene.camera, &gColourTop, CLEARMODE); if (!RsCameraBeginUpdate(Scene.camera)) break; } diff --git a/src/core/main.h b/src/core/main.h index 8bf06c30..f428224e 100644 --- a/src/core/main.h +++ b/src/core/main.h @@ -38,3 +38,8 @@ void ResetLoadingScreenBar(void); #ifndef MASTER void TheModelViewer(void); #endif + +#ifdef NEW_RENDERER +extern bool gbNewRenderer; +bool FredIsInFirstPersonCam(void); +#endif diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 318b1d47..ebfa8de5 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -422,6 +422,30 @@ DebugMenuPopulate(void) DebugMenuAddVarBool8("Render", "Frame limiter", &FrontEndMenuManager.m_PrefsFrameLimiter, nil); DebugMenuAddVarBool8("Render", "VSynch", &FrontEndMenuManager.m_PrefsVsync, nil); DebugMenuAddVar("Render", "Max FPS", &RsGlobal.maxFPS, nil, 1, 1, 1000, nil); +#ifdef NEW_RENDERER + DebugMenuAddVarBool8("Render", "new renderer", &gbNewRenderer, nil); +extern bool gbRenderRoads; +extern bool gbRenderEverythingBarRoads; +extern bool gbRenderFadingInUnderwaterEntities; +extern bool gbRenderFadingInEntities; +extern bool gbRenderWater; +extern bool gbRenderBoats; +extern bool gbRenderVehicles; +extern bool gbRenderWorld0; +extern bool gbRenderWorld1; +extern bool gbRenderWorld2; + DebugMenuAddVarBool8("Render", "gbRenderRoads", &gbRenderRoads, nil); + DebugMenuAddVarBool8("Render", "gbRenderEverythingBarRoads", &gbRenderEverythingBarRoads, nil); + DebugMenuAddVarBool8("Render", "gbRenderFadingInUnderwaterEntities", &gbRenderFadingInUnderwaterEntities, nil); + DebugMenuAddVarBool8("Render", "gbRenderFadingInEntities", &gbRenderFadingInEntities, nil); + DebugMenuAddVarBool8("Render", "gbRenderWater", &gbRenderWater, nil); + DebugMenuAddVarBool8("Render", "gbRenderBoats", &gbRenderBoats, nil); + DebugMenuAddVarBool8("Render", "gbRenderVehicles", &gbRenderVehicles, nil); + DebugMenuAddVarBool8("Render", "gbRenderWorld0", &gbRenderWorld0, nil); + DebugMenuAddVarBool8("Render", "gbRenderWorld1", &gbRenderWorld1, nil); + DebugMenuAddVarBool8("Render", "gbRenderWorld2", &gbRenderWorld2, nil); +#endif + #ifdef EXTENDED_COLOURFILTER static const char *filternames[] = { "None", "Simple", "Normal", "Mobile" }; e = DebugMenuAddVar("Render", "Colourfilter", &CPostFX::EffectSwitch, nil, 1, CPostFX::POSTFX_OFF, CPostFX::POSTFX_MOBILE, filternames); diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index 58b3277a..f37e5813 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -294,32 +294,13 @@ RwTextureAddressMode RwTextureGetAddressingV(const RwTexture *texture); // TODO void _rwD3D8TexDictionaryEnableRasterFormatConversion(bool enable) { } -static rw::Raster* -ConvertTexRaster(rw::Raster *ras) -{ - using namespace rw; - - if(ras->platform == rw::platform) - return ras; - // compatible platforms - if(ras->platform == PLATFORM_D3D8 && rw::platform == PLATFORM_D3D9 || - ras->platform == PLATFORM_D3D9 && rw::platform == PLATFORM_D3D8) - return ras; - - Image *img = ras->toImage(); - ras->destroy(); - img->unpalettize(); - ras = Raster::createFromImage(img); - img->destroy(); - return ras; -} // hack for reading native textures RwBool rwNativeTextureHackRead(RwStream *stream, RwTexture **tex, RwInt32 size) { *tex = Texture::streamReadNative(stream); #ifdef LIBRW - (*tex)->raster = ConvertTexRaster((*tex)->raster); + (*tex)->raster = rw::Raster::convertTexToCurrentPlatform((*tex)->raster); #endif return *tex != nil; } @@ -796,6 +777,9 @@ RwBool RpWorldPluginAttach(void) { registerNativeDataPlugin(); registerAtomicRightsPlugin(); registerMaterialRightsPlugin(); + + // not sure if this goes here + rw::xbox::registerVertexFormatPlugin(); return true; } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 3b996b55..c2982d6d 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,3 +1,4 @@ +#define WITH_D3D #include "common.h" #include "main.h" @@ -6,6 +7,7 @@ #include "Treadable.h" #include "Ped.h" #include "Vehicle.h" +#include "Boat.h" #include "Heli.h" #include "Bike.h" #include "Object.h" @@ -47,12 +49,27 @@ int32 CRenderer::ms_nNoOfVisibleEntities; CEntity *CRenderer::ms_aVisibleEntityPtrs[NUMVISIBLEENTITIES]; CEntity *CRenderer::ms_aInVisibleEntityPtrs[NUMINVISIBLEENTITIES]; int32 CRenderer::ms_nNoOfInVisibleEntities; +#ifdef NEW_RENDERER +int32 CRenderer::ms_nNoOfVisibleVehicles; +CEntity *CRenderer::ms_aVisibleVehiclePtrs[NUMVISIBLEENTITIES]; +int32 CRenderer::ms_nNoOfVisibleBuildings; +CEntity *CRenderer::ms_aVisibleBuildingPtrs[NUMVISIBLEENTITIES]; +#endif CVector CRenderer::ms_vecCameraPosition; CVehicle *CRenderer::m_pFirstPersonVehicle; bool CRenderer::m_loadingPriority; float CRenderer::ms_lodDistScale = 1.2f; +#ifdef FIX_BUGS +#define LOD_DISTANCE (300.0f*TheCamera.LODDistMultiplier) +#else +#define LOD_DISTANCE 300.0f +#endif +#define FADE_DISTANCE 20.0f +#define STREAM_DISTANCE 30.0f + + void CRenderer::Init(void) { @@ -75,6 +92,20 @@ CRenderer::PreRender(void) for(i = 0; i < ms_nNoOfVisibleEntities; i++) ms_aVisibleEntityPtrs[i]->PreRender(); +#ifdef NEW_RENDERER + if(gbNewRenderer){ + for(i = 0; i < ms_nNoOfVisibleVehicles; i++) + ms_aVisibleVehiclePtrs[i]->PreRender(); + // How is this done with cWorldStream? + for(i = 0; i < ms_nNoOfVisibleBuildings; i++) + ms_aVisibleBuildingPtrs[i]->PreRender(); + for(node = CVisibilityPlugins::m_alphaBuildingList.head.next; + node != &CVisibilityPlugins::m_alphaBuildingList.tail; + node = node->next) + ((CEntity*)node->item.entity)->PreRender(); + } +#endif + for (i = 0; i < ms_nNoOfInVisibleEntities; i++) { #ifdef SQUEEZE_PERFORMANCE if (ms_aInVisibleEntityPtrs[i]->IsVehicle() && ((CVehicle*)ms_aInVisibleEntityPtrs[i])->IsHeli()) @@ -230,7 +261,6 @@ CRenderer::RenderEverythingBarRoads(void) { int i; CEntity *e; - CVector dist; EntityInfo ei; RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE); @@ -253,12 +283,10 @@ CRenderer::RenderEverythingBarRoads(void) e->IsPed() && CVisibilityPlugins::GetClumpAlpha((RpClump*)e->m_rwObject) != 255){ if(e->IsVehicle() && PutIntoSortedVehicleList((CVehicle*)e)){ ei.ent = e; - dist = ms_vecCameraPosition - e->GetPosition(); - ei.sort = dist.MagnitudeSqr(); + ei.sort = (ms_vecCameraPosition - e->GetPosition()).MagnitudeSqr(); gSortedVehiclesAndPeds.InsertSorted(ei); }else{ - dist = ms_vecCameraPosition - e->GetPosition(); - if(!CVisibilityPlugins::InsertEntityIntoSortedList(e, dist.Magnitude())){ + if(!CVisibilityPlugins::InsertEntityIntoSortedList(e, (ms_vecCameraPosition - e->GetPosition()).Magnitude())){ printf("Ran out of space in alpha entity list"); RenderOneNonRoad(e); } @@ -277,6 +305,24 @@ CRenderer::RenderBoats(void) RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); SetCullMode(rwCULLMODECULLBACK); +#ifdef NEW_RENDERER + int i; + CEntity *e; + EntityInfo ei; + if(gbNewRenderer){ + gSortedVehiclesAndPeds.Clear(); + // not the real thing + for(i = 0; i < ms_nNoOfVisibleVehicles; i++){ + e = ms_aVisibleVehiclePtrs[i]; + if(e->IsVehicle() && PutIntoSortedVehicleList((CVehicle*)e)){ + ei.ent = e; + ei.sort = (ms_vecCameraPosition - e->GetPosition()).MagnitudeSqr(); + gSortedVehiclesAndPeds.InsertSorted(ei); + } + } + } +#endif + for(node = gSortedVehiclesAndPeds.tail.prev; node != &gSortedVehiclesAndPeds.head; node = node->prev){ @@ -285,6 +331,573 @@ CRenderer::RenderBoats(void) } } +#ifdef NEW_RENDERER +#ifndef LIBRW +#error "Need librw for EXTENDED_PIPELINES" +#endif +#include "WaterLevel.h" + +enum { + // blend passes + PASS_NOZ, // no z-write + PASS_ADD, // additive + PASS_BLEND // normal blend +}; + +static RwRGBAReal black; + +#ifdef RW_D3D9 +struct BuildingInst +{ + rw::RawMatrix combinedMat; + rw::d3d9::InstanceDataHeader *instHeader; + uint8 fadeAlpha; + bool lighting; +}; +static BuildingInst blendInsts[3][2000]; +static int numBlendInsts[3]; + +static void +SetStencilState(int state) +{ + switch(state){ + // disable stencil + case 0: + rw::d3d::setRenderState(D3DRS_STENCILENABLE, FALSE); + break; + // test against stencil + case 1: + rw::d3d::setRenderState(D3DRS_STENCILENABLE, TRUE); + rw::d3d::setRenderState(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL); + rw::d3d::setRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + rw::d3d::setRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + rw::d3d::setRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); + rw::d3d::setRenderState(D3DRS_STENCILMASK, 0xFF); + rw::d3d::setRenderState(D3DRS_STENCILREF, 0xFF); + break; + // write to stencil + case 2: + rw::d3d::setRenderState(D3DRS_STENCILENABLE, TRUE); + rw::d3d::setRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + rw::d3d::setRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + rw::d3d::setRenderState(D3DRS_STENCILREF, 0xFF); + break; + } +} + +static void +SetMatrix(BuildingInst *building, rw::Matrix *worldMat) +{ + using namespace rw; + RawMatrix world, worldview; + Camera *cam = engine->currentCamera; + convMatrix(&world, worldMat); + RawMatrix::mult(&worldview, &world, &cam->devView); + RawMatrix::mult(&building->combinedMat, &worldview, &cam->devProj); +} + +static bool +IsTextureTransparent(RwTexture *tex) +{ + if(tex == nil || tex->raster == nil) + return false; + return PLUGINOFFSET(rw::d3d::D3dRaster, tex->raster, rw::d3d::nativeRasterOffset)->hasAlpha; +} + +// Render all opaque meshes and put atomics that needs blending +// into the deferred list. +static void +AtomicFirstPass(RpAtomic *atomic, int pass) +{ + using namespace rw; + using namespace rw::d3d; + using namespace rw::d3d9; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (d3d9::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_D3D9); + building->fadeAlpha = 255; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + + bool setupDone = false; + bool defer = false; + SetMatrix(building, atomic->getFrame()->getLTM()); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 i = 0; i < building->instHeader->numMeshes; i++, inst++){ + Material *m = inst->material; + + if(inst->vertexAlpha || m->color.alpha != 255 || + IsTextureTransparent(m->texture)){ + defer = true; + continue; + } + + // alright we're rendering this atomic + if(!setupDone){ + setStreamSource(0, building->instHeader->vertexStream[0].vertexBuffer, 0, building->instHeader->vertexStream[0].stride); + setIndices(building->instHeader->indexBuffer); + setVertexDeclaration(building->instHeader->vertexDeclaration); + setVertexShader(default_amb_VS); + d3ddevice->SetVertexShaderConstantF(VSLOC_combined, (float*)&building->combinedMat, 4); + if(building->lighting) + setAmbient(pAmbient->color); + else + setAmbient(black); + setupDone = true; + } + + setMaterial(m->color, m->surfaceProps); + + if(m->texture){ + d3d::setTexture(0, m->texture); + setPixelShader(default_tex_PS); + }else + setPixelShader(default_PS); + + drawInst(building->instHeader, inst); + } + if(defer) + numBlendInsts[pass]++; +} + +static void +AtomicFullyTransparent(RpAtomic *atomic, int pass, int fadeAlpha) +{ + using namespace rw; + using namespace rw::d3d; + using namespace rw::d3d9; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (d3d9::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_D3D9); + building->fadeAlpha = fadeAlpha; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + SetMatrix(building, atomic->getFrame()->getLTM()); + numBlendInsts[pass]++; +} + +static void +RenderBlendPass(int pass) +{ + using namespace rw; + using namespace rw::d3d; + using namespace rw::d3d9; + + setVertexShader(default_amb_VS); + + int i; + for(i = 0; i < numBlendInsts[pass]; i++){ + BuildingInst *building = &blendInsts[pass][i]; + + setStreamSource(0, building->instHeader->vertexStream[0].vertexBuffer, 0, building->instHeader->vertexStream[0].stride); + setIndices(building->instHeader->indexBuffer); + setVertexDeclaration(building->instHeader->vertexDeclaration); + d3ddevice->SetVertexShaderConstantF(VSLOC_combined, (float*)&building->combinedMat, 4); + if(building->lighting) + setAmbient(pAmbient->color); + else + setAmbient(black); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 j = 0; j < building->instHeader->numMeshes; j++, inst++){ + Material *m = inst->material; + if(!inst->vertexAlpha && m->color.alpha == 255 && !IsTextureTransparent(m->texture) && building->fadeAlpha == 255) + continue; // already done this one + + rw::RGBA color = m->color; + color.alpha = (color.alpha * building->fadeAlpha)/255; + setMaterial(color, m->surfaceProps); + + if(m->texture){ + d3d::setTexture(0, m->texture); + setPixelShader(default_tex_PS); + }else + setPixelShader(default_PS); + + drawInst(building->instHeader, inst); + } + } +} +#endif +#ifdef RW_GL3 +struct BuildingInst +{ + rw::Matrix matrix; + rw::gl3::InstanceDataHeader *instHeader; + uint8 fadeAlpha; + bool lighting; +}; +static BuildingInst blendInsts[3][2000]; +static int numBlendInsts[3]; + +static void +SetStencilState(int state) +{ + switch(state){ + // disable stencil + case 0: + glDisable(GL_STENCIL_TEST); + break; + // test against stencil + case 1: + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_NOTEQUAL, 0xFF, 0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilMask(0xFF); + break; + // write to stencil + case 2: + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 0xFF, 0xFF); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + break; + } +} + +static bool +IsTextureTransparent(RwTexture *tex) +{ + if(tex == nil || tex->raster == nil) + return false; + return PLUGINOFFSET(rw::gl3::Gl3Raster, tex->raster, rw::gl3::nativeRasterOffset)->hasAlpha; +} + +// Render all opaque meshes and put atomics that needs blending +// into the deferred list. +static void +AtomicFirstPass(RpAtomic *atomic, int pass) +{ + using namespace rw; + using namespace rw::gl3; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (gl3::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_GL3); + building->fadeAlpha = 255; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + + WorldLights lights; + lights.numAmbients = 1; + lights.numDirectionals = 0; + lights.numLocals = 0; + if(building->lighting) + lights.ambient = pAmbient->color; + else + lights.ambient = black; + + bool setupDone = false; + bool defer = false; + building->matrix = *atomic->getFrame()->getLTM(); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 i = 0; i < building->instHeader->numMeshes; i++, inst++){ + Material *m = inst->material; + + if(inst->vertexAlpha || m->color.alpha != 255 || + IsTextureTransparent(m->texture)){ + defer = true; + continue; + } + + // alright we're rendering this atomic + if(!setupDone){ + defaultShader->use(); + setWorldMatrix(&building->matrix); +#ifdef RW_GL_USE_VAOS + glBindVertexArray(building->instHeader->vao); +#else + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, building->instHeader->ibo); + glBindBuffer(GL_ARRAY_BUFFER, building->instHeader->vbo); + setAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + setLights(&lights); + setupDone = true; + } + + setMaterial(m->color, m->surfaceProps); + + setTexture(0, m->texture); + + drawInst(building->instHeader, inst); + } +#ifndef RW_GL_USE_VAOS + disableAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + if(defer) + numBlendInsts[pass]++; +} + +static void +AtomicFullyTransparent(RpAtomic *atomic, int pass, int fadeAlpha) +{ + using namespace rw; + using namespace rw::gl3; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (gl3::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_GL3); + building->fadeAlpha = fadeAlpha; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + building->matrix = *atomic->getFrame()->getLTM(); + numBlendInsts[pass]++; +} + +static void +RenderBlendPass(int pass) +{ + using namespace rw; + using namespace rw::gl3; + + defaultShader->use(); + WorldLights lights; + lights.numAmbients = 1; + lights.numDirectionals = 0; + lights.numLocals = 0; + + int i; + for(i = 0; i < numBlendInsts[pass]; i++){ + BuildingInst *building = &blendInsts[pass][i]; + +#ifdef RW_GL_USE_VAOS + glBindVertexArray(building->instHeader->vao); +#else + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, building->instHeader->ibo); + glBindBuffer(GL_ARRAY_BUFFER, building->instHeader->vbo); + setAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + setWorldMatrix(&building->matrix); + if(building->lighting) + lights.ambient = pAmbient->color; + else + lights.ambient = black; + setLights(&lights); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 j = 0; j < building->instHeader->numMeshes; j++, inst++){ + Material *m = inst->material; + if(!inst->vertexAlpha && m->color.alpha == 255 && !IsTextureTransparent(m->texture) && building->fadeAlpha == 255) + continue; // already done this one + + rw::RGBA color = m->color; + color.alpha = (color.alpha * building->fadeAlpha)/255; + setMaterial(color, m->surfaceProps); + + setTexture(0, m->texture); + + drawInst(building->instHeader, inst); + } +#ifndef RW_GL_USE_VAOS + disableAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + } +} +#endif + +void +CRenderer::RenderOneBuilding(CEntity *ent, float camdist) +{ + if(ent->m_rwObject == nil) + return; + assert(RwObjectGetType(ent->m_rwObject) == rpATOMIC); + RpAtomic *atomic = (RpAtomic*)ent->m_rwObject; + CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(ent->GetModelIndex()); + + ent->bImBeingRendered = true; // TODO: this seems wrong, but do we even need it? + + int pass = PASS_BLEND; + if(mi->m_additive) // very questionable + pass = PASS_ADD; + if(mi->m_noZwrite) + pass = PASS_NOZ; + + if(ent->bDistanceFade){ + RpAtomic *lodatm; + float fadefactor; + uint32 alpha; + + lodatm = mi->GetAtomicFromDistance(camdist - FADE_DISTANCE); + fadefactor = (mi->GetLargestLodDistance() - (camdist - FADE_DISTANCE))/FADE_DISTANCE; + if(fadefactor > 1.0f) + fadefactor = 1.0f; + alpha = mi->m_alpha * fadefactor; + + if(alpha == 255) + AtomicFirstPass(atomic, pass); + else{ + // not quite sure what this is about, do we have to do that? + RpGeometry *geo = RpAtomicGetGeometry(lodatm); + if(geo != RpAtomicGetGeometry(atomic)) + RpAtomicSetGeometry(atomic, geo, rpATOMICSAMEBOUNDINGSPHERE); + AtomicFullyTransparent(atomic, pass, alpha); + } + }else + AtomicFirstPass(atomic, pass); + + ent->bImBeingRendered = false; // TODO: this seems wrong, but do we even need it? +} + +void +CRenderer::RenderWorld(int pass) +{ + int i; + CEntity *e; + CLink *node; + + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE); + SetCullMode(rwCULLMODECULLBACK); + DeActivateDirectional(); + SetAmbientColours(); + + // Temporary...have to figure out sorting better + switch(pass){ + case 0: + // Roads + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + for(i = 0; i < ms_nNoOfVisibleBuildings; i++){ + e = ms_aVisibleBuildingPtrs[i]; + if(e->bIsBIGBuilding || IsRoad(e)) + RenderOneBuilding(e); + } + for(node = CVisibilityPlugins::m_alphaBuildingList.tail.prev; + node != &CVisibilityPlugins::m_alphaBuildingList.head; + node = node->prev){ + e = node->item.entity; + if(e->bIsBIGBuilding || IsRoad(e)) + RenderOneBuilding(e, node->item.sort); + } + break; + case 1: + // Opaque + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + for(i = 0; i < ms_nNoOfVisibleBuildings; i++){ + e = ms_aVisibleBuildingPtrs[i]; + if(!(e->bIsBIGBuilding || IsRoad(e))) + RenderOneBuilding(e); + } + for(node = CVisibilityPlugins::m_alphaBuildingList.tail.prev; + node != &CVisibilityPlugins::m_alphaBuildingList.head; + node = node->prev){ + e = node->item.entity; + if(!(e->bIsBIGBuilding || IsRoad(e))) + RenderOneBuilding(e, node->item.sort); + } + // Now we have iterated through all visible buildings (unsorted and sorted) + // and the transparency list is done. + + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE); + RenderBlendPass(PASS_NOZ); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + break; + case 2: + // Transparent + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RenderBlendPass(PASS_ADD); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RenderBlendPass(PASS_BLEND); + break; + } +} + +void +CRenderer::RenderPeds(void) +{ + int i; + CEntity *e; + + for(i = 0; i < ms_nNoOfVisibleVehicles; i++){ + e = ms_aVisibleVehiclePtrs[i]; + if(e->IsPed()) + RenderOneNonRoad(e); + } +} + +void +CRenderer::RenderVehicles(void) +{ + int i; + CEntity *e; + EntityInfo ei; + CLink *node; + + // not the real thing + for(i = 0; i < ms_nNoOfVisibleVehicles; i++){ + e = ms_aVisibleVehiclePtrs[i]; + if(!e->IsVehicle()) + continue; + if(PutIntoSortedVehicleList((CVehicle*)e)) + continue; // boats handled elsewhere + ei.ent = e; + ei.sort = (ms_vecCameraPosition - e->GetPosition()).MagnitudeSqr(); + gSortedVehiclesAndPeds.InsertSorted(ei); + } + + for(node = gSortedVehiclesAndPeds.tail.prev; + node != &gSortedVehiclesAndPeds.head; + node = node->prev) + RenderOneNonRoad(node->item.ent); +} + +void +CRenderer::RenderTransparentWater(void) +{ + int i; + CEntity *e; + + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDZERO); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + SetStencilState(2); + + for(i = 0; i < ms_nNoOfVisibleVehicles; i++){ + e = ms_aVisibleVehiclePtrs[i]; + if(e->IsVehicle() && ((CVehicle*)e)->IsBoat()) + ((CBoat*)e)->RenderWaterOutPolys(); + } + + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + SetStencilState(1); + + CWaterLevel::RenderTransparentWater(); + + SetStencilState(0); +} + +void +CRenderer::ClearForFrame(void) +{ + ms_nNoOfVisibleEntities = 0; + ms_nNoOfVisibleVehicles = 0; + ms_nNoOfVisibleBuildings = 0; + ms_nNoOfInVisibleEntities = 0; + gSortedVehiclesAndPeds.Clear(); + + numBlendInsts[PASS_NOZ] = 0; + numBlendInsts[PASS_ADD] = 0; + numBlendInsts[PASS_BLEND] = 0; +} +#endif + void CRenderer::RenderFadingInEntities(void) { @@ -327,14 +940,6 @@ enum Visbility VIS_STREAMME }; -#ifdef FIX_BUGS -#define LOD_DISTANCE (300.0f*TheCamera.LODDistMultiplier) -#else -#define LOD_DISTANCE 300.0f -#endif -#define FADE_DISTANCE 20.0f -#define STREAM_DISTANCE 30.0f - // Time Objects can be time culled if // other == -1 || CModelInfo::GetModelInfo(other)->GetRwObject() // i.e. we have to draw even at the wrong time if @@ -640,9 +1245,13 @@ void CRenderer::ConstructRenderList(void) { COcclusion::ProcessBeforeRendering(); - +#ifdef NEW_RENDERER + if(!gbNewRenderer) +#endif +{ ms_nNoOfVisibleEntities = 0; ms_nNoOfInVisibleEntities = 0; +} ms_vecCameraPosition = TheCamera.GetPosition(); // TODO: blocked ranges, but unused ScanWorld(); @@ -1041,6 +1650,20 @@ CRenderer::ScanSectorPoly(RwV2d *poly, int32 numVertices, void (*scanfunc)(CPtrL } } +void +CRenderer::InsertEntityIntoList(CEntity *ent) +{ +#ifdef NEW_RENDERER + // TODO: there are more flags being checked here + if(gbNewRenderer && (ent->IsVehicle() || ent->IsPed())) + ms_aVisibleVehiclePtrs[ms_nNoOfVisibleVehicles++] = ent; + else if(gbNewRenderer && ent->IsBuilding()) + ms_aVisibleBuildingPtrs[ms_nNoOfVisibleBuildings++] = ent; + else +#endif + ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; +} + void CRenderer::ScanBigBuildingList(CPtrList &list) { @@ -1058,7 +1681,7 @@ CRenderer::ScanBigBuildingList(CPtrList &list) vis = VIS_VISIBLE; switch(vis){ case VIS_VISIBLE: - ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; + InsertEntityIntoList(ent); ent->bOffscreen = false; break; case VIS_STREAMME: @@ -1089,7 +1712,7 @@ CRenderer::ScanSectorList(CPtrList *lists) switch(SetupEntityVisibility(ent)){ case VIS_VISIBLE: - ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; + InsertEntityIntoList(ent); break; case VIS_INVISIBLE: if(!IsGlass(ent->GetModelIndex())) @@ -1134,7 +1757,7 @@ CRenderer::ScanSectorList_Priority(CPtrList *lists) switch(SetupEntityVisibility(ent)){ case VIS_VISIBLE: - ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; + InsertEntityIntoList(ent); break; case VIS_INVISIBLE: if(!IsGlass(ent->GetModelIndex())) @@ -1181,7 +1804,7 @@ CRenderer::ScanSectorList_Subway(CPtrList *lists) ent->bOffscreen = false; switch(SetupEntityVisibility(ent)){ case VIS_VISIBLE: - ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; + InsertEntityIntoList(ent); break; case VIS_OFFSCREEN: ent->bOffscreen = true; diff --git a/src/render/Renderer.h b/src/render/Renderer.h index e9f82078..b579bb4c 100644 --- a/src/render/Renderer.h +++ b/src/render/Renderer.h @@ -21,6 +21,13 @@ class CRenderer static CEntity *ms_aVisibleEntityPtrs[NUMVISIBLEENTITIES]; static int32 ms_nNoOfInVisibleEntities; static CEntity *ms_aInVisibleEntityPtrs[NUMINVISIBLEENTITIES]; +#ifdef NEW_RENDERER + static int32 ms_nNoOfVisibleVehicles; + static CEntity *ms_aVisibleVehiclePtrs[NUMVISIBLEENTITIES]; + // for cWorldStream emulation + static int32 ms_nNoOfVisibleBuildings; + static CEntity *ms_aVisibleBuildingPtrs[NUMVISIBLEENTITIES]; +#endif static CVector ms_vecCameraPosition; static CVehicle *m_pFirstPersonVehicle; @@ -63,4 +70,15 @@ public: static bool ShouldModelBeStreamed(CEntity *ent, const CVector &campos); static void RemoveVehiclePedLights(CEntity *ent, bool reset); + + +#ifdef NEW_RENDERER + static void ClearForFrame(void); + static void RenderPeds(void); + static void RenderVehicles(void); // also renders peds in LCS + static void RenderOneBuilding(CEntity *ent, float camdist = 0.0f); + static void RenderWorld(int pass); // like cWorldStream::Render(int) + static void RenderTransparentWater(void); // keep-out polys and transparent water +#endif + static void InsertEntityIntoList(CEntity *ent); }; diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp index 655fdb40..665a41ab 100644 --- a/src/render/SpecialFX.cpp +++ b/src/render/SpecialFX.cpp @@ -169,6 +169,9 @@ CSpecialFX::Render(void) CBrightLights::Render(); CShinyTexts::Render(); CMoneyMessages::Render(); +#ifdef NEW_RENDERER + if(!(gbNewRenderer && FredIsInFirstPersonCam())) +#endif C3dMarkers::Render(); } diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp index 36a60117..c79cb52b 100644 --- a/src/rw/VisibilityPlugins.cpp +++ b/src/rw/VisibilityPlugins.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "templates.h" +#include "main.h" #include "Entity.h" #include "ModelInfo.h" #include "Lights.h" @@ -19,6 +20,9 @@ CLinkList CVisibilityPlugins::m_alphaList; CLinkList CVisibilityPlugins::m_alphaBoatAtomicList; CLinkList CVisibilityPlugins::m_alphaEntityList; CLinkList CVisibilityPlugins::m_alphaUnderwaterEntityList; +#ifdef NEW_RENDERER +CLinkList CVisibilityPlugins::m_alphaBuildingList; +#endif int32 CVisibilityPlugins::ms_atomicPluginOffset = -1; int32 CVisibilityPlugins::ms_framePluginOffset = -1; @@ -59,6 +63,11 @@ CVisibilityPlugins::Initialise(void) m_alphaUnderwaterEntityList.head.item.sort = 0.0f; m_alphaUnderwaterEntityList.tail.item.sort = 100000000.0f; +#ifdef NEW_RENDERER + m_alphaBuildingList.Init(NUMALPHAENTITYLIST); + m_alphaBuildingList.head.item.sort = 0.0f; + m_alphaBuildingList.tail.item.sort = 100000000.0f; +#endif } void @@ -68,6 +77,9 @@ CVisibilityPlugins::Shutdown(void) m_alphaBoatAtomicList.Shutdown(); m_alphaEntityList.Shutdown(); m_alphaUnderwaterEntityList.Shutdown(); +#ifdef NEW_RENDERER + m_alphaBuildingList.Shutdown(); +#endif } void @@ -76,6 +88,9 @@ CVisibilityPlugins::InitAlphaEntityList(void) m_alphaEntityList.Clear(); m_alphaBoatAtomicList.Clear(); m_alphaUnderwaterEntityList.Clear(); +#ifdef NEW_RENDERER + m_alphaBuildingList.Clear(); +#endif } bool @@ -84,6 +99,10 @@ CVisibilityPlugins::InsertEntityIntoSortedList(CEntity *e, float dist) AlphaObjectInfo item; item.entity = e; item.sort = dist; +#ifdef NEW_RENDERER + if(gbNewRenderer && e->IsBuilding()) + return !!m_alphaBuildingList.InsertSorted(item); +#endif if(e->bUnderwater && m_alphaUnderwaterEntityList.InsertSorted(item)) return true; return !!m_alphaEntityList.InsertSorted(item); @@ -308,7 +327,7 @@ CVisibilityPlugins::RenderFadingAtomic(RpAtomic *atomic, float camdist) mi = GetAtomicModelInfo(atomic); lodatm = mi->GetAtomicFromDistance(camdist - FADE_DISTANCE); if(mi->m_additive) - AtomicDefaultRenderCallBack(atomic); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); fadefactor = (mi->GetLargestLodDistance() - (camdist - FADE_DISTANCE))/FADE_DISTANCE; if(fadefactor > 1.0f) diff --git a/src/rw/VisibilityPlugins.h b/src/rw/VisibilityPlugins.h index f277565d..03833c9c 100644 --- a/src/rw/VisibilityPlugins.h +++ b/src/rw/VisibilityPlugins.h @@ -24,6 +24,9 @@ public: static CLinkList m_alphaBoatAtomicList; static CLinkList m_alphaEntityList; static CLinkList m_alphaUnderwaterEntityList; +#ifdef NEW_RENDERER + static CLinkList m_alphaBuildingList; +#endif static RwCamera *ms_pCamera; static RwV3d *ms_pCameraPosn; static float ms_cullCompsDist; diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index 239cb9a1..7fea8c6e 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -1,5 +1,6 @@ #include "common.h" +#include "main.h" #include "General.h" #include "Timecycle.h" #include "Weather.h" @@ -1100,6 +1101,15 @@ CBoat::Render() m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 3000; if (!CVehicle::bWheelsOnlyCheat) CEntity::Render(); +#ifdef NEW_RENDERER + if(!gbNewRenderer) +#endif + RenderWaterOutPolys(); // not separate function in VC +} + +void +CBoat::RenderWaterOutPolys(void) +{ if(GetModelIndex() == MI_SKIMMER) return; KeepWaterOutIndices[0] = 0; @@ -1178,11 +1188,16 @@ CBoat::Render() KeepWaterOutVertices[2].v = 1.0f; KeepWaterOutVertices[3].u = 1.0f; KeepWaterOutVertices[3].v = 1.0f; +#ifdef NEW_RENDERER + if(!gbNewRenderer) +#endif +{ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpWaterRaster); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDZERO); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); +} if (!CVehicle::bWheelsOnlyCheat && RwIm3DTransform(KeepWaterOutVertices, 4, GetMatrix().m_attachment, rwIM3D_VERTEXUV)) { RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, KeepWaterOutIndices, 6); RwIm3DEnd(); @@ -1209,10 +1224,15 @@ CBoat::Render() RwIm3DEnd(); } } +#ifdef NEW_RENDERER + if(!gbNewRenderer) +#endif +{ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); } +} void CBoat::Teleport(CVector v) diff --git a/src/vehicles/Boat.h b/src/vehicles/Boat.h index 5f8cc8a8..5d866c48 100644 --- a/src/vehicles/Boat.h +++ b/src/vehicles/Boat.h @@ -62,7 +62,8 @@ public: virtual void GetComponentWorldPosition(int32 component, CVector &pos); virtual bool IsComponentPresent(int32 component) { return true; } virtual void BlowUpCar(CEntity *ent); - + + void RenderWaterOutPolys(void); void ApplyWaterResistance(void); void SetupModelNodes(); void PruneWakeTrail(void); diff --git a/vendor/librw b/vendor/librw index 3e2080ad..7e80d45c 160000 --- a/vendor/librw +++ b/vendor/librw @@ -1 +1 @@ -Subproject commit 3e2080ad566ded9c44ecc3e0bbccc020dbb8f116 +Subproject commit 7e80d45cdb6663f97d89ed443198ce6e37c4435e