TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1206 lines
42 KiB
1206 lines
42 KiB
#include <phpx.h>
|
|
|
|
#include <windows.h>
|
|
#include <gl/GL.h>
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
#include <windowsx.h>
|
|
|
|
using namespace php;
|
|
|
|
static HWND g_hwnd = nullptr;
|
|
static HDC g_hdc = nullptr;
|
|
static HGLRC g_glrc = nullptr;
|
|
static bool g_should_close = false;
|
|
static bool g_keys[256] = {};
|
|
static bool g_mouse_captured = false;
|
|
static bool g_mouse_ready = false;
|
|
static POINT g_last_mouse = {};
|
|
static double g_mouse_dx = 0.0;
|
|
static double g_mouse_dy = 0.0;
|
|
static int g_width = 1280;
|
|
static int g_height = 720;
|
|
|
|
static float g_boat_x = 0.0f;
|
|
static float g_boat_z = 0.0f;
|
|
static float g_boat_yaw = 0.0f;
|
|
static float g_boat_speed = 0.0f;
|
|
static float g_camera_yaw = 0.0f;
|
|
static float g_camera_pitch = 0.32f;
|
|
static float g_camera_distance = 18.0f;
|
|
static float g_day_time = 0.28f;
|
|
static int g_weather = 0;
|
|
static float g_weather_mix = 0.0f;
|
|
static float g_rain = 0.0f;
|
|
static double g_start_time = 0.0;
|
|
|
|
struct ChunkKey {
|
|
int x;
|
|
int z;
|
|
|
|
bool operator==(const ChunkKey &other) const {
|
|
return x == other.x && z == other.z;
|
|
}
|
|
};
|
|
|
|
struct ChunkKeyHash {
|
|
size_t operator()(const ChunkKey &key) const {
|
|
const uint64_t x = static_cast<uint32_t>(key.x);
|
|
const uint64_t z = static_cast<uint32_t>(key.z);
|
|
return static_cast<size_t>((x * 73856093u) ^ (z * 83492791u));
|
|
}
|
|
};
|
|
|
|
struct OceanMarker {
|
|
float x;
|
|
float z;
|
|
int type;
|
|
float size;
|
|
};
|
|
|
|
static std::unordered_map<ChunkKey, std::vector<OceanMarker>, ChunkKeyHash> g_marker_chunks;
|
|
static std::vector<OceanMarker> g_pending_markers;
|
|
static ChunkKey g_pending_chunk{0, 0};
|
|
static bool g_has_pending_chunk = false;
|
|
|
|
struct SpectralWave {
|
|
float dir_x;
|
|
float dir_z;
|
|
float amplitude;
|
|
float wavelength;
|
|
float phase;
|
|
float steepness;
|
|
};
|
|
|
|
static const SpectralWave SPECTRAL_WAVES[] = {
|
|
{0.78f, 0.62f, 0.34f, 28.0f, 0.0f, 0.42f},
|
|
{0.52f, 0.85f, 0.22f, 17.0f, 1.7f, 0.36f},
|
|
{-0.28f, 0.96f, 0.14f, 9.5f, 3.2f, 0.25f},
|
|
{0.98f, -0.20f, 0.08f, 5.8f, 4.6f, 0.16f},
|
|
{-0.76f, 0.65f, 0.06f, 3.4f, 2.4f, 0.11f},
|
|
};
|
|
|
|
static double now_seconds() {
|
|
LARGE_INTEGER freq;
|
|
LARGE_INTEGER counter;
|
|
QueryPerformanceFrequency(&freq);
|
|
QueryPerformanceCounter(&counter);
|
|
return static_cast<double>(counter.QuadPart) / static_cast<double>(freq.QuadPart);
|
|
}
|
|
|
|
static void update_cursor_clip() {
|
|
if (!g_hwnd) {
|
|
return;
|
|
}
|
|
RECT rect{};
|
|
GetClientRect(g_hwnd, &rect);
|
|
POINT top_left{rect.left, rect.top};
|
|
POINT bottom_right{rect.right, rect.bottom};
|
|
ClientToScreen(g_hwnd, &top_left);
|
|
ClientToScreen(g_hwnd, &bottom_right);
|
|
rect.left = top_left.x;
|
|
rect.top = top_left.y;
|
|
rect.right = bottom_right.x;
|
|
rect.bottom = bottom_right.y;
|
|
ClipCursor(&rect);
|
|
}
|
|
|
|
static void enable_mouse_capture() {
|
|
if (!g_hwnd || g_mouse_captured) {
|
|
if (g_mouse_captured) {
|
|
update_cursor_clip();
|
|
}
|
|
return;
|
|
}
|
|
SetCapture(g_hwnd);
|
|
ShowCursor(FALSE);
|
|
update_cursor_clip();
|
|
g_mouse_captured = true;
|
|
}
|
|
|
|
static void disable_mouse_capture() {
|
|
if (!g_mouse_captured) {
|
|
return;
|
|
}
|
|
ClipCursor(nullptr);
|
|
ReleaseCapture();
|
|
ShowCursor(TRUE);
|
|
g_mouse_captured = false;
|
|
g_mouse_ready = false;
|
|
}
|
|
|
|
static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
|
|
switch (msg) {
|
|
case WM_CLOSE:
|
|
case WM_DESTROY:
|
|
g_should_close = true;
|
|
PostQuitMessage(0);
|
|
return 0;
|
|
case WM_SIZE:
|
|
g_width = std::max(1, static_cast<int>(LOWORD(lp)));
|
|
g_height = std::max(1, static_cast<int>(HIWORD(lp)));
|
|
update_cursor_clip();
|
|
return 0;
|
|
case WM_ACTIVATE:
|
|
if (LOWORD(wp) == WA_INACTIVE) {
|
|
disable_mouse_capture();
|
|
} else {
|
|
enable_mouse_capture();
|
|
}
|
|
return 0;
|
|
case WM_KEYDOWN:
|
|
if (wp < 256) {
|
|
g_keys[wp] = true;
|
|
}
|
|
return 0;
|
|
case WM_MOUSEMOVE: {
|
|
POINT p{GET_X_LPARAM(lp), GET_Y_LPARAM(lp)};
|
|
if (g_mouse_ready) {
|
|
g_mouse_dx += static_cast<double>(p.x - g_last_mouse.x);
|
|
g_mouse_dy += static_cast<double>(p.y - g_last_mouse.y);
|
|
}
|
|
g_last_mouse = p;
|
|
g_mouse_ready = true;
|
|
return 0;
|
|
}
|
|
case WM_KEYUP:
|
|
if (wp < 256) {
|
|
g_keys[wp] = false;
|
|
}
|
|
return 0;
|
|
}
|
|
return DefWindowProc(hwnd, msg, wp, lp);
|
|
}
|
|
|
|
static void set_perspective(double fov_y, double aspect, double near_z, double far_z) {
|
|
const double top = near_z * std::tan(fov_y * 3.14159265358979323846 / 360.0);
|
|
const double right = top * aspect;
|
|
glFrustum(-right, right, -top, top, near_z, far_z);
|
|
}
|
|
|
|
static float clamp01(float v) {
|
|
return std::max(0.0f, std::min(1.0f, v));
|
|
}
|
|
|
|
static float smoothstep(float edge0, float edge1, float x) {
|
|
const float t = clamp01((x - edge0) / (edge1 - edge0));
|
|
return t * t * (3.0f - 2.0f * t);
|
|
}
|
|
|
|
static float active_weather_strength() {
|
|
const float base = g_weather == 1 ? 0.55f : (g_weather == 2 ? 1.0f : 0.0f);
|
|
const float transition = g_weather_mix * 0.30f;
|
|
return clamp01(std::max(base, transition));
|
|
}
|
|
|
|
static float wave_height(float x, float z, float t) {
|
|
float height = 0.0f;
|
|
const float storm = active_weather_strength();
|
|
for (const SpectralWave &wave : SPECTRAL_WAVES) {
|
|
const float k = 6.2831853f / wave.wavelength;
|
|
const float omega = std::sqrt(9.81f * k);
|
|
const float phase = k * (x * wave.dir_x + z * wave.dir_z) + omega * t + wave.phase;
|
|
const float choppy = std::sin(phase) + 0.34f * std::sin(phase * 2.07f + wave.phase);
|
|
height += choppy * wave.amplitude * (1.0f + storm * wave.steepness);
|
|
}
|
|
return height;
|
|
}
|
|
|
|
static void normalize3(float v[3]) {
|
|
const float len = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
|
if (len > 0.0001f) {
|
|
v[0] /= len;
|
|
v[1] /= len;
|
|
v[2] /= len;
|
|
}
|
|
}
|
|
|
|
static void wave_normal(float x, float z, float t, float out[3]) {
|
|
const float e = 0.45f;
|
|
const float hx1 = wave_height(x + e, z, t);
|
|
const float hx0 = wave_height(x - e, z, t);
|
|
const float hz1 = wave_height(x, z + e, t);
|
|
const float hz0 = wave_height(x, z - e, t);
|
|
out[0] = -(hx1 - hx0) / (e * 2.0f);
|
|
out[1] = 1.0f;
|
|
out[2] = -(hz1 - hz0) / (e * 2.0f);
|
|
normalize3(out);
|
|
}
|
|
|
|
static float sun_height() {
|
|
return std::sin((g_day_time - 0.25f) * 6.2831853f);
|
|
}
|
|
|
|
static void sun_direction(float out[3]) {
|
|
const float a = (g_day_time - 0.25f) * 6.2831853f;
|
|
out[0] = std::cos(a) * 0.45f;
|
|
out[1] = std::max(0.14f, std::sin(a));
|
|
out[2] = -0.72f;
|
|
normalize3(out);
|
|
}
|
|
|
|
static float fresnel_schlick(float cos_theta) {
|
|
const float f0 = 0.02f;
|
|
return f0 + (1.0f - f0) * std::pow(clamp01(1.0f - cos_theta), 5.0f);
|
|
}
|
|
|
|
static float ggx_distribution(float n_dot_h, float roughness) {
|
|
const float a = roughness * roughness;
|
|
const float a2 = a * a;
|
|
const float d = n_dot_h * n_dot_h * (a2 - 1.0f) + 1.0f;
|
|
return a2 / std::max(0.0001f, 3.14159265f * d * d);
|
|
}
|
|
|
|
static float slope_roughness(const float n[3]) {
|
|
const float slope = std::sqrt(n[0] * n[0] + n[2] * n[2]);
|
|
return std::max(0.05f, std::min(0.92f, 0.18f + slope * 1.9f + g_rain * 0.20f));
|
|
}
|
|
|
|
static float slope_ambient_occlusion(const float n[3]) {
|
|
const float slope = std::sqrt(n[0] * n[0] + n[2] * n[2]);
|
|
return clamp01(1.0f - 3.8f * slope);
|
|
}
|
|
|
|
static float exp_fog_factor(float distance, float density) {
|
|
const float f = std::exp(-std::pow(density * distance, 2.0f));
|
|
return clamp01(f);
|
|
}
|
|
|
|
static float night_factor() {
|
|
return clamp01(1.0f - smoothstep(0.18f, 0.30f, g_day_time) +
|
|
smoothstep(0.72f, 0.90f, g_day_time));
|
|
}
|
|
|
|
static float dawn_dusk_factor() {
|
|
const float dawn = smoothstep(0.18f, 0.30f, g_day_time) * (1.0f - smoothstep(0.35f, 0.46f, g_day_time));
|
|
const float dusk = smoothstep(0.60f, 0.72f, g_day_time) * (1.0f - smoothstep(0.78f, 0.90f, g_day_time));
|
|
return std::max(dawn, dusk);
|
|
}
|
|
|
|
static float tone_map(float color) {
|
|
color = std::max(0.0f, color);
|
|
color = color / (1.0f + color);
|
|
return std::pow(color, 1.0f / 2.2f);
|
|
}
|
|
|
|
static void tone_map_rgb(float &r, float &g, float &b, float exposure) {
|
|
r = tone_map(r * exposure);
|
|
g = tone_map(g * exposure);
|
|
b = tone_map(b * exposure);
|
|
}
|
|
|
|
static float remap_value(float value, float old_min, float old_max, float new_min, float new_max) {
|
|
return new_min + ((value - old_min) / (old_max - old_min)) * (new_max - new_min);
|
|
}
|
|
|
|
static float hash31(float x, float y, float z) {
|
|
const float n = std::sin(x * 127.1f + y * 311.7f + z * 74.7f) * 43758.5453f;
|
|
return n - std::floor(n);
|
|
}
|
|
|
|
static float value_noise3(float x, float y, float z) {
|
|
const float ix = std::floor(x);
|
|
const float iy = std::floor(y);
|
|
const float iz = std::floor(z);
|
|
const float fx = x - ix;
|
|
const float fy = y - iy;
|
|
const float fz = z - iz;
|
|
const float ux = fx * fx * fx * (fx * (fx * 6.0f - 15.0f) + 10.0f);
|
|
const float uy = fy * fy * fy * (fy * (fy * 6.0f - 15.0f) + 10.0f);
|
|
const float uz = fz * fz * fz * (fz * (fz * 6.0f - 15.0f) + 10.0f);
|
|
|
|
float c[2][2][2];
|
|
for (int dx = 0; dx <= 1; dx++) {
|
|
for (int dy = 0; dy <= 1; dy++) {
|
|
for (int dz = 0; dz <= 1; dz++) {
|
|
c[dx][dy][dz] = hash31(ix + dx, iy + dy, iz + dz);
|
|
}
|
|
}
|
|
}
|
|
|
|
const float x00 = c[0][0][0] + (c[1][0][0] - c[0][0][0]) * ux;
|
|
const float x10 = c[0][1][0] + (c[1][1][0] - c[0][1][0]) * ux;
|
|
const float x01 = c[0][0][1] + (c[1][0][1] - c[0][0][1]) * ux;
|
|
const float x11 = c[0][1][1] + (c[1][1][1] - c[0][1][1]) * ux;
|
|
const float y0 = x00 + (x10 - x00) * uy;
|
|
const float y1 = x01 + (x11 - x01) * uy;
|
|
return y0 + (y1 - y0) * uz;
|
|
}
|
|
|
|
static float worley_noise2(float x, float y) {
|
|
const int ix = static_cast<int>(std::floor(x));
|
|
const int iy = static_cast<int>(std::floor(y));
|
|
float min_dist = 10000.0f;
|
|
for (int ox = -1; ox <= 1; ox++) {
|
|
for (int oy = -1; oy <= 1; oy++) {
|
|
const float cx = static_cast<float>(ix + ox) + hash31(static_cast<float>(ix + ox), static_cast<float>(iy + oy), 11.0f);
|
|
const float cy = static_cast<float>(iy + oy) + hash31(static_cast<float>(ix + ox), static_cast<float>(iy + oy), 29.0f);
|
|
const float dx = x - cx;
|
|
const float dy = y - cy;
|
|
min_dist = std::min(min_dist, dx * dx + dy * dy);
|
|
}
|
|
}
|
|
return clamp01(1.0f - min_dist);
|
|
}
|
|
|
|
static float cloud_density_sample(float x, float y, float time, float coverage) {
|
|
const float height_fraction = clamp01((y + 0.20f) / 0.82f);
|
|
const float wind_x = std::cos(g_day_time * 6.2831853f + 0.7f);
|
|
const float wind_y = std::sin(g_day_time * 6.2831853f + 0.7f);
|
|
const float shear = height_fraction * 0.34f;
|
|
x += wind_x * time * 0.012f + shear;
|
|
y += wind_y * time * 0.008f;
|
|
|
|
const float base = value_noise3(x * 2.2f, y * 3.0f, time * 0.015f);
|
|
const float worley = worley_noise2(x * 3.4f, y * 2.1f) * 0.625f +
|
|
worley_noise2(x * 6.8f + 17.0f, y * 4.2f - 9.0f) * 0.25f +
|
|
worley_noise2(x * 13.6f - 5.0f, y * 8.4f + 23.0f) * 0.125f;
|
|
float shape = remap_value(base, 1.0f - worley * 0.78f, 1.0f, 0.0f, 1.0f);
|
|
const float vertical = smoothstep(0.0f, 0.16f, height_fraction) * (1.0f - smoothstep(0.78f, 1.0f, height_fraction));
|
|
shape *= vertical;
|
|
|
|
const float detail = value_noise3(x * 13.0f + 4.0f, y * 16.0f - 2.0f, time * 0.05f);
|
|
shape = remap_value(shape, (1.0f - detail) * 0.34f, 1.0f, 0.0f, 1.0f);
|
|
shape = remap_value(shape, coverage, 1.0f, 0.0f, 1.0f) * coverage;
|
|
return clamp01(shape);
|
|
}
|
|
|
|
static float henyey_greenstein_phase(float cos_angle, float g) {
|
|
const float g2 = g * g;
|
|
return ((1.0f - g2) / std::pow(1.0f + g2 - 2.0f * g * cos_angle, 1.5f)) * 0.07957747f;
|
|
}
|
|
|
|
static float cloud_powder(float density, float cos_angle) {
|
|
const float powder = 1.0f - std::exp(-density * 2.0f);
|
|
const float edge = clamp01((-cos_angle * 0.5f) + 0.5f);
|
|
return 1.0f + (powder - 1.0f) * edge;
|
|
}
|
|
|
|
static void sky_colors(float top[3], float horizon[3], float *light) {
|
|
const float night = 1.0f - smoothstep(0.18f, 0.27f, g_day_time) +
|
|
smoothstep(0.78f, 0.92f, g_day_time);
|
|
const float dawn = smoothstep(0.18f, 0.30f, g_day_time) * (1.0f - smoothstep(0.34f, 0.43f, g_day_time));
|
|
const float dusk = smoothstep(0.62f, 0.72f, g_day_time) * (1.0f - smoothstep(0.78f, 0.88f, g_day_time));
|
|
const float golden = std::max(dawn, dusk);
|
|
const float cloudy = g_weather == 1 ? 0.72f : (g_weather == 2 ? 0.90f : 0.0f);
|
|
|
|
top[0] = 0.12f + 0.28f * (1.0f - night) + 0.20f * golden;
|
|
top[1] = 0.18f + 0.42f * (1.0f - night) + 0.10f * golden;
|
|
top[2] = 0.34f + 0.54f * (1.0f - night) - 0.10f * golden;
|
|
horizon[0] = 0.18f + 0.55f * (1.0f - night) + 0.34f * golden;
|
|
horizon[1] = 0.23f + 0.47f * (1.0f - night) + 0.17f * golden;
|
|
horizon[2] = 0.34f + 0.44f * (1.0f - night) - 0.22f * golden;
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
top[i] = top[i] * (1.0f - cloudy) + 0.33f * cloudy;
|
|
horizon[i] = horizon[i] * (1.0f - cloudy) + 0.46f * cloudy;
|
|
}
|
|
const float exposure = 1.05f + dawn_dusk_factor() * 0.25f - cloudy * 0.10f;
|
|
tone_map_rgb(top[0], top[1], top[2], exposure);
|
|
tone_map_rgb(horizon[0], horizon[1], horizon[2], exposure);
|
|
*light = std::max(0.12f, 1.0f - night * 0.74f - cloudy * 0.28f);
|
|
}
|
|
|
|
static void draw_sky() {
|
|
float top[3];
|
|
float horizon[3];
|
|
float light = 1.0f;
|
|
sky_colors(top, horizon, &light);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glOrtho(-1, 1, -1, 1, -1, 1);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_FOG);
|
|
|
|
glBegin(GL_QUADS);
|
|
glColor3f(horizon[0], horizon[1], horizon[2]);
|
|
glVertex2f(-1.0f, -1.0f);
|
|
glVertex2f(1.0f, -1.0f);
|
|
glColor3f(top[0], top[1], top[2]);
|
|
glVertex2f(1.0f, 1.0f);
|
|
glVertex2f(-1.0f, 1.0f);
|
|
glEnd();
|
|
|
|
const float sun_angle = (g_day_time - 0.25f) * 6.2831853f;
|
|
const float sx = std::cos(sun_angle) * 0.68f;
|
|
const float sy = std::sin(sun_angle) * 0.74f;
|
|
const bool moon = sy < -0.05f;
|
|
const float body_y = moon ? -sy : sy;
|
|
if (body_y > -0.10f) {
|
|
glColor4f(moon ? 0.74f : 1.0f, moon ? 0.80f : 0.86f, moon ? 0.92f : 0.42f, moon ? 0.85f : 0.95f);
|
|
const float r = moon ? 0.045f : 0.065f;
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
glVertex2f(sx, body_y);
|
|
for (int i = 0; i <= 48; i++) {
|
|
const float a = static_cast<float>(i) / 48.0f * 6.2831853f;
|
|
glVertex2f(sx + std::cos(a) * r, body_y + std::sin(a) * r);
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
const float time = static_cast<float>(now_seconds() - g_start_time);
|
|
const float weather_coverage = g_weather == 0 ? 0.48f : (g_weather == 1 ? 0.34f : 0.24f);
|
|
const float cloud_strength = g_weather == 0 ? 0.46f : (g_weather == 1 ? 0.78f : 0.92f);
|
|
float sun_dir[3];
|
|
sun_direction(sun_dir);
|
|
const float cos_angle = clamp01(sun_dir[1] * 0.45f + 0.35f);
|
|
const float hg = std::max(henyey_greenstein_phase(cos_angle, 0.62f), henyey_greenstein_phase(cos_angle, -0.25f)) * 0.45f + 0.64f;
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
for (int layer = 0; layer < 5; layer++) {
|
|
const float layer_y = 0.26f + layer * 0.075f;
|
|
const float layer_scale = 1.0f + layer * 0.20f;
|
|
const float alpha_scale = (0.10f + layer * 0.055f) * cloud_strength;
|
|
const float y_step = 0.055f;
|
|
const float x_step = 0.075f;
|
|
for (float cy = -0.12f; cy <= 0.76f; cy += y_step) {
|
|
glBegin(GL_QUAD_STRIP);
|
|
for (float cx = -1.24f; cx <= 1.26f; cx += x_step) {
|
|
for (int row = 0; row < 2; row++) {
|
|
const float px = cx;
|
|
const float py = cy + row * y_step;
|
|
const float density = cloud_density_sample(px * layer_scale + layer * 2.7f, py * layer_scale, time, weather_coverage);
|
|
if (density <= 0.01f || py < -0.10f) {
|
|
glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
|
|
} else {
|
|
const float height_fraction = clamp01((py + 0.12f) / 0.88f);
|
|
const float transmittance = std::exp(-density * (1.45f + g_rain * 0.55f));
|
|
const float powder = cloud_powder(density, cos_angle);
|
|
const float lit = (0.38f + hg * powder * (0.85f - g_rain * 0.28f)) * (0.72f + height_fraction * 0.35f);
|
|
float cr = (0.55f + top[0] * 0.48f) * lit;
|
|
float cg = (0.58f + top[1] * 0.44f) * lit;
|
|
float cb = (0.62f + top[2] * 0.40f) * lit;
|
|
cr = cr * (1.0f - g_rain * 0.24f) + 0.34f * g_rain;
|
|
cg = cg * (1.0f - g_rain * 0.22f) + 0.36f * g_rain;
|
|
cb = cb * (1.0f - g_rain * 0.18f) + 0.40f * g_rain;
|
|
tone_map_rgb(cr, cg, cb, 1.18f + dawn_dusk_factor() * 0.22f);
|
|
const float alpha = clamp01((1.0f - transmittance) * alpha_scale);
|
|
glColor4f(cr, cg, cb, alpha);
|
|
}
|
|
glVertex2f(px, layer_y + py * 0.34f + row * 0.004f);
|
|
}
|
|
}
|
|
glEnd();
|
|
}
|
|
}
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glEnable(GL_FOG);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
}
|
|
|
|
static void draw_skybox() {
|
|
float top[3];
|
|
float horizon[3];
|
|
float light = 1.0f;
|
|
sky_colors(top, horizon, &light);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glRotatef(g_camera_pitch * 57.2957795f, 1, 0, 0);
|
|
glRotatef(g_camera_yaw * 57.2957795f, 0, 1, 0);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_CULL_FACE);
|
|
glDisable(GL_FOG);
|
|
glDepthMask(GL_FALSE);
|
|
|
|
const float radius = 135.0f;
|
|
const int rings = 8;
|
|
const int segments = 64;
|
|
for (int ring = 0; ring < rings; ring++) {
|
|
const float v0 = static_cast<float>(ring) / static_cast<float>(rings);
|
|
const float v1 = static_cast<float>(ring + 1) / static_cast<float>(rings);
|
|
const float e0 = 0.04f + v0 * 1.18f;
|
|
const float e1 = 0.04f + v1 * 1.18f;
|
|
const float y0 = std::sin(e0) * radius - 12.0f;
|
|
const float y1 = std::sin(e1) * radius - 12.0f;
|
|
const float r0 = std::cos(e0) * radius;
|
|
const float r1 = std::cos(e1) * radius;
|
|
const float c0 = smoothstep(0.0f, 1.0f, v0);
|
|
const float c1 = smoothstep(0.0f, 1.0f, v1);
|
|
|
|
glBegin(GL_QUAD_STRIP);
|
|
for (int seg = 0; seg <= segments; seg++) {
|
|
const float a = static_cast<float>(seg) / static_cast<float>(segments) * 6.2831853f;
|
|
const float ca = std::cos(a);
|
|
const float sa = std::sin(a);
|
|
glColor3f(
|
|
horizon[0] * (1.0f - c0) + top[0] * c0,
|
|
horizon[1] * (1.0f - c0) + top[1] * c0,
|
|
horizon[2] * (1.0f - c0) + top[2] * c0);
|
|
glVertex3f(ca * r0, y0, sa * r0);
|
|
glColor3f(
|
|
horizon[0] * (1.0f - c1) + top[0] * c1,
|
|
horizon[1] * (1.0f - c1) + top[1] * c1,
|
|
horizon[2] * (1.0f - c1) + top[2] * c1);
|
|
glVertex3f(ca * r1, y1, sa * r1);
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
glDepthMask(GL_TRUE);
|
|
glEnable(GL_FOG);
|
|
glEnable(GL_CULL_FACE);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glPopMatrix();
|
|
}
|
|
|
|
static void draw_water() {
|
|
const double t = now_seconds() - g_start_time;
|
|
float top[3];
|
|
float horizon[3];
|
|
float light = 1.0f;
|
|
sky_colors(top, horizon, &light);
|
|
float sun[3];
|
|
sun_direction(sun);
|
|
const float day_spec = smoothstep(-0.05f, 0.35f, sun_height()) * (1.0f - g_rain * 0.70f);
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
const int half = 68;
|
|
const float step = 1.55f;
|
|
for (int z = -half; z < half; z++) {
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
for (int x = -half; x <= half; x++) {
|
|
for (int row = 0; row < 2; row++) {
|
|
const float wx = g_boat_x + x * step;
|
|
const float wz = g_boat_z + (z + row) * step;
|
|
const float y = wave_height(wx, wz, static_cast<float>(t));
|
|
float n[3];
|
|
wave_normal(wx, wz, static_cast<float>(t), n);
|
|
float view[3] = {g_boat_x - wx, 5.0f - y, g_boat_z + g_camera_distance - wz};
|
|
normalize3(view);
|
|
const float diffuse = std::max(0.0f, n[0] * sun[0] + n[1] * sun[1] + n[2] * sun[2]);
|
|
const float n_dot_v = clamp01(n[0] * view[0] + n[1] * view[1] + n[2] * view[2]);
|
|
const float fresnel = fresnel_schlick(n_dot_v);
|
|
const float roughness = slope_roughness(n);
|
|
const float ao = slope_ambient_occlusion(n);
|
|
float halfway[3] = {
|
|
view[0] + sun[0],
|
|
view[1] + sun[1],
|
|
view[2] + sun[2],
|
|
};
|
|
normalize3(halfway);
|
|
const float n_dot_h = std::max(0.0f, n[0] * halfway[0] + n[1] * halfway[1] + n[2] * halfway[2]);
|
|
const float spec = ggx_distribution(n_dot_h, roughness) * day_spec * (0.08f + fresnel * 0.55f);
|
|
const float dist = std::sqrt((wx - g_boat_x) * (wx - g_boat_x) + (wz - g_boat_z) * (wz - g_boat_z));
|
|
const float fog = exp_fog_factor(dist * 0.045f, 0.50f + g_rain * 0.22f);
|
|
const float radial = std::sqrt(static_cast<float>(x * x + (z + row) * (z + row))) / static_cast<float>(half);
|
|
const float fade = 1.0f - smoothstep(0.74f, 1.0f, radial);
|
|
const float depth_tint = clamp01(0.58f + y * 0.45f);
|
|
const float shallow = std::max(0.0f, n[1] - 0.82f) * (1.0f - g_rain * 0.35f);
|
|
const float sky_reflect = fresnel * (0.42f + n[1] * 0.18f);
|
|
const float body_r = 0.004f + 0.012f * shallow;
|
|
const float body_g = 0.075f + 0.055f * shallow + 0.025f * diffuse;
|
|
const float body_b = 0.145f + 0.120f * shallow + 0.050f * diffuse;
|
|
const float deep_r = body_r * (0.68f + depth_tint * 0.20f);
|
|
const float deep_g = body_g * (0.74f + depth_tint * 0.22f);
|
|
const float deep_b = body_b * (0.88f + depth_tint * 0.18f);
|
|
float r = deep_r + horizon[0] * sky_reflect * 0.45f + spec * 0.68f;
|
|
float g = deep_g + horizon[1] * sky_reflect * 0.42f + spec * 0.76f;
|
|
float b = deep_b + horizon[2] * sky_reflect * 0.38f + spec * 0.92f;
|
|
r *= 0.70f + ao * 0.30f;
|
|
g *= 0.72f + ao * 0.28f;
|
|
b *= 0.76f + ao * 0.24f;
|
|
r = r * (1.0f - g_rain * 0.24f) + 0.030f * g_rain;
|
|
g = g * (1.0f - g_rain * 0.20f) + 0.070f * g_rain;
|
|
b = b * (1.0f - g_rain * 0.16f) + 0.105f * g_rain;
|
|
const float lantern = night_factor() * (1.0f - g_rain * 0.35f);
|
|
if (lantern > 0.02f) {
|
|
const float lx = wx - g_boat_x;
|
|
const float lz = wz - g_boat_z;
|
|
const float ldist2 = lx * lx + lz * lz + 2.0f;
|
|
const float point = lantern * std::min(1.0f, 16.0f / ldist2) * std::max(0.0f, n[1]);
|
|
r += point * 1.45f;
|
|
g += point * 0.84f;
|
|
b += point * 0.36f;
|
|
}
|
|
r = horizon[0] * (1.0f - fog) + r * fog;
|
|
g = horizon[1] * (1.0f - fog) + g * fog;
|
|
b = horizon[2] * (1.0f - fog) + b * fog;
|
|
tone_map_rgb(r, g, b, 1.25f + dawn_dusk_factor() * 0.35f);
|
|
glColor4f(r * light, g * light, b * light, 0.92f * fade);
|
|
glVertex3f(wx, y, wz);
|
|
}
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
glColor4f(0.56f, 0.78f, 0.88f, (0.18f + g_boat_speed * 0.018f) * (1.0f - g_rain * 0.62f));
|
|
glLineWidth(1.0f);
|
|
glBegin(GL_LINES);
|
|
for (int i = -30; i <= 30; i += 2) {
|
|
const float wx = g_boat_x + i * 2.2f;
|
|
const float wz = g_boat_z - 12.0f + std::sin(i * 0.7f + static_cast<float>(t)) * 7.0f;
|
|
const float y = wave_height(wx, wz, static_cast<float>(t)) + 0.025f;
|
|
glVertex3f(wx - 0.7f, y, wz);
|
|
glVertex3f(wx + 1.1f, y + 0.01f, wz + 0.25f);
|
|
}
|
|
glEnd();
|
|
glEnable(GL_CULL_FACE);
|
|
}
|
|
|
|
static void draw_marker_geometry(const OceanMarker &marker) {
|
|
const float t = static_cast<float>(now_seconds() - g_start_time);
|
|
const float y = wave_height(marker.x, marker.z, t);
|
|
glPushMatrix();
|
|
glTranslatef(marker.x, y, marker.z);
|
|
glScalef(marker.size, marker.size, marker.size);
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
if (marker.type == 3) {
|
|
glTranslatef(0.0f, -0.18f, 0.0f);
|
|
for (int tier = 0; tier < 4; tier++) {
|
|
const float h0 = tier * 0.38f;
|
|
const float h1 = h0 + 0.42f + tier * 0.12f;
|
|
const float r0 = 2.35f - tier * 0.38f;
|
|
const float r1 = 1.62f - tier * 0.28f;
|
|
glColor3f(0.28f + tier * 0.035f, 0.23f + tier * 0.025f, 0.20f + tier * 0.018f);
|
|
glBegin(GL_QUAD_STRIP);
|
|
for (int i = 0; i <= 18; i++) {
|
|
const float a = static_cast<float>(i) / 18.0f * 6.2831853f;
|
|
const float wobble = 1.0f + std::sin(a * 3.0f + marker.x * 0.01f) * 0.13f;
|
|
glVertex3f(std::cos(a) * r0 * wobble, h0, std::sin(a) * r0 * (1.0f - tier * 0.04f));
|
|
glVertex3f(std::cos(a) * r1 * wobble, h1, std::sin(a) * r1 * (1.0f - tier * 0.04f));
|
|
}
|
|
glEnd();
|
|
}
|
|
glColor3f(0.16f, 0.38f, 0.17f);
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
glVertex3f(0.0f, 1.85f, 0.0f);
|
|
for (int i = 0; i <= 24; i++) {
|
|
const float a = static_cast<float>(i) / 24.0f * 6.2831853f;
|
|
glVertex3f(std::cos(a) * 1.35f, 1.52f + std::sin(i * 0.9f) * 0.05f, std::sin(a) * 1.15f);
|
|
}
|
|
glEnd();
|
|
for (int tree = 0; tree < 5; tree++) {
|
|
const float a = tree * 1.37f + marker.z * 0.01f;
|
|
const float tx = std::cos(a) * (0.45f + 0.18f * tree);
|
|
const float tz = std::sin(a) * (0.38f + 0.16f * tree);
|
|
glColor3f(0.18f, 0.10f, 0.055f);
|
|
glBegin(GL_QUADS);
|
|
glVertex3f(tx - 0.035f, 1.45f, tz);
|
|
glVertex3f(tx + 0.035f, 1.45f, tz);
|
|
glVertex3f(tx + 0.035f, 1.92f, tz);
|
|
glVertex3f(tx - 0.035f, 1.92f, tz);
|
|
glEnd();
|
|
glColor3f(0.20f, 0.46f + tree * 0.018f, 0.20f);
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
glVertex3f(tx, 2.10f, tz);
|
|
for (int i = 0; i <= 14; i++) {
|
|
const float ca = static_cast<float>(i) / 14.0f * 6.2831853f;
|
|
glVertex3f(tx + std::cos(ca) * 0.18f, 1.88f + std::sin(ca) * 0.12f, tz + std::sin(ca) * 0.18f);
|
|
}
|
|
glEnd();
|
|
}
|
|
glPopMatrix();
|
|
return;
|
|
}
|
|
|
|
if (marker.type == 4) {
|
|
glRotatef(-18.0f + std::fmod(marker.x + marker.z, 36.0f), 0, 1, 0);
|
|
glColor3f(0.10f, 0.065f, 0.045f);
|
|
glBegin(GL_QUADS);
|
|
glVertex3f(-1.70f, 0.05f, -0.55f);
|
|
glVertex3f(1.70f, 0.05f, -0.55f);
|
|
glVertex3f(1.15f, -0.35f, 0.72f);
|
|
glVertex3f(-1.15f, -0.35f, 0.72f);
|
|
glVertex3f(-1.70f, 0.05f, -0.55f);
|
|
glVertex3f(-1.15f, -0.35f, 0.72f);
|
|
glVertex3f(-0.58f, -0.52f, 0.45f);
|
|
glVertex3f(-1.05f, -0.12f, -0.46f);
|
|
glVertex3f(1.70f, 0.05f, -0.55f);
|
|
glVertex3f(1.05f, -0.12f, -0.46f);
|
|
glVertex3f(0.58f, -0.52f, 0.45f);
|
|
glVertex3f(1.15f, -0.35f, 0.72f);
|
|
glEnd();
|
|
glColor3f(0.58f, 0.45f, 0.29f);
|
|
for (int mast = -1; mast <= 1; mast++) {
|
|
const float mx = mast * 0.72f;
|
|
glBegin(GL_QUADS);
|
|
glVertex3f(mx - 0.025f, -0.05f, -0.05f);
|
|
glVertex3f(mx + 0.025f, -0.05f, -0.05f);
|
|
glVertex3f(mx + 0.025f, 1.95f + (mast == 0 ? 0.35f : 0.0f), -0.05f);
|
|
glVertex3f(mx - 0.025f, 1.95f + (mast == 0 ? 0.35f : 0.0f), -0.05f);
|
|
glEnd();
|
|
glColor3f(0.77f, 0.72f, 0.62f);
|
|
glBegin(GL_TRIANGLES);
|
|
glVertex3f(mx + 0.05f, 1.65f, -0.04f);
|
|
glVertex3f(mx + 0.05f, 0.45f, -0.04f);
|
|
glVertex3f(mx + 0.58f, 0.68f, -0.04f);
|
|
glEnd();
|
|
glColor3f(0.58f, 0.45f, 0.29f);
|
|
}
|
|
glColor3f(0.03f, 0.025f, 0.02f);
|
|
glBegin(GL_LINES);
|
|
for (int mast = -1; mast <= 1; mast++) {
|
|
const float mx = mast * 0.72f;
|
|
glVertex3f(mx, 1.9f, -0.05f);
|
|
glVertex3f(-1.55f, 0.10f, -0.55f);
|
|
glVertex3f(mx, 1.9f, -0.05f);
|
|
glVertex3f(1.55f, 0.10f, -0.55f);
|
|
}
|
|
glEnd();
|
|
glPopMatrix();
|
|
return;
|
|
}
|
|
|
|
if (marker.type == 2) {
|
|
glColor3f(0.18f, 0.17f, 0.15f);
|
|
glBegin(GL_TRIANGLES);
|
|
glVertex3f(-1.1f, 0.0f, -0.8f);
|
|
glVertex3f(1.0f, 0.0f, -0.7f);
|
|
glVertex3f(0.1f, 0.9f, -0.2f);
|
|
glVertex3f(1.0f, 0.0f, -0.7f);
|
|
glVertex3f(0.8f, 0.0f, 1.0f);
|
|
glVertex3f(0.1f, 0.9f, -0.2f);
|
|
glVertex3f(0.8f, 0.0f, 1.0f);
|
|
glVertex3f(-0.9f, 0.0f, 0.8f);
|
|
glVertex3f(0.1f, 0.9f, -0.2f);
|
|
glVertex3f(-0.9f, 0.0f, 0.8f);
|
|
glVertex3f(-1.1f, 0.0f, -0.8f);
|
|
glVertex3f(0.1f, 0.9f, -0.2f);
|
|
glEnd();
|
|
glPopMatrix();
|
|
return;
|
|
}
|
|
|
|
glColor3f(marker.type == 1 ? 0.95f : 0.82f, marker.type == 1 ? 0.78f : 0.08f, marker.type == 1 ? 0.18f : 0.06f);
|
|
glBegin(GL_QUADS);
|
|
glVertex3f(-0.35f, 0.05f, -0.35f);
|
|
glVertex3f(0.35f, 0.05f, -0.35f);
|
|
glVertex3f(0.35f, 0.65f, -0.35f);
|
|
glVertex3f(-0.35f, 0.65f, -0.35f);
|
|
glVertex3f(0.35f, 0.05f, 0.35f);
|
|
glVertex3f(-0.35f, 0.05f, 0.35f);
|
|
glVertex3f(-0.35f, 0.65f, 0.35f);
|
|
glVertex3f(0.35f, 0.65f, 0.35f);
|
|
glVertex3f(-0.35f, 0.05f, 0.35f);
|
|
glVertex3f(-0.35f, 0.05f, -0.35f);
|
|
glVertex3f(-0.35f, 0.65f, -0.35f);
|
|
glVertex3f(-0.35f, 0.65f, 0.35f);
|
|
glVertex3f(0.35f, 0.05f, -0.35f);
|
|
glVertex3f(0.35f, 0.05f, 0.35f);
|
|
glVertex3f(0.35f, 0.65f, 0.35f);
|
|
glVertex3f(0.35f, 0.65f, -0.35f);
|
|
glEnd();
|
|
|
|
glColor3f(0.88f, 0.88f, 0.78f);
|
|
glBegin(GL_QUADS);
|
|
glVertex3f(-0.07f, 0.65f, -0.07f);
|
|
glVertex3f(0.07f, 0.65f, -0.07f);
|
|
glVertex3f(0.07f, 1.45f, -0.07f);
|
|
glVertex3f(-0.07f, 1.45f, -0.07f);
|
|
glVertex3f(0.07f, 0.65f, 0.07f);
|
|
glVertex3f(-0.07f, 0.65f, 0.07f);
|
|
glVertex3f(-0.07f, 1.45f, 0.07f);
|
|
glVertex3f(0.07f, 1.45f, 0.07f);
|
|
glEnd();
|
|
|
|
if (marker.type == 1) {
|
|
const float glow = 0.35f + night_factor() * 0.65f;
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
glColor4f(1.0f, 0.70f, 0.20f, 0.45f * glow);
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
glVertex3f(0.0f, 1.55f, 0.0f);
|
|
for (int i = 0; i <= 24; i++) {
|
|
const float a = static_cast<float>(i) / 24.0f * 6.2831853f;
|
|
glVertex3f(std::cos(a) * 0.55f, 1.55f + std::sin(a) * 0.55f, 0.0f);
|
|
}
|
|
glEnd();
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
|
|
glPopMatrix();
|
|
}
|
|
|
|
static void draw_world_markers() {
|
|
glDisable(GL_CULL_FACE);
|
|
for (const auto &chunk : g_marker_chunks) {
|
|
for (const OceanMarker &marker : chunk.second) {
|
|
const float dx = marker.x - g_boat_x;
|
|
const float dz = marker.z - g_boat_z;
|
|
if (dx * dx + dz * dz <= 430.0f * 430.0f) {
|
|
draw_marker_geometry(marker);
|
|
}
|
|
}
|
|
}
|
|
glEnable(GL_CULL_FACE);
|
|
}
|
|
|
|
static void draw_boat() {
|
|
const double t = now_seconds() - g_start_time;
|
|
const float bob = wave_height(g_boat_x, g_boat_z, static_cast<float>(t)) + 0.20f;
|
|
glPushMatrix();
|
|
glTranslatef(g_boat_x, bob, g_boat_z);
|
|
glRotatef(g_boat_yaw * 57.2957795f, 0, 1, 0);
|
|
glRotatef(std::sin(static_cast<float>(t) * 2.2f + g_boat_x) * 2.2f, 0, 0, 1);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
glColor3f(0.30f, 0.13f, 0.055f);
|
|
glBegin(GL_QUADS);
|
|
glVertex3f(-1.25f, 0.10f, -1.80f);
|
|
glVertex3f(1.25f, 0.10f, -1.80f);
|
|
glVertex3f(0.82f, 0.02f, 1.85f);
|
|
glVertex3f(-0.82f, 0.02f, 1.85f);
|
|
glVertex3f(-0.82f, 0.02f, 1.85f);
|
|
glVertex3f(0.82f, 0.02f, 1.85f);
|
|
glVertex3f(0.44f, -0.45f, 1.35f);
|
|
glVertex3f(-0.44f, -0.45f, 1.35f);
|
|
glVertex3f(-1.25f, 0.10f, -1.80f);
|
|
glVertex3f(-0.82f, 0.02f, 1.85f);
|
|
glVertex3f(-0.44f, -0.45f, 1.35f);
|
|
glVertex3f(-0.72f, -0.36f, -1.40f);
|
|
glVertex3f(1.25f, 0.10f, -1.80f);
|
|
glVertex3f(0.72f, -0.36f, -1.40f);
|
|
glVertex3f(0.44f, -0.45f, 1.35f);
|
|
glVertex3f(0.82f, 0.02f, 1.85f);
|
|
glEnd();
|
|
|
|
glColor3f(0.72f, 0.58f, 0.38f);
|
|
glBegin(GL_QUADS);
|
|
glVertex3f(-0.08f, 0.00f, -0.45f);
|
|
glVertex3f(0.08f, 0.00f, -0.45f);
|
|
glVertex3f(0.08f, 1.85f, -0.45f);
|
|
glVertex3f(-0.08f, 1.85f, -0.45f);
|
|
glEnd();
|
|
|
|
glColor3f(0.88f, 0.86f, 0.76f);
|
|
glBegin(GL_TRIANGLES);
|
|
glVertex3f(0.10f, 1.70f, -0.45f);
|
|
glVertex3f(0.10f, 0.28f, -0.45f);
|
|
glVertex3f(1.25f, 0.34f, -0.45f);
|
|
glEnd();
|
|
|
|
const float lantern = night_factor() * (1.0f - g_rain * 0.25f);
|
|
if (lantern > 0.02f) {
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
glDisable(GL_CULL_FACE);
|
|
glColor4f(1.0f, 0.62f, 0.24f, 0.95f * lantern);
|
|
glBegin(GL_QUADS);
|
|
glVertex3f(-0.18f, 0.75f, 0.24f);
|
|
glVertex3f(0.18f, 0.75f, 0.24f);
|
|
glVertex3f(0.18f, 1.12f, 0.24f);
|
|
glVertex3f(-0.18f, 1.12f, 0.24f);
|
|
glEnd();
|
|
glColor4f(1.0f, 0.54f, 0.18f, 0.20f * lantern);
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
glVertex3f(0.0f, 0.94f, 0.26f);
|
|
for (int i = 0; i <= 32; i++) {
|
|
const float a = static_cast<float>(i) / 32.0f * 6.2831853f;
|
|
glVertex3f(std::cos(a) * 1.1f, 0.94f + std::sin(a) * 0.65f, 0.28f);
|
|
}
|
|
glEnd();
|
|
glEnable(GL_CULL_FACE);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
|
|
glPopMatrix();
|
|
}
|
|
|
|
static void draw_rain() {
|
|
if (g_rain <= 0.02f) {
|
|
return;
|
|
}
|
|
const float t = static_cast<float>(now_seconds() - g_start_time);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_CULL_FACE);
|
|
glColor4f(0.66f, 0.78f, 0.86f, 0.42f * g_rain);
|
|
glLineWidth(1.0f);
|
|
glBegin(GL_LINES);
|
|
for (int i = 0; i < 150; i++) {
|
|
const float seed = static_cast<float>(i) * 12.9898f;
|
|
const float rx = g_boat_x + std::fmod(std::sin(seed) * 43758.5f, 64.0f) - 32.0f;
|
|
const float rz = g_boat_z + std::fmod(std::cos(seed * 1.31f) * 21758.5f, 64.0f) - 32.0f;
|
|
const float fall = std::fmod(t * 19.0f + i * 0.37f, 9.0f);
|
|
glVertex3f(rx, 8.0f - fall, rz);
|
|
glVertex3f(rx + 0.26f, 6.8f - fall, rz - 0.36f);
|
|
}
|
|
glEnd();
|
|
glEnable(GL_CULL_FACE);
|
|
}
|
|
|
|
static void draw_screen_disc(float x, float y, float radius_x, float radius_y, float r, float g, float b, float alpha) {
|
|
if (alpha <= 0.001f) {
|
|
return;
|
|
}
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
glColor4f(r, g, b, alpha);
|
|
glVertex2f(x, y);
|
|
glColor4f(r, g, b, 0.0f);
|
|
for (int i = 0; i <= 48; i++) {
|
|
const float a = static_cast<float>(i) / 48.0f * 6.2831853f;
|
|
glVertex2f(x + std::cos(a) * radius_x, y + std::sin(a) * radius_y);
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
static void draw_bloom_overlay() {
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glOrtho(-1, 1, -1, 1, -1, 1);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_FOG);
|
|
glDisable(GL_CULL_FACE);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
|
|
const float sun_angle = (g_day_time - 0.25f) * 6.2831853f;
|
|
const float sx = std::cos(sun_angle) * 0.68f;
|
|
const float sy = std::sin(sun_angle) * 0.74f;
|
|
const float body_y = sy < -0.05f ? -sy : sy;
|
|
const float daylight = smoothstep(-0.05f, 0.28f, sun_height()) * (1.0f - g_rain * 0.55f);
|
|
draw_screen_disc(sx, body_y, 0.24f, 0.24f, 1.0f, 0.68f, 0.28f, 0.17f * daylight);
|
|
draw_screen_disc(sx, body_y, 0.48f, 0.34f, 1.0f, 0.58f, 0.22f, 0.07f * daylight);
|
|
|
|
const float golden = dawn_dusk_factor() * (1.0f - g_rain * 0.45f);
|
|
draw_screen_disc(0.0f, -0.42f, 1.25f, 0.28f, 1.0f, 0.48f, 0.18f, 0.11f * golden);
|
|
|
|
const float lantern = night_factor() * (1.0f - g_rain * 0.20f);
|
|
draw_screen_disc(0.0f, -0.18f, 0.28f, 0.18f, 1.0f, 0.48f, 0.12f, 0.12f * lantern);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glEnable(GL_CULL_FACE);
|
|
glEnable(GL_FOG);
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
}
|
|
|
|
Bool php_ocean_init(String title, Int width, Int height) {
|
|
SetProcessDPIAware();
|
|
SetConsoleOutputCP(65001);
|
|
g_width = static_cast<int>(width);
|
|
g_height = static_cast<int>(height);
|
|
g_start_time = now_seconds();
|
|
|
|
WNDCLASS wc{};
|
|
wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = wnd_proc;
|
|
wc.hInstance = GetModuleHandle(nullptr);
|
|
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
|
wc.lpszClassName = "TypePhpOceanWindow";
|
|
RegisterClass(&wc);
|
|
|
|
g_hwnd = CreateWindowEx(
|
|
0, wc.lpszClassName, title.data(),
|
|
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, g_width, g_height,
|
|
nullptr, nullptr, wc.hInstance, nullptr);
|
|
if (!g_hwnd) {
|
|
return false;
|
|
}
|
|
|
|
g_hdc = GetDC(g_hwnd);
|
|
PIXELFORMATDESCRIPTOR pfd{};
|
|
pfd.nSize = sizeof(pfd);
|
|
pfd.nVersion = 1;
|
|
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
|
pfd.iPixelType = PFD_TYPE_RGBA;
|
|
pfd.cColorBits = 32;
|
|
pfd.cDepthBits = 24;
|
|
pfd.cAlphaBits = 8;
|
|
pfd.iLayerType = PFD_MAIN_PLANE;
|
|
const int pf = ChoosePixelFormat(g_hdc, &pfd);
|
|
SetPixelFormat(g_hdc, pf, &pfd);
|
|
|
|
g_glrc = wglCreateContext(g_hdc);
|
|
wglMakeCurrent(g_hdc, g_glrc);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glEnable(GL_CULL_FACE);
|
|
glClearColor(0.42f, 0.67f, 0.88f, 1.0f);
|
|
enable_mouse_capture();
|
|
return true;
|
|
}
|
|
|
|
void php_ocean_shutdown() {
|
|
disable_mouse_capture();
|
|
g_marker_chunks.clear();
|
|
g_pending_markers.clear();
|
|
if (g_glrc) {
|
|
wglMakeCurrent(nullptr, nullptr);
|
|
wglDeleteContext(g_glrc);
|
|
g_glrc = nullptr;
|
|
}
|
|
if (g_hwnd && g_hdc) {
|
|
ReleaseDC(g_hwnd, g_hdc);
|
|
g_hdc = nullptr;
|
|
}
|
|
if (g_hwnd) {
|
|
DestroyWindow(g_hwnd);
|
|
g_hwnd = nullptr;
|
|
}
|
|
}
|
|
|
|
Bool php_ocean_should_close() {
|
|
return g_should_close;
|
|
}
|
|
|
|
void php_ocean_poll_events() {
|
|
MSG msg;
|
|
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
Bool php_ocean_key_pressed(Int key) {
|
|
const int k = static_cast<int>(key);
|
|
return k >= 0 && k < 256 && g_keys[k];
|
|
}
|
|
|
|
Float php_ocean_mouse_delta_x() {
|
|
const double value = g_mouse_dx;
|
|
g_mouse_dx = 0.0;
|
|
return value;
|
|
}
|
|
|
|
Float php_ocean_mouse_delta_y() {
|
|
const double value = g_mouse_dy;
|
|
g_mouse_dy = 0.0;
|
|
return value;
|
|
}
|
|
|
|
Float php_ocean_get_time() {
|
|
return now_seconds();
|
|
}
|
|
|
|
void php_ocean_sleep(Int milliseconds) {
|
|
Sleep(static_cast<DWORD>(std::max(0, static_cast<int>(milliseconds))));
|
|
}
|
|
|
|
Bool php_ocean_confirm_exit() {
|
|
disable_mouse_capture();
|
|
const int result = MessageBoxW(
|
|
g_hwnd,
|
|
L"\x662f\x5426\x9000\x51fa\x6d77\x6d0b\x573a\x666f\xff1f",
|
|
L"\x786e\x8ba4\x9000\x51fa",
|
|
MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2);
|
|
enable_mouse_capture();
|
|
g_mouse_dx = 0.0;
|
|
g_mouse_dy = 0.0;
|
|
return result == IDYES;
|
|
}
|
|
|
|
void php_ocean_set_boat(Float x, Float z, Float yaw, Float speed) {
|
|
g_boat_x = static_cast<float>(x);
|
|
g_boat_z = static_cast<float>(z);
|
|
g_boat_yaw = static_cast<float>(yaw);
|
|
g_boat_speed = static_cast<float>(speed);
|
|
}
|
|
|
|
void php_ocean_set_camera(Float yaw, Float pitch, Float distance) {
|
|
g_camera_yaw = static_cast<float>(yaw);
|
|
g_camera_pitch = static_cast<float>(pitch);
|
|
g_camera_distance = std::max(8.0f, std::min(42.0f, static_cast<float>(distance)));
|
|
}
|
|
|
|
void php_ocean_set_environment(Float day_time, Int weather, Float weather_mix, Float rain_amount) {
|
|
g_day_time = clamp01(static_cast<float>(day_time));
|
|
g_weather = std::max(0, std::min(2, static_cast<int>(weather)));
|
|
g_weather_mix = clamp01(static_cast<float>(weather_mix));
|
|
g_rain = clamp01(static_cast<float>(rain_amount));
|
|
}
|
|
|
|
void php_ocean_begin_chunk(Int chunk_x, Int chunk_z) {
|
|
g_pending_chunk = ChunkKey{static_cast<int>(chunk_x), static_cast<int>(chunk_z)};
|
|
g_pending_markers.clear();
|
|
g_has_pending_chunk = true;
|
|
}
|
|
|
|
void php_ocean_add_marker(Float x, Float z, Int type, Float size) {
|
|
if (!g_has_pending_chunk) {
|
|
return;
|
|
}
|
|
OceanMarker marker{};
|
|
marker.x = static_cast<float>(x);
|
|
marker.z = static_cast<float>(z);
|
|
marker.type = std::max(0, std::min(2, static_cast<int>(type)));
|
|
marker.size = std::max(0.35f, std::min(4.0f, static_cast<float>(size)));
|
|
g_pending_markers.push_back(marker);
|
|
}
|
|
|
|
void php_ocean_commit_chunk(Int chunk_x, Int chunk_z) {
|
|
const ChunkKey key{static_cast<int>(chunk_x), static_cast<int>(chunk_z)};
|
|
if (!g_has_pending_chunk) {
|
|
return;
|
|
}
|
|
g_marker_chunks[key] = g_pending_markers;
|
|
g_pending_markers.clear();
|
|
g_pending_chunk = key;
|
|
g_has_pending_chunk = false;
|
|
}
|
|
|
|
void php_ocean_remove_chunk(Int chunk_x, Int chunk_z) {
|
|
const ChunkKey key{static_cast<int>(chunk_x), static_cast<int>(chunk_z)};
|
|
g_marker_chunks.erase(key);
|
|
}
|
|
|
|
void php_ocean_render_frame() {
|
|
SetWindowTextA(g_hwnd, "TypePHP Ocean Demo - OpenGL");
|
|
glViewport(0, 0, g_width, std::max(1, g_height));
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
draw_sky();
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
set_perspective(62.0, static_cast<double>(g_width) / std::max(1, g_height), 0.1, 260.0);
|
|
|
|
draw_skybox();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
glRotatef(g_camera_pitch * 57.2957795f, 1, 0, 0);
|
|
glRotatef(g_camera_yaw * 57.2957795f, 0, 1, 0);
|
|
glTranslatef(-g_boat_x, -4.2f, -g_boat_z - g_camera_distance);
|
|
|
|
const GLfloat fog_color[] = {0.38f + g_rain * 0.04f, 0.52f + g_rain * 0.02f, 0.61f + g_rain * 0.03f, 1.0f};
|
|
glEnable(GL_FOG);
|
|
glFogfv(GL_FOG_COLOR, fog_color);
|
|
glFogi(GL_FOG_MODE, GL_EXP2);
|
|
glFogf(GL_FOG_DENSITY, 0.010f + g_rain * 0.006f + active_weather_strength() * 0.003f);
|
|
|
|
draw_water();
|
|
draw_world_markers();
|
|
draw_boat();
|
|
draw_rain();
|
|
|
|
glDisable(GL_FOG);
|
|
draw_bloom_overlay();
|
|
SwapBuffers(g_hdc);
|
|
}
|
|
|