import type { Client } from "$/client/client.ts"; import { begin_mode_3d, clear_background, end_mode_3d, update_lightmap } from "$/client/renderer/mod.ts"; import { daylight } from "$/common/time.ts"; import { Hud } from "$/client/gui/hud.ts"; import { DebugOverlay } from "$/client/gui/debug_overlay.ts"; import { LevelRenderer } from "./level_renderer.ts"; // the sky at noon and in the middle of the night const DAY_SKY = [0.69, 0.8, 1]; const NIGHT_SKY = [0.02, 0.03, 0.08]; // minecraft's darkest sky: moonlight still lights things a little const NIGHT_SKY_LIGHT = 0.2; // draws a frame, like minecraft's GameRenderer: the level from the camera, then the hud and screens on top export class GameRenderer { level_renderer = new LevelRenderer(); hud = new Hud(); debug_overlay = new DebugOverlay(); // what the lightmap was last made for, so it's only rebuilt when the light changes #lightmap_daylight = -1; // sky color and sky light for the time of day #setup_sky(client: Client, partial_tick: number) { const light = daylight(client.level.time + partial_tick); const [r, g, b] = DAY_SKY.map((day, i) => NIGHT_SKY[i] + (day - NIGHT_SKY[i]) * light); clear_background(r, g, b, 1); if (Math.abs(light - this.#lightmap_daylight) > 0.001) { this.#lightmap_daylight = light; update_lightmap(NIGHT_SKY_LIGHT + (1 - NIGHT_SKY_LIGHT) * light); } } // partial_tick is how far this frame is between the last tick and the next, entities are drawn in between render(client: Client, partial_tick: number) { const camera = client.camera; camera.setup(client.player, partial_tick); this.#setup_sky(client, partial_tick); begin_mode_3d(camera); this.level_renderer.render_opaque(client.level, camera); this.level_renderer.render_destroy_progress(client.game_mode); this.level_renderer.render_entities(client.level, client.player, partial_tick); this.level_renderer.render_translucent(client.level, camera); end_mode_3d(); this.hud.render(client); client.screen?.on_render(); if (client.debugging) { this.debug_overlay.render(client); } } }