Files
GTASource/game/renderer/River.cpp
T
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

837 lines
25 KiB
C++

// game headers
#include "river.h"
#include "audio/northaudioengine.h"
#include "game/Clock.h"
#include "grcore/image_dxt.h"
#include "grcore/image.h"
#include "camera/CamInterface.h"
#include "debug/TiledScreenCapture.h"
#include "renderer/Entities/EntityDrawHandler.h"
#include "renderer/Lights/lights.h"
#include "renderer/rendertargets.h"
#include "renderer/RenderPhases/RenderPhaseCascadeShadows.h"
#include "renderer/RenderPhases/RenderPhaseReflection.h"
#include "renderer/SSAO.h"
#include "renderer/Water.h"
#include "renderer/Mirrors.h"
#include "scene/RegdRefTypes.h"
#include "spatialdata/aabb.h"
#include "timecycle/TimeCycle.h"
#include "physics/WorldProbe/worldprobe.h"
#include "vfx/sky/Sky.h"
#include "grcore\texture_gnm.h"
#include "grcore\wrapper_gnm.h"
#include "system/xtl.h"
#if __D3D
# include "system/d3d9.h"
# if __XENON
# include "system/xtl.h"
# define DBG 0 // yuck
# include <xgraphics.h>
# elif RSG_DURANGO
# include <xg.h>
#endif
#endif
#if __DEV
//OPTIMISATIONS_OFF()
#endif
#if RSG_PC && !RSG_FINAL
PARAM(disableRiverFlowReadback, "Disable river flow read back");
#endif // RSG_PC && !RSG_FINAL
bank_float m_RiverPushForce = 0.1f;
static grcEffectGlobalVar m_RiverReflectionTextureVar;
static grcEffectGlobalVar m_RiverRefractionTextureVar;
static grcEffectGlobalVar m_RiverNoiseTextureVar;
static grcEffectGlobalVar m_RiverBumpTextureVar;
static grcEffectGlobalVar m_RiverWetTextureVar;
static grcEffectGlobalVar m_RiverScaledTimeVar;
static grcEffectGlobalVar m_RiverFlowParamsVar;
static grcEffectGlobalVar m_RiverFlowParams2Var;
#if WATER_SHADER_DEBUG
static grcEffectGlobalVar m_RiverFogLightVar;
#endif // WATER_SHADER_DEBUG
static grcEffectGlobalVar m_RiverRefractionDepthTextureVar;
grcEffectGlobalVar River::GetBumpTextureVar() { return m_RiverBumpTextureVar; }
grcEffectGlobalVar River::GetWetTextureVar() { return m_RiverWetTextureVar; }
static grcEffectVar m_RiverFlowVar; //This comes from the river effect, not the ocean
float m_RiverHeightAtCamera;
bool m_CameraOnRiver = false;
s32 m_RiverFogTechniqueGroup = -1;
static atFixedArray<WaterEntity, MAXRIVERENTITIES> m_WaterEntities;
struct RiverDrawable
{
fwModelId m_ModelId;
Mat34V m_Matrix;
};
static atFixedArray<RiverDrawable, 16> m_RiverDrawables[2];
static s32 m_WaterBucketCount[2];
#if __BANK
bank_s32 m_NumRiverEntities = 0;
bank_s32 m_NumRiverDrawables = 0;
#endif
s32 m_NumRiverClassEntities = 0;
using namespace River;
grcTexture* m_OffsetTexture4x = NULL;
void River::Init()
{
m_RiverReflectionTextureVar = grcEffect::LookupGlobalVar("ReflectionTex2");
m_RiverRefractionTextureVar = grcEffect::LookupGlobalVar("RefractionTexture");
m_RiverNoiseTextureVar = grcEffect::LookupGlobalVar("NoiseTexture");
m_RiverBumpTextureVar = grcEffect::LookupGlobalVar("WaterBumpTexture");
m_RiverWetTextureVar = grcEffect::LookupGlobalVar("WetTexture");
m_RiverScaledTimeVar = grcEffect::LookupGlobalVar("RiverScaledTime");
m_RiverFlowParamsVar = grcEffect::LookupGlobalVar("RiverFlowParams");
m_RiverFlowParams2Var = grcEffect::LookupGlobalVar("RiverFlowParams2");
#if WATER_SHADER_DEBUG
m_RiverFogLightVar = grcEffect::LookupGlobalVar("RiverFogLight");
#endif // WATER_SHADER_DEBUG
m_RiverRefractionDepthTextureVar = grcEffect::LookupGlobalVar("RefractionDepthTexture");
m_OffsetTexture4x = CShaderLib::LookupTexture("offset4x");
Assert(m_OffsetTexture4x);
if(m_OffsetTexture4x)
m_OffsetTexture4x->AddRef();
m_RiverFogTechniqueGroup = grmShader::FindTechniqueGroupId("imposter");
}
void CalcFlowParams(float scaledTimeF, float numSamples, Vector4* flowParams)
{
Vector4 scaledTime = Vector4(scaledTimeF);
scaledTime.y +=1.0f;
scaledTime.z +=2.0f;
scaledTime.w +=3.0f;
Vector4 grossTime;
grossTime.x = fmod(scaledTime.x, numSamples);
grossTime.y = fmod(scaledTime.y, numSamples);
grossTime.z = fmod(scaledTime.z, numSamples);
grossTime.w = fmod(scaledTime.w, numSamples);
Vector4 offset = Vector4(numSamples/2.0f);
Vector4 t = grossTime - offset;
grossTime = scaledTime - grossTime;
Vector4 tAbs = t;
tAbs.Abs();
Vector4 c = offset-tAbs;
float cLength = c.x*c.x + c.y*c.y;
if(numSamples>2.1f)
cLength += c.z*c.z;
if(numSamples>3.1f)
cLength += c.w*c.w;
cLength = sqrt(cLength);
flowParams[0] = Vector4(t.x, t.y, c.x/cLength, c.y/cLength);
if(numSamples > 2.0f)
flowParams[1] = Vector4(t.z, t.w, c.z/cLength, c.w/cLength);
}
s32 m_PreviousForcedTechniqueGroupId = -1;
void River::BeginRenderRiverFog()
{
m_PreviousForcedTechniqueGroupId = grmShaderFx::GetForcedTechniqueGroupId();
grmShaderFx::SetForcedTechniqueGroupId(m_RiverFogTechniqueGroup);
}
void River::EndRenderRiverFog()
{
grmShaderFx::SetForcedTechniqueGroupId(m_PreviousForcedTechniqueGroupId);
}
void River::SetWaterPassGlobalVars(float elapsedTime, bool XENON_ONLY(useMirrorWaterRT))
{
#if __XENON
const grcTexture* reflectionTexture = useMirrorWaterRT? CMirrors::GetMirrorWaterRenderTarget() : Water::GetReflectionRT();
#else
const grcTexture* reflectionTexture = Water::GetReflectionRT();
#endif //__XENON
const grcTexture* refractionTexture = Water::GetRefractionRT();
#if __BANK
switch (Water::m_debugReflectionSource)
{
case Water::WATER_REFLECTION_SOURCE_BLACK: reflectionTexture = grcTexture::NoneBlack; break;
case Water::WATER_REFLECTION_SOURCE_WHITE: reflectionTexture = grcTexture::NoneWhite; break;
}
if (TiledScreenCapture::IsEnabled())
{
reflectionTexture = TiledScreenCapture::GetWaterReflectionTexture();
refractionTexture = TiledScreenCapture::GetWaterReflectionTexture();
}
#endif // __BANK
grcEffect::SetGlobalVar(m_RiverReflectionTextureVar, reflectionTexture);
grcEffect::SetGlobalVar(m_RiverRefractionTextureVar, refractionTexture);
grcEffect::SetGlobalVar(m_RiverRefractionDepthTextureVar, CRenderTargets::GetDepthBufferQuarterLinear());
grcEffect::SetGlobalVar(m_RiverNoiseTextureVar, Water::GetNoiseTexture());
Water::SetWorldBase();
//Calculate flow params
Vector4 flowParams[2] = { Vector4(0.f,0.f,0.f,0.f), Vector4(0.f,0.f,0.f,0.f) };
static dev_float timeScale = 2.0f;
CalcFlowParams(elapsedTime*timeScale, 2.0f, flowParams);//Get flow params for 2x flow
grcEffect::SetGlobalVar(m_RiverFlowParamsVar, (Vec4V&)flowParams[0]);
const float time = CClock::GetDayRatio();
grcEffect::SetGlobalVar(m_RiverFlowParams2Var, Vec4V(flowParams[1].x, Water::GetUnderwaterRefractionIndex(), flowParams[1].z, fmodf(time*timeScale, 1.0f)));
#if WATER_SHADER_DEBUG
// hijacking two unused params for debugging
grcEffect::SetGlobalVar(m_RiverFlowParams2Var, Vec4f(
Water::m_debugDistortionScale*(Water::m_debugDistortionEnabled ? 1.0f : 0.0f),
0.0f,
Water::m_debugReflectionBrightnessScale,
0.0f));
grcEffect::SetGlobalVar(m_RiverFogLightVar, Vec4f(
Water::m_debugRefractionOverride*0.5f + floorf(Water::m_debugAlphaBias*256.0f),
Water::m_debugReflectionOverride,
Water::m_debugReflectionOverrideParab,
Water::m_debugHighlightAmount));
#endif // WATER_SHADER_DEBUG
}
void River::SetFogPassGlobalVars()
{
grcEffect::SetGlobalVar(m_RiverWetTextureVar, Water::GetWetMap());
grcViewport* vp=grcViewport::GetCurrent();
float n = vp->GetNearClip();
float f = vp->GetFarClip();
float fogLightIntensity = g_timeCycle.GetCurrRenderKeyframe().GetVar(TCVAR_WATER_FOGLIGHT);
grcEffect::SetGlobalVar(m_RiverScaledTimeVar, Vec4f(fwTimer::GetTimeInMilliseconds()/10000.0f, fogLightIntensity, -n*(f/(f-n)), f/(f-n)));
Water::SetWorldBase();
grcEffect::SetGlobalVar(m_RiverNoiseTextureVar, m_OffsetTexture4x);
grcEffect::SetGlobalVar(m_RiverRefractionTextureVar, CRenderPhaseCascadeShadowsInterface::GetSmoothStepTexture());
grcEffect::SetGlobalVar(m_RiverRefractionDepthTextureVar, CRenderTargets::GetDepthBufferQuarterLinear());
#if WATER_SHADER_DEBUG
grcEffect::SetGlobalVar(m_RiverFogLightVar, Vec4f(
Water::m_debugWaterFogDepthBias *(Water::m_debugWaterFogBiasEnabled ? 1.0f : 0.0f),
Water::m_debugWaterFogRefractBias*(Water::m_debugWaterFogBiasEnabled ? 1.0f : 0.0f),
Water::m_debugWaterFogColourBias *(Water::m_debugWaterFogBiasEnabled ? 1.0f : 0.0f),
Water::m_debugWaterFogShadowBias *(Water::m_debugWaterFogBiasEnabled ? 1.0f : 0.0f)));
#endif // WATER_SHADER_DEBUG
}
void River::SetDecalPassGlobalVars()
{
Water::GetCameraRangeForRender();
Water::SetWorldBase();
grcEffect::SetGlobalVar(m_RiverWetTextureVar, BANK_ONLY(TiledScreenCapture::IsEnabled() ? grcTexture::NoneBlack :) Water::GetWetMap());
grcEffect::SetGlobalVar(m_RiverBumpTextureVar, BANK_ONLY(TiledScreenCapture::IsEnabled() ? grcTexture::NoneBlack :) Water::GetWaterBumpHeightRT());
}
void River::DrawRiverCaustics(grmShader* shader, grcEffectTechnique tech, s32 pass)
{
s32 b = Water::GetWaterRenderIndex();
s32 count = m_RiverDrawables[b].GetCount();
for(s32 i = 0; i < count; i++)
{
Mat34V matrix = m_RiverDrawables[b][i].m_Matrix;
const rmcDrawable* drawable = CModelInfo::GetBaseModelInfo(m_RiverDrawables[b][i].m_ModelId)->GetDrawable();
if(Verifyf(drawable, "River drawable is null! It shouldn't be..."))
{
grcViewport::SetCurrentWorldMtx(matrix);
AssertVerify(shader->BeginDraw(grmShader::RMC_DRAW, true, tech));
shader->Bind(pass);
drawable->DrawNoShaders(RCC_MATRIX34(matrix), 0xFFFFFFFF, 0);
shader->UnBind();
shader->EndDraw();
}
}
}
void River::ResetRiverDrawList(){ m_RiverDrawables[Water::GetWaterUpdateIndex()].Reset(); }
void River::FillRiverDrawList(){
s32 b = Water::GetWaterUpdateIndex();
fwRenderListDesc& renderList = gRenderListGroup.GetRenderListForPhase(Water::GetWaterRenderPhase()->GetEntityListIndex());
fwEntityList &entityList = renderList.GetList(RPASS_WATER);
s32 entityCount = entityList.GetCount();
m_WaterBucketCount[b] = entityCount;
for(s32 i = 0; i < entityCount; i++)
{
if(m_RiverDrawables[b].IsFull())
break;
fwEntity* entity = entityList.GetEntity(i);
fwDrawData* drawHandler = entity->GetDrawHandlerPtr();
if(!drawHandler)
continue;
rmcDrawable* drawable = drawHandler->GetDrawable();
const grmShaderGroup& shaderGroup = drawable->GetShaderGroup();
const grmShader* shader = shaderGroup.GetShaderPtr(0);
bool riverType = false;
if(shader->GetHashCode() == ATSTRINGHASH("water_river", 0x38B8A4BB))
riverType = true;
if(shader->GetHashCode() == ATSTRINGHASH("water_riverocean", 0x81CC67B3))
riverType = true;
if(shader->GetHashCode() == ATSTRINGHASH("water_rivershallow", 0x938E5D80))
riverType = true;
if(shader->GetHashCode() == ATSTRINGHASH("water_fountain", 0x7569CA0))
riverType = true;
if(!riverType)
continue;
RiverDrawable riverDrawable;
riverDrawable.m_ModelId = entity->GetModelId();
riverDrawable.m_Matrix = entity->GetMatrix();
if(drawHandler)
m_RiverDrawables[b].Append() = riverDrawable;
}
#if __BANK
m_NumRiverDrawables = m_RiverDrawables[b].GetCount();
#endif //__BANK
}
void River::AddToRiverEntityList(CEntity* entity)
{
m_NumRiverClassEntities++;
Assert(entity);
if(m_WaterEntities.IsFull())
return;
if( !entity->GetLodData().IsHighDetail() )
return;
const CBaseModelInfo *modelInfo = entity->GetBaseModelInfo();
const rmcDrawable *drawable = modelInfo->GetDrawable();
const grmShaderGroup& shaderGroup = drawable->GetShaderGroup();
const grmShader* shader = shaderGroup.GetShaderPtr(0);
WaterEntity waterEntity;
waterEntity.m_Entity = RegdEnt(entity);
if( shader->GetHashCode() == ATSTRINGHASH("water_river", 0x38B8A4BB) ||
shader->GetHashCode() == ATSTRINGHASH("water_shallow", 0xE585594F) ||
shader->GetHashCode() == ATSTRINGHASH("water_rivershallow", 0x938E5D80))
waterEntity.m_IsRiver = true;
else
waterEntity.m_IsRiver = false;
#if RSG_ORBIS || RSG_PC
waterEntity.flowTextureData = NULL;
#endif
#if RSG_PC
waterEntity.m_WaitingForFlowData = false;
#endif
spdAABB localBBox = modelInfo->GetBoundingBox();
spdAABB worldAABB = TransformAABB(entity->GetTransform().GetMatrix(),localBBox);
waterEntity.m_Min = worldAABB.GetMin();
waterEntity.m_Max = worldAABB.GetMax();
m_WaterEntities.Append() = waterEntity;
#if __BANK
m_NumRiverEntities = m_WaterEntities.GetCount();
if(m_WaterEntities.IsFull())
{
Warningf("[River] River entities list full!");
for(s32 i = 0; i < m_WaterEntities.GetCount(); i++)
{
const CEntity* entity = m_WaterEntities[i].m_Entity;
Warningf("[River] %d %p river entity %s at [%f, %f, %f]", i, entity,
entity->GetModelName(),
VEC3V_ARGS(entity->GetTransform().GetPosition()));
}
}
#endif //__BANK
if(m_RiverFlowVar == grcevNONE)
{
if(!waterEntity.m_IsRiver)
return;
const CBaseModelInfo *modelInfo = entity->GetBaseModelInfo();
const rmcDrawable *drawable = modelInfo->GetDrawable();
Assert(drawable);
const grmShaderGroup& shaderGroup = drawable->GetShaderGroup();
s32 count = shaderGroup.GetCount();
for(s32 i = 0; i < count; i++)
{
const grmShader* shader = shaderGroup.GetShaderPtr(i);
if( shader->GetHashCode() == ATSTRINGHASH("water_river", 0x38B8A4BB) ||
shader->GetHashCode() == ATSTRINGHASH("water_shallow", 0xE585594F) ||
shader->GetHashCode() == ATSTRINGHASH("water_rivershallow", 0x938E5D80))
{
grcEffectVar flowVar = shader->LookupVar("FlowTexture");
Assertf(flowVar != grcevNONE, "Flow var not found in entity: %s!", entity->GetModelName());
Displayf("[River] Flow Var Index obtained: %d", flowVar);
m_RiverFlowVar = flowVar;
break;
}
}
Assertf(m_RiverFlowVar != grcevNONE, "Failed to obtain flow flow var index from entity: %s!", entity->GetModelName());
}
}
void River::RemoveFromRiverEntityList(const CEntity* entity)
{
m_NumRiverClassEntities--;
Assert(entity);
if( !entity->GetLodData().IsHighDetail() )
return;
s32 count = m_WaterEntities.GetCount();
for(s32 i =0; i < count; i++)
{
if(m_WaterEntities[i].m_Entity == entity)
{
#if RSG_ORBIS || RSG_PC
if (m_WaterEntities[i].flowTextureData)
{
delete [] m_WaterEntities[i].flowTextureData;
m_WaterEntities[i].flowTextureData = NULL;
}
#endif
m_WaterEntities.DeleteFast(i--);
BANK_ONLY(m_NumRiverEntities = m_WaterEntities.GetCount();)
return;
}
}
BANK_ONLY(m_NumRiverEntities = m_WaterEntities.GetCount();)
}
s32 River::GetRiverEntityCount()
{
return m_WaterEntities.GetCount();
}
s32 River::GetRiverDrawableCount()
{
return m_RiverDrawables[Water::GetWaterCurrentIndex()].GetCount();
}
s32 River::GetWaterBucketCount()
{
return m_WaterBucketCount[Water::GetWaterCurrentIndex()];
}
const CEntity* River::GetRiverEntity(s32 entityIndex)
{
return m_WaterEntities[entityIndex].m_Entity.Get();
}
Color32 GetTiledDXT1PixelColor32(s32 x, s32 y, s32 width, const void* bits, const grcTexture* texture)
{
s32 offset;
#if __XENON
s32 bytesPerBlock = 8;
(void)texture;
offset = XGAddress2DTiledOffset(x/4, y/4, (width+3)/4, bytesPerBlock)*bytesPerBlock;
#elif RSG_DURANGO
(void)width;
(void)bits;
XGTextureAddressComputer *pxgComputer = NULL;
XG_TEXTURE2D_DESC xgDesc;
(reinterpret_cast<const grcTextureDurango*>(texture))->GetPlacementTexture()->FillInXGDesc2D(xgDesc);
XGCreateTexture2DComputer(&xgDesc, &pxgComputer);
offset = pxgComputer->GetTexelElementOffsetBytes(0, 0, x/4, y/4, 0, 0);
pxgComputer->Release();
#else
s32 bytesPerBlock = 8;
(void)texture;
const s32 bx = x/4;
const s32 by = y/4;
const s32 blocksPerRow = (width + 3)/4;
offset = (bx + by*blocksPerRow)*bytesPerBlock;
#endif //__XENON
Color32 block[4*4];
reinterpret_cast<DXT::DXT1_BLOCK*>((u8 *)bits + offset)->Decompress(block);
return block[(x&3) + (y&3)*4];
}
#if RSG_PC
void River::UpdateFlowMaps()
{
#if !RSG_FINAL
if (PARAM_disableRiverFlowReadback.Get())
return;
#endif // !RSG_FINAL
s32 count = m_WaterEntities.GetCount();
for(s32 i =0; i < count; i++)
{
WaterEntity &waterEntity = m_WaterEntities[i];
if (waterEntity.m_IsRiver && waterEntity.flowTextureData == NULL)
{
const CEntity* entity = waterEntity.m_Entity;
const CBaseModelInfo *modelInfo = entity->GetBaseModelInfo();
const rmcDrawable *drawable = modelInfo->GetDrawable();
Assert(drawable);
const grmShaderGroup& shaderGroup = drawable->GetShaderGroup();
//Get shader
s32 numShaders = shaderGroup.GetCount();
s32 shaderGroupIndex = -1;
for(s32 i = 0; i < numShaders; i++)
{
const grmShader* shader = shaderGroup.GetShaderPtr(i);
if( shader->GetHashCode() == ATSTRINGHASH("water_river", 0x38B8A4BB) ||
shader->GetHashCode() == ATSTRINGHASH("water_shallow", 0xE585594F) ||
shader->GetHashCode() == ATSTRINGHASH("water_rivershallow", 0x938E5D80))
{
shaderGroupIndex = i;
break;
}
}
const grmShader* shader = shaderGroup.GetShaderPtr(shaderGroupIndex);
grcTexture* texture = NULL;
shader->GetVar(m_RiverFlowVar, texture);
if (!Verifyf(texture, "Flow map lookup failed on entity with model: [%s] and shader: [%s]", entity->GetModelName(), shader->GetName()))
continue;
grcTextureDX11* flowTexture = (grcTextureDX11*)texture;
bool bHasStagingTexture = flowTexture->HasStagingTexture();
if (!bHasStagingTexture)
{
flowTexture->InitializeTempStagingTexture();
}
if ( !waterEntity.m_WaitingForFlowData )
{
// If the read-back hasn't already been started, kick it off now
flowTexture->UpdateCPUCopy(true);
waterEntity.m_WaitingForFlowData = true;
}
else
{
// The texture read-back was kicked off already, check to see if it's done yet
if ( flowTexture->MapStagingBufferToBackingStore(true) )
{
waterEntity.m_WaitingForFlowData = false;
grcTextureLock lock;
if (flowTexture->LockRect( 0, 0, lock, grcsRead ))
{
u32 textureSize = flowTexture->GetStride(0) * flowTexture->GetRowCount(0);
waterEntity.flowTextureData = rage_new u8[textureSize];
sysMemCpy( waterEntity.flowTextureData, (u8*)lock.Base, flowTexture->GetStride(0) * flowTexture->GetRowCount(0));
flowTexture->UnlockRect(lock);
}
if (!bHasStagingTexture)
flowTexture->ReleaseTempStagingTexture();
}
}
}
}
}
#endif
void River::GetRiverFlowFromEntity(WaterEntity& waterEntity, const Vector3& position, Vector2& outFlow)
{
const CEntity* entity = waterEntity.m_Entity;
const CBaseModelInfo *modelInfo = entity->GetBaseModelInfo();
const rmcDrawable *drawable = modelInfo->GetDrawable();
spdAABB localBBox = modelInfo->GetBoundingBox();
spdAABB worldAABB = TransformAABB(entity->GetTransform().GetMatrix(),localBBox);
Vector3 min = worldAABB.GetMinVector3();
Vector3 max = worldAABB.GetMaxVector3();
Assert(drawable);
const grmShaderGroup& shaderGroup = drawable->GetShaderGroup();
//Get shader
s32 numShaders = shaderGroup.GetCount();
s32 shaderGroupIndex = -1;
for(s32 i = 0; i < numShaders; i++)
{
const grmShader* shader = shaderGroup.GetShaderPtr(i);
if( shader->GetHashCode() == ATSTRINGHASH("water_river", 0x38B8A4BB) ||
shader->GetHashCode() == ATSTRINGHASH("water_shallow", 0xE585594F) ||
shader->GetHashCode() == ATSTRINGHASH("water_rivershallow", 0x938E5D80))
{
shaderGroupIndex = i;
break;
}
}
const grmShader* shader = shaderGroup.GetShaderPtr(shaderGroupIndex);
grcTexture* texture = NULL;
shader->GetVar(m_RiverFlowVar, texture);
if(!Verifyf(texture, "Flow map lookup failed on entity with model: [%s] and shader: [%s]", entity->GetModelName(), shader->GetName()))
{
#if __ASSERT
grcEffectVar flowVar = shader->LookupVar("FlowTexture");
if(flowVar != m_RiverFlowVar)
Assertf(texture, "Flow map found at index [%d] but is suppose to be at [%d]", flowVar, m_RiverFlowVar);
else if(flowVar == grcevNONE)
Assertf(texture, "Flow sampler not found in this shader [%s]", shader->GetName());
else
Assertf(texture, "Flow var appears correct yet a texture could not be found");
#endif //_BANK
return;
}
s32 width = texture->GetWidth();
s32 height = texture->GetHeight();
#if RSG_PC
if (!waterEntity.flowTextureData)
{
return;
}
void* fastLock = waterEntity.flowTextureData;
#elif RSG_ORBIS
if (waterEntity.flowTextureData == NULL)
{
const sce::Gnm::Texture *gnmTexture = reinterpret_cast<const sce::Gnm::Texture*>(texture->GetTexturePtr());
uint64_t offset;
uint64_t size;
#if SCE_ORBIS_SDK_VERSION < (0x00930020u)
sce::GpuAddress::computeSurfaceOffsetAndSize(
#else
sce::GpuAddress::computeTextureSurfaceOffsetAndSize(
#endif
&offset,&size,gnmTexture,0,0);
waterEntity.flowTextureData = rage_new u8[size];
sce::GpuAddress::TilingParameters tp;
tp.initFromTexture(gnmTexture, 0, 0);
sce::GpuAddress::detileSurface(waterEntity.flowTextureData, ((char*)gnmTexture->getBaseAddress() + offset),&tp);
}
if (!waterEntity.flowTextureData) return;
void* fastLock = waterEntity.flowTextureData;
#else
grcTextureLock lock;
if (!texture->LockRect(0, 0, lock, grcsRead))
return;
void* fastLock = lock.Base;
#endif //RSG_PC
Vector3 offsetV3 = -min;
Vector3 scaleV3 = Vector3((float)width, (float)height, 1.0f)/(max-min);
Vector2 offset = Vector2(offsetV3.x, offsetV3.y);
Vector2 scale = Vector2(scaleV3.x, scaleV3.y);
Vector2 pos = Vector2(position.x, position.y);
// Vector2 flow = Vector2(0, 0);
if((pos.x >= min.x) && (pos.x <= max.x) && (pos.y >= min.y) && (pos.y <= max.y))
{
Vector2 texCoords = (pos + offset) * scale;
s32 x = (s32)texCoords.x;
s32 y = height-1-(s32)texCoords.y;
if(!(x < width && x >= 0))
{
// fix for rounding errors
if(texCoords.x + 0.1f < 0)
{
Errorf("invalid x of %d [%d-%d]", x, 0, width);
outFlow.Set(0.0f, 0.0f);
return;
}
else
x = 0;
if(texCoords.x - 0.1f > width)
{
Errorf("invalid x of %d [%d-%d]", x, 0, width);
outFlow.Set(0.0f, 0.0f);
return;
}
else
x = width -1;
}
if(!(y < height && y >= 0))
{
// fix for rounding errors
if(texCoords.y + 0.1f < 0)
{
Errorf("invalid x of %d [%d-%d]", x, 0, width);
outFlow.Set(0.0f, 0.0f);
return;
}
else
y = 0;
if(texCoords.y - 0.1f > height)
{
Errorf("invalid x of %d [%d-%d]", y, 0, height);
outFlow.Set(0.0f, 0.0f);
return;
}
else
y = height -1;
}
Color32 color = GetTiledDXT1PixelColor32(x, y, width, fastLock, texture);
Vector2 colorV = Vector2(color.GetRedf(), color.GetGreenf());
colorV.Scale(2.0f);
colorV.Subtract(Vector2(1.0f, 1.0f));
outFlow = colorV * m_RiverPushForce;
}
else
outFlow.Set(0.0f, 0.0f);
#if !__XENON && !RSG_ORBIS && !RSG_PC
texture->UnlockRect(lock);
#endif //__XENON
}
bool River::IsPositionNearRiver_Impl(Vec3V_In pos, s32* pEntityIndex, bool riversOnly, VecBoolV_In channelsToConsider, ScalarV_In maxDistanceToConsider)
{
// Walk through the array of river entities and determine if the given position
// is within any of their bounding boxes. Returns the index of the first entity
// which we are in by reference.
Vec3V boundingBoxExpandForMaxDistance(maxDistanceToConsider);
for(WaterEntity* ent = m_WaterEntities.begin(); ent != m_WaterEntities.end(); ++ent)
{
if(riversOnly && !ent->m_IsRiver)
continue;
Vec3V min = ent->m_Min - boundingBoxExpandForMaxDistance;
Vec3V max = ent->m_Max + boundingBoxExpandForMaxDistance;
VecBoolV posVsMin = IsLessThan(pos, min);
VecBoolV posVsMax = IsGreaterThan(pos, max);
VecBoolV isOutside = posVsMin | posVsMax;
if (IsEqualIntAll(isOutside & channelsToConsider, VecBoolV(V_FALSE)))
{
if(pEntityIndex)
*pEntityIndex = ptrdiff_t_to_int(ent - m_WaterEntities.begin());
return true;
}
}
if(pEntityIndex)
*pEntityIndex = -1;
return false;
}
void River::GetRiverFlowFromPosition(Vec3V_In pos, Vector2& outFlow)
{
s32 entityIndex;
if(IsPositionNearRiver(pos, &entityIndex, true))
{
Vector3 posV = VEC3V_TO_VECTOR3(pos);
GetRiverFlowFromEntity(m_WaterEntities[entityIndex], posV, outFlow);
return;
}
outFlow.Set(0.0f, 0.0f);
}
bool hit = false;
void River::Update()
{
Vector3 cameraPosition = camInterface::GetPos();
float height;
bool hasFoundWater = CWaterTestHelper::GetRiverHeightAtPosition(cameraPosition, &height);
if(hasFoundWater)
{
m_CameraOnRiver = true;
m_RiverHeightAtCamera = height;
}
else
{
m_CameraOnRiver = false;
m_RiverHeightAtCamera = 0.0f;
}
}
float River::GetRiverPushForce(){ return m_RiverPushForce; }
float River::GetRiverHeightAtCamera(){ return m_RiverHeightAtCamera; }
bool River::CameraOnRiver(){ return m_CameraOnRiver; }
#if __BANK
void PrintFlowList()
{
s32 count = m_WaterEntities.GetCount();
for(s32 i = 0; i < count; i++)
{
CEntity* entity = m_WaterEntities[i].m_Entity;
Displayf("%s", entity->GetModelName());
}
}
void River::InitWidgets(bkBank& bank)
{
bank.AddTitle("Rivers");
bank.AddSlider("River Push Force", &m_RiverPushForce, 0.0f,5.0f, 0.1f);
bank.AddText("River Entities", &m_NumRiverEntities);
bank.AddText("River Drawables", &m_NumRiverDrawables);
bank.AddText("River Class Entities", &m_NumRiverClassEntities);
bank.AddText("Water Bucket Count", &m_WaterBucketCount[0]);
bank.AddText("CameraRiverHeight", &m_RiverHeightAtCamera);
bank.AddButton("Print Flow List", PrintFlowList);
}
#endif