Skip to content

Commit

Permalink
Add more special renderers (#36)
Browse files Browse the repository at this point in the history
* Add hacky shield rendering

* Add skulls and heads

* Refactor special renderer transformations

* Handle `rotation` block state for skulls

* Add trapped chests and ender chests

* Add signs

* Add conduit

* Add shulker box

* Add bell

* Add beds

* Add hanging signs

* Add banners
  • Loading branch information
misode authored Oct 2, 2024
1 parent c644a28 commit 4a3a21d
Show file tree
Hide file tree
Showing 9 changed files with 968 additions and 96 deletions.
8 changes: 6 additions & 2 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@
.invalid {
color: #cb0000;
}
#item-display {
width: 64px;
height: 64px;
}
</style>
</head>
<body>
<div class="row">
<canvas id="item-display" width="64" height="64"></canvas>
<input id="item-input" list="item-list" type="text" value="stone">
<canvas id="item-display" width="256" height="256"></canvas>
<input id="item-input" list="item-list" type="text">
</div>
<canvas id="voxel-display" width="600" height="400"></canvas>
<canvas id="structure-display" width="600" height="400"></canvas>
Expand Down
14 changes: 8 additions & 6 deletions demo/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,17 @@ Promise.all([

const itemCanvas = document.getElementById('item-display') as HTMLCanvasElement
const itemGl = itemCanvas.getContext('webgl')!
const itemRenderer = new ItemRenderer(itemGl, Identifier.parse('stone'), resources)

const itemInput = document.getElementById('item-input') as HTMLInputElement
itemInput.value = localStorage.getItem('deepslate_demo_item') ?? 'stone'
const itemRenderer = new ItemRenderer(itemGl, Identifier.parse(itemInput.value), resources)

itemInput.addEventListener('keyup', () => {
try {
const id = itemInput.value
itemRenderer.setItem(new ItemStack(Identifier.parse(id), 1))
itemRenderer.drawItem()
itemInput.classList.remove('invalid')
localStorage.setItem('deepslate_demo_item', id)
} catch (e) {
console.error(e)
itemInput.classList.add('invalid')
Expand All @@ -146,10 +148,10 @@ Promise.all([

const structure = new Structure([3, 2, 1])
const size = structure.getSize()
structure.addBlock([1, 0, 0], 'minecraft:stone')
structure.addBlock([2, 0, 0], 'minecraft:grass_block', { snowy: 'false' })
structure.addBlock([1, 1, 0], 'minecraft:cake', { bites: '3' })
structure.addBlock([2, 1, 0], 'minecraft:acacia_fence', { waterlogged: 'true' })
structure.addBlock([1, 0, 0], 'minecraft:grass_block', { snowy: 'false' })
structure.addBlock([2, 0, 0], 'minecraft:stone')
structure.addBlock([1, 1, 0], 'minecraft:skeleton_skull', { rotation: '15' })
structure.addBlock([2, 1, 0], 'minecraft:acacia_fence', { waterlogged: 'true', north: 'true' })
structure.addBlock([0, 0, 0], 'minecraft:wall_torch', { facing: 'west' })

const structureCanvas = document.getElementById('structure-display') as HTMLCanvasElement
Expand Down
8 changes: 7 additions & 1 deletion src/core/BlockState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,13 @@ export class BlockState {
})
}

public is(other: BlockState) {
public is(other: string | Identifier | BlockState) {
if (typeof other === 'string') {
return this.name.equals(Identifier.parse(other))
}
if (other instanceof Identifier) {
return this.name.equals(other)
}
return this.name.equals(other.name)
}

Expand Down
2 changes: 0 additions & 2 deletions src/render/BlockDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export class BlockDefinition {

if (variant.x || variant.y) {
const t = mat4.create()
mat4.identity(t)
mat4.translate(t, t, [8, 8, 8])
mat4.rotateY(t, t, -glMatrix.toRadian(variant.y ?? 0))
mat4.rotateX(t, t, -glMatrix.toRadian(variant.x ?? 0))
Expand All @@ -80,7 +79,6 @@ export class BlockDefinition {
}

const t = mat4.create()
mat4.identity(t)
mat4.scale(t, t, [0.0625, 0.0625, 0.0625])
return mesh.transform(t)
}
Expand Down
12 changes: 8 additions & 4 deletions src/render/BlockModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export class BlockModel {
private static readonly BUILTIN_GENERATED = Identifier.create('builtin/generated')
private static readonly GENERATED_LAYERS = ['layer0', 'layer1', 'layer2', 'layer3', 'layer4']
private generationMarker = false
private uvEpsilon = 1/16

constructor(
private readonly id: Identifier,
Expand All @@ -87,7 +88,6 @@ export class BlockModel {
public getDisplayTransform(display: Display) {
const transform = this.display?.[display]
const t = mat4.create()
mat4.identity(t)
mat4.translate(t, t, [8, 8, 8])
if (transform?.translation) {
mat4.translate(t, t, transform.translation)
Expand Down Expand Up @@ -136,8 +136,8 @@ export class BlockModel {
const [u0, v0, u1, v1] = uvProvider.getTextureUV(this.getTexture(face.texture))
const du = (u1 - u0) / 16
const dv = (v1 - v0) / 16
const duu = du / 16
const dvv = dv / 16
const duu = du * this.uvEpsilon
const dvv = dv * this.uvEpsilon
uv[0] = (face.uv?.[0] ?? uv[0]) * du + duu
uv[1] = (face.uv?.[1] ?? uv[1]) * dv + dvv
uv[2] = (face.uv?.[2] ?? uv[2]) * du - duu
Expand Down Expand Up @@ -177,7 +177,6 @@ export class BlockModel {
}

const t = mat4.create()
mat4.identity(t)
if (e.rotation) {
const origin = vec3.fromValues(...e.rotation.origin)
mat4.translate(t, t, origin)
Expand All @@ -198,6 +197,11 @@ export class BlockModel {
return Identifier.parse(textureRef)
}

public withUvEpsilon(epsilon: number) {
this.uvEpsilon = epsilon
return this
}

public flatten(accessor: BlockModelProvider) {
if (!this.parent) {
return
Expand Down
2 changes: 1 addition & 1 deletion src/render/ChunkBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class ChunkBuilder {
if (blockDefinition) {
mesh.merge(blockDefinition.getMesh(blockName, blockProps, this.resources, this.resources, cull))
}
const specialMesh = SpecialRenderers.getMesh(blockName.toString(), blockProps, this.resources, cull)
const specialMesh = SpecialRenderers.getBlockMesh(b.state, this.resources, cull)
if (!specialMesh.isEmpty()) {
mesh.merge(specialMesh)
}
Expand Down
16 changes: 3 additions & 13 deletions src/render/ItemRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,10 @@ export class ItemRenderer extends Renderer {
tint = getItemColor(this.item)
}
const mesh = model.getMesh(this.resources, Cull.none(), tint)
const specialMesh = SpecialRenderers.getMesh(this.item.id.toString(), {}, this.resources, Cull.none())
if (!specialMesh.isEmpty()) {
// undo the scaling done by the special renderer
const t = mat4.create()
mat4.identity(t)
mat4.scale(t, t, [16, 16, 16])
specialMesh.transform(t)
mesh.merge(specialMesh)
}
const specialMesh = SpecialRenderers.getItemMesh(this.item, this.resources)
mesh.merge(specialMesh)
mesh.transform(model.getDisplayTransform('gui'))
mesh.quads.forEach(q => {
const normal = q.normal()
q.forEach(v => v.normal = normal)
})
mesh.computeNormals()
mesh.rebuild(this.gl, { pos: true, color: true, texture: true, normal: true })
return mesh
}
Expand Down
7 changes: 7 additions & 0 deletions src/render/Mesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ export class Mesh {
return this
}

public computeNormals() {
for (const quad of this.quads) {
const normal = quad.normal()
quad.forEach(v => v.normal = normal)
}
}

public rebuild(gl: WebGLRenderingContext, options: { pos?: boolean, color?: boolean, texture?: boolean, normal?: boolean, blockPos?: boolean }) {
const rebuildBuffer = (buffer: WebGLBuffer | undefined, type: number, data: BufferSource): WebGLBuffer | undefined => {
if (!buffer) {
Expand Down
Loading

0 comments on commit 4a3a21d

Please sign in to comment.