From 244f0eb741a36aa6188cde1a9fc7d0bd4d1a2a0f Mon Sep 17 00:00:00 2001 From: paulaboks Date: Wed, 11 Mar 2026 16:55:14 -0300 Subject: [PATCH] nothing works --- client/renderer/core.ts | 457 ++++++++++++++++++++++++-------- client/renderer/math.ts | 68 ++++- client/systems/render_system.ts | 44 ++- 3 files changed, 456 insertions(+), 113 deletions(-) diff --git a/client/renderer/core.ts b/client/renderer/core.ts index a466d0a..09e78c4 100644 --- a/client/renderer/core.ts +++ b/client/renderer/core.ts @@ -1,21 +1,26 @@ import { Camera } from "../components/camera.ts"; +import { mat4_mul, mat4_perspective, mat4_view } from "./math.ts"; const MAX_SPRITES = 10000; const VERTS_PER_SPRITE = 6; -const FLOATS_PER_VERT = 8; +const FLOATS_PER_VERT = 9; export let gl: WebGLRenderingContext; export let canvas: HTMLCanvasElement; let program: WebGLProgram; let buffer: WebGLBuffer; -const default_camera = new Camera(); -let camera: Camera = default_camera; +// const default_camera = new Camera(); +// let camera: Camera = default_camera; +// +// let camera_pos_loc: WebGLUniformLocation | null; +// let camera_zoom_loc: WebGLUniformLocation | null; +// let camera_rot_loc: WebGLUniformLocation | null; +// let camera_offset_loc: WebGLUniformLocation | null; -let camera_pos_loc: WebGLUniformLocation | null; -let camera_zoom_loc: WebGLUniformLocation | null; -let camera_rot_loc: WebGLUniformLocation | null; -let camera_offset_loc: WebGLUniformLocation | null; +export const projection = new Float32Array(16); +export const view = new Float32Array(16); +export const mvp_matrix = new Float32Array(16); const vertex_data = new Float32Array(MAX_SPRITES * VERTS_PER_SPRITE * FLOATS_PER_VERT); let vert_index = 0; @@ -23,64 +28,56 @@ let vert_index = 0; let pos_loc: GLint; let uv_loc: GLint; let resolution_loc: WebGLUniformLocation | null; -let _texture_loc: WebGLUniformLocation | null; +let texture_loc: WebGLUniformLocation | null; +let mvp_loc: WebGLUniformLocation | null; +let col_diffuse_loc: WebGLUniformLocation | null; let current_texture: WebGLTexture | null = null; export let white_tex: WebGLTexture | null = null; -const vertex_src = ` -attribute vec2 aPos; -attribute vec2 aUV; -attribute vec4 aColor; +export const camera = { + x: 3, + y: 3, + z: 3, -varying vec2 vUV; -varying vec4 vColor; + pitch: 0, + yaw: 0, + roll: 0, -uniform vec2 uResolution; -uniform vec2 uCameraPos; -uniform float uCameraZoom; -uniform float uCameraRot; -uniform vec2 uCameraOffset; + fov: Math.PI / 3, + near: 0.1, + far: 1000, +}; -void main(){ +let mode3d = false; +let active_camera = camera; - // world → camera space - vec2 pos = aPos - uCameraPos; +const vertex_src = `#version 300 es +precision mediump float; +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec4 vertexColor; +out vec2 fragTexCoord; +out vec4 fragColor; +uniform mat4 mvp; - // rotation - float c = cos(uCameraRot); - float s = sin(uCameraRot); - pos = vec2( - pos.x * c - pos.y * s, - pos.x * s + pos.y * c - ); - - // zoom - pos *= uCameraZoom; - - // screen offset (center camera) - pos += uCameraOffset; - - // convert to clip space - vec2 zero = pos / uResolution; - vec2 clip = zero * 2.0 - 1.0; - - gl_Position = vec4(clip * vec2(1.0,-1.0),0.0,1.0); - - vUV = aUV; - vColor = aColor; +void main() { + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + gl_Position = mvp*vec4(vertexPosition, 1.0); } `; -const fragment_src = ` +const fragment_src = `#version 300 es precision mediump float; -varying vec2 vUV; -varying vec4 vColor; -uniform sampler2D uTex; - +in vec2 fragTexCoord; +in vec4 fragColor; +out vec4 finalColor; +uniform sampler2D texture0; +uniform vec4 colDiffuse; void main() { - vec4 texColor = texture2D(uTex, vUV); - gl_FragColor = texColor * vColor; + vec4 texelColor = texture(texture0, fragTexCoord); + finalColor = texelColor*colDiffuse*fragColor; } `; @@ -88,9 +85,10 @@ export function init_window(canvas_element: HTMLCanvasElement) { canvas = canvas_element; canvas.width = 1800; canvas.height = 900; - const ctx = canvas.getContext("webgl"); + + const ctx = canvas.getContext("webgl2"); if (!ctx) { - throw new Error("WebGL not supported"); + throw new Error("WebGL2 not supported"); } gl = ctx; @@ -98,41 +96,41 @@ export function init_window(canvas_element: HTMLCanvasElement) { program = create_program(vertex_src, fragment_src); buffer = gl.createBuffer()!; - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); const stride = FLOATS_PER_VERT * 4; - pos_loc = gl.getAttribLocation(program, "aPos"); + pos_loc = gl.getAttribLocation(program, "vertexPosition"); gl.enableVertexAttribArray(pos_loc); - gl.vertexAttribPointer(pos_loc, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(pos_loc, 3, gl.FLOAT, false, stride, 0); - uv_loc = gl.getAttribLocation(program, "aUV"); + uv_loc = gl.getAttribLocation(program, "vertexTexCoord"); gl.enableVertexAttribArray(uv_loc); - gl.vertexAttribPointer(uv_loc, 2, gl.FLOAT, false, stride, 8); + gl.vertexAttribPointer(uv_loc, 2, gl.FLOAT, false, stride, 12); - const color_loc = gl.getAttribLocation(program, "aColor"); + const color_loc = gl.getAttribLocation(program, "vertexColor"); gl.enableVertexAttribArray(color_loc); - gl.vertexAttribPointer(color_loc, 4, gl.FLOAT, false, FLOATS_PER_VERT * 4, 16); + gl.vertexAttribPointer(color_loc, 4, gl.FLOAT, false, stride, 20); - resolution_loc = gl.getUniformLocation(program, "uResolution"); - _texture_loc = gl.getUniformLocation(program, "uTex"); - - camera_pos_loc = gl.getUniformLocation(program, "uCameraPos"); - camera_zoom_loc = gl.getUniformLocation(program, "uCameraZoom"); - camera_rot_loc = gl.getUniformLocation(program, "uCameraRot"); - camera_offset_loc = gl.getUniformLocation(program, "uCameraOffset"); + mvp_loc = gl.getUniformLocation(program, "mvp"); + texture_loc = gl.getUniformLocation(program, "texture0"); + col_diffuse_loc = gl.getUniformLocation(program, "colDiffuse"); gl.useProgram(program); - gl.uniform2f(resolution_loc, canvas.width, canvas.height); gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + gl.disable(gl.CULL_FACE); + create_white_texture(); + + update_mvp(canvas.width, canvas.height); } export function begin_drawing() { + update_2d_mvp(); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); vert_index = 0; } @@ -140,13 +138,48 @@ export function end_drawing() { flush_batch(); } +export const ortho_matrix = new Float32Array(16); + +export function update_2d_mvp() { + const w = canvas.width; + const h = canvas.height; + const l = 0, r = w, t = 0, b = h, n = -1, f = 1; + + ortho_matrix[0] = 2 / (r - l); + ortho_matrix[1] = 0; + ortho_matrix[2] = 0; + ortho_matrix[3] = 0; + + ortho_matrix[4] = 0; + ortho_matrix[5] = 2 / (t - b); + ortho_matrix[6] = 0; + ortho_matrix[7] = 0; + + ortho_matrix[8] = 0; + ortho_matrix[9] = 0; + ortho_matrix[10] = -2 / (f - n); + ortho_matrix[11] = 0; + + ortho_matrix[12] = -(r + l) / (r - l); + ortho_matrix[13] = -(t + b) / (t - b); + ortho_matrix[14] = -(f + n) / (f - n); + ortho_matrix[15] = 1; +} + export function begin_mode_2d(new_camera: Camera) { - camera = new_camera; + mode3d = false; + + gl.disable(gl.DEPTH_TEST); + + vert_index = 0; + + update_2d_mvp(); + gl.uniformMatrix4fv(mvp_loc, false, ortho_matrix); } export function end_mode_2d() { flush_batch(); - camera = default_camera; + // camera = default_camera; } export function begin_clip(x: number, y: number, width: number, height: number) { @@ -174,21 +207,20 @@ export function flush_batch() { gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData(gl.ARRAY_BUFFER, vertex_data.subarray(0, vert_index), gl.STREAM_DRAW); - gl.useProgram(program); + if (mode3d) { + gl.uniformMatrix4fv(mvp_loc, false, mvp_matrix); + } else { + gl.uniformMatrix4fv(mvp_loc, false, ortho_matrix); + } - // const stride = FLOATS_PER_VERT * 4; - // gl.enableVertexAttribArray(pos_loc); - // gl.vertexAttribPointer(pos_loc, 2, gl.FLOAT, false, stride, 0); - // gl.enableVertexAttribArray(uv_loc); - // gl.vertexAttribPointer(uv_loc, 2, gl.FLOAT, false, stride, 8); - - gl.uniform2f(camera_pos_loc, Math.floor(camera.x), Math.floor(camera.y)); - gl.uniform1f(camera_zoom_loc, camera.zoom); - gl.uniform1f(camera_rot_loc, camera.rotation); - gl.uniform2f(camera_offset_loc, camera.offset_x, camera.offset_y); + gl.uniform4f(col_diffuse_loc, 1, 1, 1, 1); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, current_texture); - gl.drawArrays(gl.TRIANGLES, 0, vert_index / 8); + gl.uniform1i(texture_loc, 0); + + gl.drawArrays(gl.TRIANGLES, 0, vert_index / FLOATS_PER_VERT); + vert_index = 0; } @@ -209,20 +241,71 @@ export function push_quad( const x2 = dx + dw; const y2 = dy + dh; - // deno-fmt-ignore - const v = [ - dx, dy, u0, v0, r, g, b, a, - x2, dy, u1, v0, r, g, b, a, - dx, y2, u0, v1, r, g, b, a, + let i = vert_index; - x2, dy, u1, v0, r, g, b, a, - x2, y2, u1, v1, r, g, b, a, - dx, y2, u0, v1, r, g, b, a, - ]; + // triangle 1 + vertex_data[i++] = dx; + vertex_data[i++] = dy; + vertex_data[i++] = 0; + vertex_data[i++] = u0; + vertex_data[i++] = v0; + vertex_data[i++] = r; + vertex_data[i++] = g; + vertex_data[i++] = b; + vertex_data[i++] = a; - for (let i = 0; i < v.length; i += 1) { - vertex_data[vert_index++] = v[i]; - } + vertex_data[i++] = x2; + vertex_data[i++] = dy; + vertex_data[i++] = 0; + vertex_data[i++] = u1; + vertex_data[i++] = v0; + vertex_data[i++] = r; + vertex_data[i++] = g; + vertex_data[i++] = b; + vertex_data[i++] = a; + + vertex_data[i++] = dx; + vertex_data[i++] = y2; + vertex_data[i++] = 0; + vertex_data[i++] = u0; + vertex_data[i++] = v1; + vertex_data[i++] = r; + vertex_data[i++] = g; + vertex_data[i++] = b; + vertex_data[i++] = a; + + // triangle 2 + vertex_data[i++] = x2; + vertex_data[i++] = dy; + vertex_data[i++] = 0; + vertex_data[i++] = u1; + vertex_data[i++] = v0; + vertex_data[i++] = r; + vertex_data[i++] = g; + vertex_data[i++] = b; + vertex_data[i++] = a; + + vertex_data[i++] = x2; + vertex_data[i++] = y2; + vertex_data[i++] = 0; + vertex_data[i++] = u1; + vertex_data[i++] = v1; + vertex_data[i++] = r; + vertex_data[i++] = g; + vertex_data[i++] = b; + vertex_data[i++] = a; + + vertex_data[i++] = dx; + vertex_data[i++] = y2; + vertex_data[i++] = 0; + vertex_data[i++] = u0; + vertex_data[i++] = v1; + vertex_data[i++] = r; + vertex_data[i++] = g; + vertex_data[i++] = b; + vertex_data[i++] = a; + + vert_index = i; } export function resize_canvas() { @@ -238,7 +321,8 @@ export function resize_canvas() { gl.viewport(0, 0, width, height); gl.useProgram(program); - gl.uniform2f(resolution_loc, width, height); + // gl.uniform2f(resolution_loc, width, height); + update_mvp(canvas.width, canvas.height); } } @@ -250,23 +334,34 @@ export function set_current_texture(texture: WebGLTexture) { current_texture = texture; } -function create_shader(type: number, src: string): WebGLShader { - const s = gl.createShader(type)!; - gl.shaderSource(s, src); - gl.compileShader(s); - return s; +function compile_shader(type: number, src: string) { + const shader = gl.createShader(type)!; + + gl.shaderSource(shader, src); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + console.error(gl.getShaderInfoLog(shader)); + throw new Error("Shader compile failed"); + } + + return shader; } -function create_program(vs: string, fs: string): WebGLProgram { - const program = gl.createProgram(); +function create_program(vs_src: string, fs_src: string) { + const vs = compile_shader(gl.VERTEX_SHADER, vs_src); + const fs = compile_shader(gl.FRAGMENT_SHADER, fs_src); - const v = create_shader(gl.VERTEX_SHADER, vs); - const f = create_shader(gl.FRAGMENT_SHADER, fs); - - gl.attachShader(program, v); - gl.attachShader(program, f); + const program = gl.createProgram()!; + gl.attachShader(program, vs); + gl.attachShader(program, fs); gl.linkProgram(program); + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + console.error(gl.getProgramInfoLog(program)); + throw new Error("Program link failed"); + } + return program; } @@ -283,3 +378,151 @@ function create_white_texture() { white_tex = tex; } + +function update_mvp(width: number, height: number) { + const l = 0; + const r = width; + const b = height; + const t = 0; + const n = -1; + const f = 1; + + mvp_matrix[0] = 2 / (r - l); + mvp_matrix[1] = 0; + mvp_matrix[2] = 0; + mvp_matrix[3] = 0; + + mvp_matrix[4] = 0; + mvp_matrix[5] = 2 / (t - b); + mvp_matrix[6] = 0; + mvp_matrix[7] = 0; + + mvp_matrix[8] = 0; + mvp_matrix[9] = 0; + mvp_matrix[10] = -2 / (f - n); + mvp_matrix[11] = 0; + + mvp_matrix[12] = -(r + l) / (r - l); + mvp_matrix[13] = -(t + b) / (t - b); + mvp_matrix[14] = -(f + n) / (f - n); + mvp_matrix[15] = 1; +} + +export function push_cube( + x: number, + y: number, + z: number, + w: number, + h: number, + d: number, + r = 1, + g = 1, + b = 1, + a = 1, +) { + set_current_texture(white_tex!); + + const x2 = x + w; + const y2 = y + h; + const z2 = z + d; + + const u0 = 0, v0 = 0; + const u1 = 1, v1 = 1; + + let i = vert_index; + + function v(px: number, py: number, pz: number, u: number, vv: number) { + vertex_data[i++] = px; + vertex_data[i++] = py; + vertex_data[i++] = pz; + vertex_data[i++] = u; + vertex_data[i++] = vv; + vertex_data[i++] = r; + vertex_data[i++] = g; + vertex_data[i++] = b; + vertex_data[i++] = a; + } + + v(x, y, z2, u0, v0); + v(x2, y, z2, u1, v0); + v(x, y2, z2, u0, v1); + v(x2, y, z2, u1, v0); + v(x2, y2, z2, u1, v1); + v(x, y2, z2, u0, v1); + + v(x2, y, z, u0, v0); + v(x, y, z, u1, v0); + v(x2, y2, z, u0, v1); + v(x, y, z, u1, v0); + v(x, y2, z, u1, v1); + v(x2, y2, z, u0, v1); + + v(x, y, z, u0, v0); + v(x, y, z2, u1, v0); + v(x, y2, z, u0, v1); + v(x, y, z2, u1, v0); + v(x, y2, z2, u1, v1); + v(x, y2, z, u0, v1); + + v(x2, y, z2, u0, v0); + v(x2, y, z, u1, v0); + v(x2, y2, z2, u0, v1); + v(x2, y, z, u1, v0); + v(x2, y2, z, u1, v1); + v(x2, y2, z2, u0, v1); + + v(x, y2, z2, u0, v0); + v(x2, y2, z2, u1, v0); + v(x, y2, z, u0, v1); + v(x2, y2, z2, u1, v0); + v(x2, y2, z, u1, v1); + v(x, y2, z, u0, v1); + + v(x, y, z, u0, v0); + v(x2, y, z, u1, v0); + v(x, y, z2, u0, v1); + v(x2, y, z, u1, v0); + v(x2, y, z2, u1, v1); + v(x, y, z2, u0, v1); + + vert_index = i; +} + +export function begin_mode_3d() { + flush_batch(); + + mode3d = true; + active_camera = camera; + + gl.enable(gl.DEPTH_TEST); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + vert_index = 0; + + update_camera(); +} + +export function end_mode_3d() { + if (!mode3d) { + return; + } + + flush_batch(); + + mode3d = false; + gl.disable(gl.DEPTH_TEST); +} + +export function update_camera() { + mat4_perspective( + projection, + camera.fov, + canvas.width / canvas.height, + camera.near, + camera.far, + ); + + mat4_view(view); + + mat4_mul(mvp_matrix, projection, view); +} diff --git a/client/renderer/math.ts b/client/renderer/math.ts index f643f7f..9e05bc7 100644 --- a/client/renderer/math.ts +++ b/client/renderer/math.ts @@ -1,6 +1,7 @@ -export function perspective(out: Float32Array, fov: number, aspect: number, near: number, far: number) { +import { camera } from "./core.ts"; + +export function mat4_perspective(out: Float32Array, fov: number, aspect: number, near: number, far: number) { const f = 1 / Math.tan(fov / 2); - const nf = 1 / (near - far); out[0] = f / aspect; out[1] = 0; @@ -14,11 +15,70 @@ export function perspective(out: Float32Array, fov: number, aspect: number, near out[8] = 0; out[9] = 0; - out[10] = (far + near) * nf; + out[10] = -(far + near) / (far - near); out[11] = -1; out[12] = 0; out[13] = 0; - out[14] = (2 * far * near) * nf; + out[14] = -(2 * far * near) / (far - near); out[15] = 0; } + +export function mat4_view(out: Float32Array) { + const cx = camera.x; + const cy = camera.y; + const cz = camera.z; + + const yaw = camera.yaw; + const pitch = camera.pitch; + + const cosY = Math.cos(yaw); + const sinY = Math.sin(yaw); + const cosP = Math.cos(pitch); + const sinP = Math.sin(pitch); + + const fx = cosP * sinY; + const fy = sinP; + const fz = cosP * cosY; + + const rx = cosY; + const rz = -sinY; + + const ux = -sinP * sinY; + const uy = cosP; + const uz = -sinP * cosY; + + out[0] = rx; + out[1] = ux; + out[2] = -fx; + out[3] = 0; + + out[4] = 0; + out[5] = uy; + out[6] = -fy; + out[7] = 0; + + out[8] = rz; + out[9] = uz; + out[10] = -fz; + out[11] = 0; + + out[12] = -(rx * cx + rz * cz); + out[13] = -(ux * cx + uy * cy + uz * cz); + out[14] = fx * cx + fy * cy + fz * cz; + out[15] = 1; +} + +export function mat4_mul(out: Float32Array, a: Float32Array, b: Float32Array) { + for (let i = 0; i < 4; i++) { + const ai0 = a[i]; + const ai1 = a[i + 4]; + const ai2 = a[i + 8]; + const ai3 = a[i + 12]; + + out[i] = ai0 * b[0] + ai1 * b[1] + ai2 * b[2] + ai3 * b[3]; + out[i + 4] = ai0 * b[4] + ai1 * b[5] + ai2 * b[6] + ai3 * b[7]; + out[i + 8] = ai0 * b[8] + ai1 * b[9] + ai2 * b[10] + ai3 * b[11]; + out[i + 12] = ai0 * b[12] + ai1 * b[13] + ai2 * b[14] + ai3 * b[15]; + } +} diff --git a/client/systems/render_system.ts b/client/systems/render_system.ts index b98a82d..015c2cc 100644 --- a/client/systems/render_system.ts +++ b/client/systems/render_system.ts @@ -10,6 +10,7 @@ import { render_dimension } from "./rendering/dimension.ts"; import { render_player_hotbar } from "./rendering/player.ts"; import { begin_mode_2d, end_mode_2d } from "../renderer/mod.ts"; import { PlayerComponent } from "../player.ts"; +import { begin_mode_3d, end_mode_3d, push_cube } from "../renderer/core.ts"; export class RenderSystem extends System { constructor() { @@ -17,7 +18,7 @@ export class RenderSystem extends System { } update(world: World, _delta: number): void { - const camera_entity = world.get_entities().values().find((e) => e.get(Camera)?.active); + /*const camera_entity = world.get_entities().values().find((e) => e.get(Camera)?.active); const camera = camera_entity?.get(Camera); if (!camera) { @@ -55,6 +56,45 @@ export class RenderSystem extends System { if (player_component) { render_player_hotbar(player_component.player_inventory); } - } + }*/ + + begin_mode_3d(); + push_cube( + -0.5, + -0.5, + -0.5, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + ); + push_cube( + 0.5, + 0.5, + 0.5, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + ); + push_cube( + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + ); + end_mode_3d(); } }