diff --git a/assets/sprites/textures/dirt.png b/assets/sprites/textures/dirt.png index f4515b3..6f449a5 100644 Binary files a/assets/sprites/textures/dirt.png and b/assets/sprites/textures/dirt.png differ diff --git a/assets/sprites/textures/grass_side.png b/assets/sprites/textures/grass_side.png new file mode 100644 index 0000000..2977b21 Binary files /dev/null and b/assets/sprites/textures/grass_side.png differ diff --git a/assets/sprites/textures/grass_top.png b/assets/sprites/textures/grass_top.png new file mode 100644 index 0000000..4682149 Binary files /dev/null and b/assets/sprites/textures/grass_top.png differ diff --git a/client/blocks/chest.ts b/client/blocks/chest.ts index a23edd7..38948d8 100644 --- a/client/blocks/chest.ts +++ b/client/blocks/chest.ts @@ -8,7 +8,7 @@ interface TileChestData { } EverythingRegistry.register>("blocks", "bworld:chest", { - texture_id: "bworld:chest", + textures: "bworld:chest", has_collision: false, on_interact(world, tile) { diff --git a/client/blocks/crops.ts b/client/blocks/crops.ts index 6dbdec8..a47faa2 100644 --- a/client/blocks/crops.ts +++ b/client/blocks/crops.ts @@ -67,7 +67,7 @@ interface TileCropData { current_stage: number; growth_time: number; } - +/* function create_crop_tile(crop_id: string) { const crop_info = EverythingRegistry.get("crops", crop_id); @@ -144,3 +144,4 @@ EverythingRegistry.register>( "bworld:pumpkin_crop", create_crop_tile("bworld:pumpkin"), ); +*/ diff --git a/client/blocks/dirt.ts b/client/blocks/dirt.ts index 16fead9..6ca3e40 100644 --- a/client/blocks/dirt.ts +++ b/client/blocks/dirt.ts @@ -3,7 +3,7 @@ import { WateringCanData } from "../items/watering_can.ts"; import { PlayerComponent } from "../player.ts"; EverythingRegistry.register("blocks", "bworld:dirt", { - texture_id: "bworld:dirt", + textures: "bworld:dirt", has_collision: false, on_interact(world, tile) { @@ -17,7 +17,7 @@ EverythingRegistry.register("blocks", "bworld:dirt", { }); EverythingRegistry.register("blocks", "bworld:hoed_dirt", { - texture_id: "bworld:hoed_dirt", + textures: "bworld:hoed_dirt", has_collision: false, on_click(world, tile) { @@ -51,7 +51,7 @@ EverythingRegistry.register("blocks", "bworld:hoed_dirt", { }); EverythingRegistry.register("blocks", "bworld:hoed_watered_dirt", { - texture_id: "bworld:hoed_watered_dirt", + textures: "bworld:hoed_watered_dirt", has_collision: false, on_click(world, tile) { diff --git a/client/blocks/furnace.ts b/client/blocks/furnace.ts index 536f08e..ef4827b 100644 --- a/client/blocks/furnace.ts +++ b/client/blocks/furnace.ts @@ -67,7 +67,7 @@ interface TileChestData { } EverythingRegistry.register>("blocks", "bworld:furnace", { - texture_id: "bworld:furnace", + textures: "bworld:furnace", has_collision: false, on_interact(world, tile) { diff --git a/client/blocks/grass.ts b/client/blocks/grass.ts index 65f0cfd..66d0a1c 100644 --- a/client/blocks/grass.ts +++ b/client/blocks/grass.ts @@ -2,7 +2,7 @@ import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry. import { PlayerComponent } from "../player.ts"; EverythingRegistry.register("blocks", "bworld:grass", { - texture_id: "bworld:grass", + textures: { top: "bworld:grass_top", bottom: "bworld:dirt", "side": "bworld:grass_side" }, has_collision: false, on_interact(world, tile) { diff --git a/client/blocks/log.ts b/client/blocks/log.ts index 1efe565..f3a9d90 100644 --- a/client/blocks/log.ts +++ b/client/blocks/log.ts @@ -1,12 +1,12 @@ import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry.ts"; EverythingRegistry.register("blocks", "bworld:log", { - texture_id: "bworld:log_side", + textures: { side: "bworld:log_side", top: "bworld:log_top", bottom: "bworld:log_top" }, has_collision: true, }); EverythingRegistry.register("blocks", "bworld:leaves", { - texture_id: "bworld:leaves", + textures: "bworld:leaves", has_collision: true, transparent: true, }); diff --git a/client/blocks/mod.ts b/client/blocks/mod.ts index 17b9628..b6bd790 100644 --- a/client/blocks/mod.ts +++ b/client/blocks/mod.ts @@ -1,6 +1,5 @@ import "./grass.ts"; import "./dirt.ts"; -import "./tree.ts"; import "./crops.ts"; import "./water.ts"; import "./chest.ts"; diff --git a/client/blocks/sand.ts b/client/blocks/sand.ts index cb6aa3e..38cf1b3 100644 --- a/client/blocks/sand.ts +++ b/client/blocks/sand.ts @@ -1,6 +1,6 @@ import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry.ts"; EverythingRegistry.register("blocks", "bworld:sand", { - texture_id: "bworld:sand", + textures: "bworld:sand", has_collision: true, }); diff --git a/client/blocks/snow.ts b/client/blocks/snow.ts index 5b107b1..7909d1a 100644 --- a/client/blocks/snow.ts +++ b/client/blocks/snow.ts @@ -1,6 +1,6 @@ import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry.ts"; EverythingRegistry.register("blocks", "bworld:snow", { - texture_id: "bworld:snow", + textures: "bworld:snow", has_collision: true, }); diff --git a/client/blocks/stone.ts b/client/blocks/stone.ts index 30548df..5a2cfba 100644 --- a/client/blocks/stone.ts +++ b/client/blocks/stone.ts @@ -1,6 +1,6 @@ import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry.ts"; EverythingRegistry.register("blocks", "bworld:stone", { - texture_id: "bworld:stone", + textures: "bworld:stone", has_collision: true, }); diff --git a/client/blocks/tree.ts b/client/blocks/tree.ts deleted file mode 100644 index 623d8ed..0000000 --- a/client/blocks/tree.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry.ts"; -import { ItemStack } from "../inventory.ts"; -import { PlayerComponent } from "../player.ts"; - -EverythingRegistry.register("blocks", "bworld:tree", { - texture_id: "bworld:tree", - has_collision: false, - - on_click(world, tile) { - const [player] = world.get_tag("player")!; - const player_inventory = player.get(PlayerComponent)!.player_inventory; - const maybe_item = player_inventory.container.get_item(player_inventory.hotbar_selected); - if (maybe_item && maybe_item.type_id === "bworld:axe") { - tile.id = "bworld:grass"; - player_inventory.container.add_item(new ItemStack("bworld:log", 7)); - } - }, -}); diff --git a/client/blocks/water.ts b/client/blocks/water.ts index 1cf3b4b..f862f2b 100644 --- a/client/blocks/water.ts +++ b/client/blocks/water.ts @@ -1,6 +1,6 @@ import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry.ts"; EverythingRegistry.register("blocks", "bworld:water", { - texture_id: "bworld:water", + textures: "bworld:water", has_collision: false, }); diff --git a/client/renderer/models.ts b/client/renderer/models.ts index 4214fe1..db0e0a3 100644 --- a/client/renderer/models.ts +++ b/client/renderer/models.ts @@ -1,8 +1,34 @@ import { Texture } from "./types.ts"; -export function push_cube_to_mesh( +function push_vertex( vertices: Float32Array, - vertex_count: number, + i: number, + px: number, + py: number, + pz: number, + u: number, + v: number, + r: number, + g: number, + b: number, + a: number, +) { + vertices[i++] = px; + vertices[i++] = py; + vertices[i++] = pz; + vertices[i++] = u; + vertices[i++] = v; + vertices[i++] = r; + vertices[i++] = g; + vertices[i++] = b; + vertices[i++] = a; + + return i; +} + +export function pushFrontFace( + vertices: Float32Array, + i: number, texture: Texture, x: number, y: number, @@ -18,12 +44,6 @@ export function push_cube_to_mesh( g = 1, b = 1, a = 1, - front = true, - back = true, - left = true, - right = true, - top = true, - bottom = true, ) { const x2 = x + w; const y2 = y + h; @@ -34,85 +54,199 @@ export function push_cube_to_mesh( const u1 = (sx + sw) / texture.width; const v1 = (sy + sh) / texture.height; - let i = vertex_count; + i = push_vertex(vertices, i, x, y, z2, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y, z2, u1, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y2, z2, u1, v0, r, g, b, a); - const push = (px: number, py: number, pz: number, u: number, vv: number) => { - vertices[i++] = px; - vertices[i++] = py; - vertices[i++] = pz; - vertices[i++] = u; - vertices[i++] = vv; - vertices[i++] = r; - vertices[i++] = g; - vertices[i++] = b; - vertices[i++] = a; - }; - - // front (+z) - if (front) { - push(x, y, z2, u0, v1); - push(x2, y, z2, u1, v1); - push(x2, y2, z2, u1, v0); - - push(x, y, z2, u0, v1); - push(x2, y2, z2, u1, v0); - push(x, y2, z2, u0, v0); - } - - // back (-z) - if (back) { - push(x2, y, z, u0, v1); - push(x, y, z, u1, v1); - push(x, y2, z, u1, v0); - - push(x2, y, z, u0, v1); - push(x, y2, z, u1, v0); - push(x2, y2, z, u0, v0); - } - - // left (-x) - if (left) { - push(x, y, z, u0, v1); - push(x, y, z2, u1, v1); - push(x, y2, z2, u1, v0); - - push(x, y, z, u0, v1); - push(x, y2, z2, u1, v0); - push(x, y2, z, u0, v0); - } - - // right (+x) - if (right) { - push(x2, y, z2, u0, v1); - push(x2, y, z, u1, v1); - push(x2, y2, z, u1, v0); - - push(x2, y, z2, u0, v1); - push(x2, y2, z, u1, v0); - push(x2, y2, z2, u0, v0); - } - - // top (+y) - if (top) { - push(x, y2, z2, u0, v1); - push(x2, y2, z2, u1, v1); - push(x2, y2, z, u1, v0); - - push(x, y2, z2, u0, v1); - push(x2, y2, z, u1, v0); - push(x, y2, z, u0, v0); - } - - // bottom (-y) - if (bottom) { - push(x, y, z, u0, v1); - push(x2, y, z, u1, v1); - push(x2, y, z2, u1, v0); - - push(x, y, z, u0, v1); - push(x2, y, z2, u1, v0); - push(x, y, z2, u0, v0); - } + i = push_vertex(vertices, i, x, y, z2, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y2, z2, u1, v0, r, g, b, a); + i = push_vertex(vertices, i, x, y2, z2, u0, v0, r, g, b, a); + + return i; +} + +export function pushBackFace( + vertices: Float32Array, + i: number, + texture: Texture, + x: number, + y: number, + z: number, + w: number, + h: number, + d: number, + sx: number, + sy: number, + sw: number, + sh: number, + r = 1, + g = 1, + b = 1, + a = 1, +) { + const x2 = x + w, y2 = y + h; + + const u0 = sx / texture.width; + const v0 = sy / texture.height; + const u1 = (sx + sw) / texture.width; + const v1 = (sy + sh) / texture.height; + + i = push_vertex(vertices, i, x2, y, z, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x, y, z, u1, v1, r, g, b, a); + i = push_vertex(vertices, i, x, y2, z, u1, v0, r, g, b, a); + + i = push_vertex(vertices, i, x2, y, z, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x, y2, z, u1, v0, r, g, b, a); + i = push_vertex(vertices, i, x2, y2, z, u0, v0, r, g, b, a); + + return i; +} + +export function pushLeftFace( + vertices: Float32Array, + i: number, + texture: Texture, + x: number, + y: number, + z: number, + w: number, + h: number, + d: number, + sx: number, + sy: number, + sw: number, + sh: number, + r = 1, + g = 1, + b = 1, + a = 1, +) { + const y2 = y + h; + const z2 = z + d; + + const u0 = sx / texture.width; + const v0 = sy / texture.height; + const u1 = (sx + sw) / texture.width; + const v1 = (sy + sh) / texture.height; + + i = push_vertex(vertices, i, x, y, z, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x, y, z2, u1, v1, r, g, b, a); + i = push_vertex(vertices, i, x, y2, z2, u1, v0, r, g, b, a); + + i = push_vertex(vertices, i, x, y, z, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x, y2, z2, u1, v0, r, g, b, a); + i = push_vertex(vertices, i, x, y2, z, u0, v0, r, g, b, a); + + return i; +} + +export function pushRightFace( + vertices: Float32Array, + i: number, + texture: Texture, + x: number, + y: number, + z: number, + w: number, + h: number, + d: number, + sx: number, + sy: number, + sw: number, + sh: number, + r = 1, + g = 1, + b = 1, + a = 1, +) { + const x2 = x + w, y2 = y + h; + + const u0 = sx / texture.width; + const v0 = sy / texture.height; + const u1 = (sx + sw) / texture.width; + const v1 = (sy + sh) / texture.height; + + i = push_vertex(vertices, i, x2, y, z + d, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y, z, u1, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y2, z, u1, v0, r, g, b, a); + + i = push_vertex(vertices, i, x2, y, z + d, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y2, z, u1, v0, r, g, b, a); + i = push_vertex(vertices, i, x2, y2, z + d, u0, v0, r, g, b, a); + + return i; +} + +export function pushTopFace( + vertices: Float32Array, + i: number, + texture: Texture, + x: number, + y: number, + z: number, + w: number, + h: number, + d: number, + sx: number, + sy: number, + sw: number, + sh: number, + r = 1, + g = 1, + b = 1, + a = 1, +) { + const x2 = x + w, z2 = z + d, y2 = y + h; + + const u0 = sx / texture.width; + const v0 = sy / texture.height; + const u1 = (sx + sw) / texture.width; + const v1 = (sy + sh) / texture.height; + + i = push_vertex(vertices, i, x, y2, z2, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y2, z2, u1, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y2, z, u1, v0, r, g, b, a); + + i = push_vertex(vertices, i, x, y2, z2, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y2, z, u1, v0, r, g, b, a); + i = push_vertex(vertices, i, x, y2, z, u0, v0, r, g, b, a); + + return i; +} + +export function pushBottomFace( + vertices: Float32Array, + i: number, + texture: Texture, + x: number, + y: number, + z: number, + w: number, + h: number, + d: number, + sx: number, + sy: number, + sw: number, + sh: number, + r = 1, + g = 1, + b = 1, + a = 1, +) { + const x2 = x + w, z2 = z + d; + + const u0 = sx / texture.width; + const v0 = sy / texture.height; + const u1 = (sx + sw) / texture.width; + const v1 = (sy + sh) / texture.height; + + i = push_vertex(vertices, i, x, y, z, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y, z, u1, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y, z2, u1, v0, r, g, b, a); + + i = push_vertex(vertices, i, x, y, z, u0, v1, r, g, b, a); + i = push_vertex(vertices, i, x2, y, z2, u1, v0, r, g, b, a); + i = push_vertex(vertices, i, x, y, z2, u0, v0, r, g, b, a); return i; } diff --git a/client/systems/rendering/dimension.ts b/client/systems/rendering/dimension.ts index 4dfb9aa..8817217 100644 --- a/client/systems/rendering/dimension.ts +++ b/client/systems/rendering/dimension.ts @@ -2,7 +2,17 @@ import { get_sprite_region } from "$/common/utils.ts"; import { Chunk, CHUNK_AREA, CHUNK_SIZE, Dimension } from "$/client/components/dimension.ts"; import { TEXTURE_SIZE } from "$/common/constants.ts"; import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry.ts"; -import { flush_buffer, gl, push_cube_to_mesh, set_current_texture } from "$/client/renderer/mod.ts"; +import { + flush_buffer, + gl, + pushBackFace, + pushBottomFace, + pushFrontFace, + pushLeftFace, + pushRightFace, + pushTopFace, + set_current_texture, +} from "$/client/renderer/mod.ts"; import { Camera } from "$/client/components/camera.ts"; export function render_dimension(dimension: Dimension, camera: Camera) { @@ -29,6 +39,15 @@ function render_chunk_opaque(chunk: Chunk) { flush_buffer(chunk.vertex_buffer, chunk.vertex_count); } +const FACE_PUSHING_FUNCTIONS = { + top: pushTopFace, + bottom: pushBottomFace, + front: pushFrontFace, + back: pushBackFace, + left: pushLeftFace, + right: pushRightFace, +} as const; + function make_chunk_mesh(chunk: Chunk, dimension: Dimension, camera: Camera) { let vertices = new Float32Array(CHUNK_AREA * 24 * 6 * 9); let count = 0; @@ -57,13 +76,41 @@ function make_chunk_mesh(chunk: Chunk, dimension: Dimension, camera: Camera) { const block_info = blocks_registry[block_nid]; - let texture_id = "bworld:missing"; - if (block_info?.texture_id) { - if (typeof block_info.texture_id === "string") { - texture_id = block_info.texture_id; - } else { - // texture_id = block_info.texture_id(block); - } + const texture_ids = { + top: "bworld:missing", + bottom: "bworld:missing", + front: "bworld:missing", + back: "bworld:missing", + left: "bworld:missing", + right: "bworld:missing", + }; + + const textures = block_info.textures; + if (!textures) { + throw new Error(`no textures for ${block_nid}`); + } + + if (typeof textures === "string") { + texture_ids.top = textures; + texture_ids.bottom = textures; + texture_ids.front = textures; + texture_ids.back = textures; + texture_ids.left = textures; + texture_ids.right = textures; + } else if ("top" in textures && "bottom" in textures && "side" in textures) { + texture_ids.top = textures.top; + texture_ids.bottom = textures.bottom; + texture_ids.front = textures.side; + texture_ids.back = textures.side; + texture_ids.left = textures.side; + texture_ids.right = textures.side; + } else if ("front" in textures && "side" in textures) { + texture_ids.top = textures.side; + texture_ids.bottom = textures.side; + texture_ids.front = textures.front; + texture_ids.back = textures.side; + texture_ids.left = textures.side; + texture_ids.right = textures.side; } const [x, y, z] = dimension.index_to_xyz(i); @@ -71,41 +118,41 @@ function make_chunk_mesh(chunk: Chunk, dimension: Dimension, camera: Camera) { const wx = chunk.x * CHUNK_SIZE + x; const wz = chunk.z * CHUNK_SIZE + z; - const front = show_face(wx, y, wz + 1); - const back = show_face(wx, y, wz - 1); - const left = show_face(wx - 1, y, wz); - const right = show_face(wx + 1, y, wz); - const top = show_face(wx, y + 1, wz); - const bottom = show_face(wx, y - 1, wz); + const faces = { + front: show_face(wx, y, wz + 1), + back: show_face(wx, y, wz - 1), + left: show_face(wx - 1, y, wz), + right: show_face(wx + 1, y, wz), + top: show_face(wx, y + 1, wz), + bottom: show_face(wx, y - 1, wz), + } as const; - const region = get_sprite_region(texture_id); + for (const side of ["front", "back", "left", "right", "top", "bottom"] as const) { + if (faces[side]) { + const region = get_sprite_region(texture_ids[side]); - vertices = ensure_capacity(vertices, count + (6 * 6 * 9)); - count = push_cube_to_mesh( - vertices, - count, - dimension.image, - wx, - y, - wz, - 1, - 1, - 1, - region.x * TEXTURE_SIZE, - region.y * TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - 1, - 1, - 1, - 1, - front, - back, - left, - right, - top, - bottom, - ); + vertices = ensure_capacity(vertices, count + (6 * 6 * 9)); + count = FACE_PUSHING_FUNCTIONS[side]( + vertices, + count, + dimension.image, + wx, + y, + wz, + 1, + 1, + 1, + region.x * TEXTURE_SIZE, + region.y * TEXTURE_SIZE, + TEXTURE_SIZE, + TEXTURE_SIZE, + 1, + 1, + 1, + 1, + ); + } + } } chunk.vertex_buffer = gl.createBuffer(); diff --git a/common/everything_registry.ts b/common/everything_registry.ts index dbfbbad..20ad1fb 100644 --- a/common/everything_registry.ts +++ b/common/everything_registry.ts @@ -49,8 +49,19 @@ export class EverythingRegistry { } } +interface TextureSideTopBottom { + top: string; + bottom: string; + side: string; +} + +interface TextureFront { + front: string; + side: string; +} + export interface BlockRegistry { - texture_id: string | ((block: Block) => string); + textures: string | TextureSideTopBottom | TextureFront; has_collision: boolean; transparent?: boolean;