#include "Contents/Ground/GroundGeometry.h" #include "Contents/Ground/GroundRendering.h" #include "Render/Primitives/RenderPrimitivePool.h" #include "Render/Projection/RenderProjection.h" #include "Render/Primitives/RenderQueues.h" #include "Utility/Math/AffineMatrix.h" #include "Utility/Math/ScalarConversion.h" #include #include // 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(x) + static_cast(z) * static_cast(this->water.columns); } GroundWaterSurface& surface = this->water.surfaces[partition]; float middle = level; float first = level; float last = level; if (surface.height != 0.0f) { const int sum = column + row; const auto wave = [&](int coordinate) { const float angle = static_cast(coordinate) * surface.pitch + surface.phase; const int degrees = TruncateToInt(angle); return ClientSine(degrees) * surface.height + level; }; middle = wave(sum); first = wave(sum - 1); last = wave(sum + 1); } 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(TruncateToInt(scaled)) & 255u) << (16 - 8 * channel); } } const float left = static_cast(static_cast(column) & 3u) * 0.25f; const float right = (static_cast(static_cast(column) & 3u) + 1.0f) * 0.25f; const float top = static_cast(static_cast(row) & 3u) * 0.25f; const float bottom = (static_cast(static_cast(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); }