diff --git a/client/blocks/mod.ts b/client/blocks/mod.ts index b6bd790..d77a8a0 100644 --- a/client/blocks/mod.ts +++ b/client/blocks/mod.ts @@ -8,3 +8,4 @@ import "./stone.ts"; import "./log.ts"; import "./sand.ts"; import "./snow.ts"; +import "./glass.ts"; diff --git a/client/blocks/water.ts b/client/blocks/water.ts index f862f2b..76f66e4 100644 --- a/client/blocks/water.ts +++ b/client/blocks/water.ts @@ -3,4 +3,6 @@ import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry. EverythingRegistry.register("blocks", "bworld:water", { textures: "bworld:water", has_collision: false, + transparent: true, + alpha: 0.8, }); diff --git a/client/components/dimension.ts b/client/components/dimension.ts index aaa3f99..3c79ed8 100644 --- a/client/components/dimension.ts +++ b/client/components/dimension.ts @@ -28,8 +28,10 @@ export interface Chunk { blocks: Int16Array; generated: boolean; dirty: boolean; - vertex_buffer?: WebGLBuffer; - vertex_count?: number; + opaque_vertex_buffer?: WebGLBuffer; + opaque_vertex_count?: number; + transparent_vertex_buffer?: WebGLBuffer; + transparent_vertex_count?: number; } export class Dimension extends Component { @@ -193,8 +195,11 @@ export class Dimension extends Component { } delete_chunk_mesh(chunk: Chunk) { - if (chunk.vertex_buffer) { - gl.deleteBuffer(chunk.vertex_buffer); + if (chunk.opaque_vertex_buffer) { + gl.deleteBuffer(chunk.opaque_vertex_buffer); + } + if (chunk.transparent_vertex_buffer) { + gl.deleteBuffer(chunk.transparent_vertex_buffer); } } diff --git a/client/systems/player_controls.ts b/client/systems/player_controls.ts index 122561f..1cfb856 100644 --- a/client/systems/player_controls.ts +++ b/client/systems/player_controls.ts @@ -116,7 +116,7 @@ export class PlayerControlsSystem extends System { x: block.x + offset.x, y: block.y + offset.y, z: block.z + offset.z, - id: "bworld:dirt", + id: "bworld:glass", }); } } diff --git a/client/systems/rendering/dimension.ts b/client/systems/rendering/dimension.ts index 2d288ad..e313184 100644 --- a/client/systems/rendering/dimension.ts +++ b/client/systems/rendering/dimension.ts @@ -11,7 +11,7 @@ const worker = new Worker(new URL("./workers/chunk_mesh_worker.js", import.meta. }); worker.onmessage = (event) => { - const { vertices, count, chunk_x, chunk_z } = event.data; + const { opaque_vertices, opaque_count, transparent_vertices, transparent_count, chunk_x, chunk_z } = event.data; const chunk = gdimension.get_chunk(chunk_x, chunk_z); if (!chunk) { console.error("bad"); @@ -19,13 +19,24 @@ worker.onmessage = (event) => { } gdimension.delete_chunk_mesh(chunk); chunk.dirty = false; - chunk.vertex_buffer = gl.createBuffer(); - chunk.vertex_count = count / 9; - gl.bindBuffer(gl.ARRAY_BUFFER, chunk.vertex_buffer); + chunk.opaque_vertex_buffer = gl.createBuffer(); + chunk.opaque_vertex_count = opaque_count / 9; + + gl.bindBuffer(gl.ARRAY_BUFFER, chunk.opaque_vertex_buffer); gl.bufferData( gl.ARRAY_BUFFER, - vertices.subarray(0, count), + opaque_vertices.subarray(0, opaque_count), + gl.STATIC_DRAW, + ); + + chunk.transparent_vertex_buffer = gl.createBuffer(); + chunk.transparent_vertex_count = transparent_count / 9; + + gl.bindBuffer(gl.ARRAY_BUFFER, chunk.transparent_vertex_buffer); + gl.bufferData( + gl.ARRAY_BUFFER, + transparent_vertices.subarray(0, transparent_count), gl.STATIC_DRAW, ); }; @@ -70,12 +81,24 @@ export function render_dimension(dimension: Dimension, camera: Camera) { for (const chunk of dimension.chunks) { render_chunk_opaque(chunk); } + + for (const chunk of dimension.chunks) { + render_chunk_transparent(chunk); + } } function render_chunk_opaque(chunk: Chunk) { - if (!chunk.vertex_buffer || !chunk.vertex_count) { + if (!chunk.opaque_vertex_buffer || !chunk.opaque_vertex_count) { return; } - flush_buffer(chunk.vertex_buffer, chunk.vertex_count); + flush_buffer(chunk.opaque_vertex_buffer, chunk.opaque_vertex_count); +} + +function render_chunk_transparent(chunk: Chunk) { + if (!chunk.transparent_vertex_buffer || !chunk.transparent_vertex_count) { + return; + } + + flush_buffer(chunk.transparent_vertex_buffer, chunk.transparent_vertex_count); } diff --git a/client/workers/chunk_mesh_worker.ts b/client/workers/chunk_mesh_worker.ts index 412073e..261f822 100644 --- a/client/workers/chunk_mesh_worker.ts +++ b/client/workers/chunk_mesh_worker.ts @@ -29,8 +29,18 @@ const FACE_PUSHING_FUNCTIONS = { self.onmessage = (event) => { const { chunk_x, chunk_z, padded_chunk, blocks_registry, textures_info, image } = event.data; - const [vertices, count] = make_chunk_mesh(chunk_x, chunk_z, padded_chunk, blocks_registry, textures_info, image); - self.postMessage({ vertices, count, chunk_x, chunk_z }, [vertices.buffer]); + const [opaque_vertices, opaque_count, transparent_vertices, transparent_count] = make_chunk_mesh( + chunk_x, + chunk_z, + padded_chunk, + blocks_registry, + textures_info, + image, + ); + self.postMessage( + { opaque_vertices, opaque_count, transparent_vertices, transparent_count, chunk_x, chunk_z }, + [opaque_vertices.buffer, transparent_vertices.buffer], + ); }; function make_chunk_mesh( @@ -40,9 +50,11 @@ function make_chunk_mesh( blocks_registry: BlockRegistry[], textures_info: TexturesInfo, image: Texture, -): [Float32Array, number] { - let vertices = new Float32Array(2048); - let count = 0; +): [Float32Array, number, Float32Array, number] { + let opaque_vertices = new Float32Array(2048); + let opaque_count = 0; + let transparent_vertices = new Float32Array(2048); + let transparent_count = 0; const size = CHUNK_SIZE + 2; const layer = size * size; @@ -119,30 +131,53 @@ function make_chunk_mesh( if (faces[side]) { const region = textures_info[texture_ids[side]]; - vertices = ensure_capacity(vertices, count + (6 * 6 * 9)); - count = FACE_PUSHING_FUNCTIONS[side]( - vertices, - count, - image, - wx, - y, - wz, - region.x * TEXTURE_SIZE, - region.y * TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - 1, - 1, - 1, - 1, - ); + if (block_info.transparent) { + transparent_vertices = ensure_capacity( + transparent_vertices, + transparent_count + (6 * 6 * 9), + ); + transparent_count = FACE_PUSHING_FUNCTIONS[side]( + transparent_vertices, + transparent_count, + image, + wx, + y, + wz, + region.x * TEXTURE_SIZE, + region.y * TEXTURE_SIZE, + TEXTURE_SIZE, + TEXTURE_SIZE, + 1, + 1, + 1, + block_info.alpha ?? 1, + ); + } else { + opaque_vertices = ensure_capacity(opaque_vertices, opaque_count + (6 * 6 * 9)); + opaque_count = FACE_PUSHING_FUNCTIONS[side]( + opaque_vertices, + opaque_count, + image, + wx, + y, + wz, + region.x * TEXTURE_SIZE, + region.y * TEXTURE_SIZE, + TEXTURE_SIZE, + TEXTURE_SIZE, + 1, + 1, + 1, + 1, + ); + } } } } } } - return [vertices, count]; + return [opaque_vertices, opaque_count, transparent_vertices, transparent_count]; } function ensure_capacity( diff --git a/common/everything_registry.ts b/common/everything_registry.ts index 45da432..fca1c01 100644 --- a/common/everything_registry.ts +++ b/common/everything_registry.ts @@ -62,8 +62,10 @@ interface TextureFront { export interface BlockRegistry { textures: string | TextureSideTopBottom | TextureFront; - has_collision: boolean; transparent?: boolean; + alpha?: number; + + has_collision: boolean; drop_table?: string; on_create?(dimension: Dimension, block: Block): void;