rodecomp/Source/Contents/GroundWaterRendering.cpp
2026-10-24 00:35:19 +00:00

108 lines
3.6 KiB
C++

#include "Contents/GroundGeometry.h"
#include "Contents/GroundRendering.h"
#include "Render/RenderPrimitivePool.h"
#include "Render/RenderProjection.h"
#include "Render/RenderQueues.h"
#include "Utility/AffineMatrix.h"
#include <algorithm>
#include <bit>
#include <cstring>
#include <emmintrin.h>
// OFFSET: 0x00AC2B80
// FUNCTION: fn_17594
void GroundGeometry::DrawWaterCell(
int column,
int row,
GroundCell& cell,
const float* matrix,
const float* ambient,
bool overrideColor,
GroundRenderContext& context
) {
const float level = this->water.Level(this->width, this->height, column, row);
unsigned partition = 0;
if (this->water.partitioned) {
const int x = std::min(column / (this->width / this->water.columns), this->water.columns - 1);
const int z = std::min(row / (this->height / this->water.rows), this->water.rows - 1);
partition = static_cast<unsigned>(x) + static_cast<unsigned>(z) * static_cast<unsigned>(this->water.columns);
}
GroundWaterSurface& surface = this->water.surfaces[partition];
float middle = level;
float first = level;
float last = level;
if (surface.height != 0.0f) {
const auto sum = static_cast<unsigned>(column) + static_cast<unsigned>(row);
const auto wave = [&](unsigned coordinate) {
const float angle = static_cast<float>(std::bit_cast<int>(coordinate)) * surface.pitch + surface.phase;
const int degrees = _mm_cvttss_si32(_mm_set_ss(angle));
return ClientSine(degrees) * surface.height + level;
};
middle = wave(sum);
first = wave(sum - 1u);
last = wave(sum + 1u);
}
bool above = false;
for (unsigned corner = 0; corner < 4; ++corner) {
if (cell.top->vertices[corner][1] > middle) {
above = true;
break;
}
}
if (!above) {
return;
}
cell.corners[0][1] = first;
cell.corners[1][1] = middle;
cell.corners[2][1] = middle;
cell.corners[3][1] = last;
RenderVertex vertices[4]{};
for (unsigned corner = 0; corner < 4; ++corner) {
vertices[corner].specular = 0xFF000000u;
context.projection.Project(cell.corners[corner], matrix, vertices[corner]);
}
const float firstArea = (vertices[2].x - vertices[0].x) * (vertices[1].y - vertices[0].y);
const float secondArea = (vertices[1].x - vertices[0].x) * (vertices[2].y - vertices[0].y);
if (!(firstArea > secondArea)) {
return;
}
RenderPrimitive* primitive = context.primitives.Acquire();
std::memcpy(primitive->vertices, vertices, sizeof(vertices));
std::uint32_t color = 0x90FFFFFFu;
if (!overrideColor && this->water.type == 4) {
color = 0xFF000000u;
for (unsigned channel = 0; channel < 3; ++channel) {
const float scaled = ambient[channel] * 255.0f;
color |= (static_cast<unsigned>(_mm_cvttss_si32(_mm_set_ss(scaled))) & 255u) << (16 - 8 * channel);
}
}
const float left = static_cast<float>(static_cast<unsigned>(column) & 3u) * 0.25f;
const float right = (static_cast<float>(static_cast<unsigned>(column) & 3u) + 1.0f) * 0.25f;
const float top = static_cast<float>(static_cast<unsigned>(row) & 3u) * 0.25f;
const float bottom = (static_cast<float>(static_cast<unsigned>(row) & 3u) + 1.0f) * 0.25f;
for (unsigned corner = 0; corner < 4; ++corner) {
primitive->vertices[corner].diffuse = color;
primitive->vertices[corner].u = (corner & 1) ? right : left;
primitive->vertices[corner].v = (corner & 2) ? bottom : top;
}
primitive->unknown_0014 = (primitive->unknown_0014 & 0xFF00u) | 1u;
primitive->texture = surface.texture;
context.queues.Submit(primitive, 1, context.depthAlpha, context.depthStart, context.depthEnd);
}