diff --git a/scripts/compile.js b/scripts/compile.js index d54b7f97..d8cfbca2 100644 --- a/scripts/compile.js +++ b/scripts/compile.js @@ -28,6 +28,8 @@ const charMap = { start: "┫" } +console.log("Processing fonts...") + const fonts = JSON.parse(fs.readFileSync("../fonts.json")) const ten = fonts.find(e => e.id === "minecraft-ten") @@ -64,9 +66,9 @@ for (const font of fonts) { fs.writeFileSync(`../fonts/${font.id}/textures.json`, JSON.stringify(JSON.parse(fs.readFileSync(`../fonts/${font.id}/textures.json`)), null, 2) + "\n") - fs.mkdirSync(`temp/${font.id}/textures`, { recursive: true }) - fs.mkdirSync(`temp/${font.id}/overlays`, { recursive: true }) - fs.mkdirSync(`temp/${font.id}/thumbnails`, { recursive: true }) + fs.mkdirSync(`temp/fonts/${font.id}/textures`, { recursive: true }) + fs.mkdirSync(`temp/fonts/${font.id}/overlays`, { recursive: true }) + fs.mkdirSync(`temp/fonts/${font.id}/thumbnails`, { recursive: true }) const textures = fs.readdirSync(`../fonts/${font.id}/textures`).map(e => ["textures", e]).concat(fs.readdirSync(`../fonts/${font.id}/overlays`).map(e => ["overlays", e])) @@ -84,7 +86,7 @@ for (const font of fonts) { if (!file[1].endsWith(".png") || file[1] === "overlay.png") continue const texture = await loadTexture(file[0] ? `../fonts/${font.id}/${file[0]}/${file[1]}` : file[2]) - if (file[0]) texture.image.saveAs(`temp/${font.id}/${file[0]}/${file[1]}`) + if (file[0]) texture.image.saveAs(`temp/fonts/${font.id}/${file[0]}/${file[1]}`) const scaleFactor = texture.image.width / 1000 const [scene, camera] = makeTitleScene(scaleFactor) @@ -102,7 +104,7 @@ for (const font of fonts) { else text = `┫${text}┣` } - await addTitleText(scene, text, { + addTitleText(scene, text, { font: font.id, texture }) @@ -132,14 +134,54 @@ for (const font of fonts) { canvas = bordered } - canvas.saveAs(`temp/${font.id}/thumbnails/${file[1]}`) + canvas.saveAs(`temp/fonts/${font.id}/thumbnails/${file[1]}`) console.log(`Done ${font.id} ${file[1]}`) } } +console.log("Processed fonts") +console.log("Processing shapes...") + +const shapes = {} + +const shapesList = JSON.parse(fs.readFileSync("../shapes.json")) + +for (const [id, shape] of Object.entries(shapesList)) { + shapes[id] = JSON.parse(fs.readFileSync(`../shapes/${id}/model.json`)).elements + for (const element of shapes[id]) { + for (const [direction, face] of Object.entries(element.faces)) { + if (face.rotation === 180) face.uv = [face.uv.slice(2), face.uv.slice(0, 2)].flat() + element.faces[direction] = face.uv + } + } + + fs.mkdirSync(`temp/shapes/${id}/textures`, { recursive: true }) + fs.mkdirSync(`temp/shapes/${id}/thumbnails`, { recursive: true }) + + const textures = Object.entries(JSON.parse(fs.readFileSync(`../shapes/${id}/textures.json`))).flatMap(([id, data]) => [id, ...(data.variants ? Object.keys(data.variants) : [])]) + + for (const name of textures) { + const texture = await loadTexture(`../shapes/${id}/textures/${name}.png`) + texture.image.saveAs(`temp/shapes/${id}/textures/${name}.png`) + + const scaleFactor = texture.image.width / shape.width + const [scene, camera] = makeTitleScene(scaleFactor) + + addShape(scene, shapes[id], texture) + + let canvas = await renderTitleScene(scene, camera, scaleFactor) + + canvas.saveAs(`temp/shapes/${id}/thumbnails/${name}.png`) + console.log(`Done ${id} ${name}.png`) + } +} + +fs.writeFileSync("../shapes/shapes.json", JSON.stringify(shapes)) + +console.log("Processed shapes") console.log("Compressing textures...") -compress_images("temp/**/*.png", "../fonts/", { +compress_images("temp/**/*.png", "../", { statistic: false, autoupdate: true, compress_force: true, @@ -183,7 +225,81 @@ function makeTitleScene(scaleFactor) { return [scene, camera] } -async function addTitleText(scene, str, args) { +function addModel(scene, model, group, material, cubes, i, font, width, args) { + let min = Infinity + let max = -Infinity + const character = new THREE.Group() + for (let cube of model) { + if (!cube.parsed) { + cube.parsed = true + for (const [direction, uv] of Object.entries(cube.faces)) { + cube.faces[direction] = { uv } + } + } + + cube = JSON.parse(JSON.stringify(cube)) + min = Math.min(min, cube.from[0], cube.to[0]) + max = Math.max(max, cube.from[0], cube.to[0]) + + if (args.type === "bottom") { + if (cube.to[2] > cube.from[2]) { + cube.to[2] += 20 + } else { + cube.from[2] += 20 + } + } + + const geometry = new THREE.BoxGeometry(cube.to[0] - cube.from[0], cube.to[1] - cube.from[1], cube.to[2] - cube.from[2]) + const mesh = new THREE.Mesh(geometry, material) + + mesh.position.fromArray([ + (cube.from[0] + cube.to[0]) / 2, + (cube.from[1] + cube.to[1]) / 2, + (cube.from[2] + cube.to[2]) / 2 + ]) + + const indexes = { + north: 40, + east: 0, + south: 32, + west: 8, + up: 16, + down: 24 + } + + for (const key of Object.keys(indexes)) { + const face = cube.faces[key] + const i = indexes[key] + if (face) { + const uv = [ + [face.uv[0] / 16, 1 - (face.uv[1] / 16)], + [face.uv[2] / 16, 1 - (face.uv[1] / 16)], + [face.uv[0] / 16, 1 - (face.uv[3] / 16)], + [face.uv[2] / 16, 1 - (face.uv[3] / 16)] + ] + mesh.geometry.attributes.uv.array.set(uv[0], i + 0) + mesh.geometry.attributes.uv.array.set(uv[1], i + 2) + mesh.geometry.attributes.uv.array.set(uv[2], i + 4) + mesh.geometry.attributes.uv.array.set(uv[3], i + 6) + } else { + mesh.geometry.attributes.uv.array.set([1, 1], i + 0) + mesh.geometry.attributes.uv.array.set([1, 1], i + 2) + mesh.geometry.attributes.uv.array.set([1, 1], i + 4) + mesh.geometry.attributes.uv.array.set([1, 1], i + 6) + } + } + character.add(mesh) + cubes.push(mesh) + } + if (i) max += font.characterSpacing ?? 0 + for (const cube of character.children) { + cube.position.x -= width + max + } + group.add(character) + return max - min +} + +function addTitleText(scene, str, args) { const font = fonts.find(e => e.id === args.font) args.texture.colorSpace = THREE.SRGBColorSpace @@ -206,110 +322,37 @@ async function addTitleText(scene, str, args) { continue } if (!font.characters[char]) continue - let min = Infinity - let max = -Infinity - const character = new THREE.Group() - for (let cube of font.characters[char]) { - if (!cube.parsed) { - cube.parsed = true - for (const [direction, uv] of Object.entries(cube.faces)) { - cube.faces[direction] = { uv } - } - } - - cube = JSON.parse(JSON.stringify(cube)) - min = Math.min(min, cube.from[0], cube.to[0]) - max = Math.max(max, cube.from[0], cube.to[0]) - - if (args.type === "bottom") { - if (cube.to[2] > cube.from[2]) { - cube.to[2] += 20 - } else { - cube.from[2] += 20 - } - } - - const geometry = new THREE.BoxGeometry(cube.to[0] - cube.from[0], cube.to[1] - cube.from[1], cube.to[2] - cube.from[2]) - const mesh = new THREE.Mesh(geometry, material) - - mesh.position.fromArray([ - (cube.from[0] + cube.to[0]) / 2, - (cube.from[1] + cube.to[1]) / 2, - (cube.from[2] + cube.to[2]) / 2 - ]) - - const indexes = { - north: 40, - east: 0, - south: 32, - west: 8, - up: 16, - down: 24 - } - - for (const key of Object.keys(indexes)) { - const face = cube.faces[key] - const i = indexes[key] - if (face) { - const uv = [ - [face.uv[0] / 16, 1 - (face.uv[1] / 16)], - [face.uv[2] / 16, 1 - (face.uv[1] / 16)], - [face.uv[0] / 16, 1 - (face.uv[3] / 16)], - [face.uv[2] / 16, 1 - (face.uv[3] / 16)] - ] - mesh.geometry.attributes.uv.array.set(uv[0], i + 0) - mesh.geometry.attributes.uv.array.set(uv[1], i + 2) - mesh.geometry.attributes.uv.array.set(uv[2], i + 4) - mesh.geometry.attributes.uv.array.set(uv[3], i + 6) - } else { - mesh.geometry.attributes.uv.array.set([1, 1], i + 0) - mesh.geometry.attributes.uv.array.set([1, 1], i + 2) - mesh.geometry.attributes.uv.array.set([1, 1], i + 4) - mesh.geometry.attributes.uv.array.set([1, 1], i + 6) - } - } - character.add(mesh) - cubes.push(mesh) - } - if (i) max += font.characterSpacing ?? 0 - for (const cube of character.children) { - cube.position.x -= width + max - } - group.add(character) - width += max - min + const model = font.characters[char] + width += addModel(scene, model, group, material, cubes, i, font, width, args) } for (const cube of cubes) { cube.position.x += width / 2 } - if (args.row) { - group.position.y += font.height * args.row - } + scene.add(group) +} - if (args.type === "bottom") { - group.scale.setX(0.75) - group.scale.setY(1.6) - group.scale.setZ(0.75) - group.rotation.fromArray([torad(-90), 0, 0]) - group.position.z += font.height + 49 - group.position.y -= 25 - font.depth - } else if (args.type === "small") { - group.scale.setX(0.35) - group.scale.setY(0.35) - group.scale.setZ(0.35) - group.position.y -= font.height * 0.35 - } +function addShape(scene, model, texture) { + texture.colorSpace = THREE.SRGBColorSpace + texture.magFilter = THREE.NearestFilter + texture.minFilter = THREE.NearestFilter + texture.flipY = true - if (args.scale) { - group.scale.setX(group.scale.x * args.scale[0]) - group.scale.setY(group.scale.y * args.scale[1]) - group.scale.setZ(group.scale.z * args.scale[2]) - } + const material = new THREE.MeshBasicMaterial({ + map: texture, + transparent: true, + alphaTest: 0.01 + }) - if (args.rotation) { - const old = group.rotation.toArray() - group.rotation.fromArray(args.rotation.map((e, i) => torad(e) + old[i])) + let width = 0 + const cubes = [] + const group = new THREE.Group() + + width += addModel(scene, model, group, material, cubes, 0, {}, width, {}) + + for (const cube of cubes) { + cube.position.x += width / 2 } scene.add(group) diff --git a/shapes.json b/shapes.json new file mode 100644 index 00000000..a6b158a0 --- /dev/null +++ b/shapes.json @@ -0,0 +1,5 @@ +{ + "minecraft-ten-blank": { + "width": 28 + } +} \ No newline at end of file diff --git a/shapes/minecraft-ten-blank/model.json b/shapes/minecraft-ten-blank/model.json new file mode 100644 index 00000000..c3ec139f --- /dev/null +++ b/shapes/minecraft-ten-blank/model.json @@ -0,0 +1,32 @@ +{ + "credit": "By Ewan Howell", + "texture_size": [28, 86], + "textures": { + "1": "minecraft_ten_blank:flat", + "particle": "minecraft_ten_blank:flat" + }, + "elements": [ + { + "from": [-6, 2, -3], + "to": [22, 42, 19], + "faces": { + "north": {"uv": [0, 4.09302, 16, 11.53488], "texture": "#1"}, + "south": {"uv": [16, 4.09302, 0, 11.53488], "texture": "#1"}, + "up": {"uv": [16, 4.09302, 0, 0], "texture": "#1"}, + "down": {"uv": [16, 15.62791, 0, 11.53488], "texture": "#1"} + } + }, + { + "from": [24, 44, 21], + "to": [-8, 0, -5], + "faces": { + "north": {"uv": [0, 15.81395, 0.57143, 16], "texture": "#1"}, + "east": {"uv": [0, 15.81395, 0.57143, 16], "texture": "#1"}, + "south": {"uv": [0, 15.81395, 0.57143, 16], "texture": "#1"}, + "west": {"uv": [0, 15.81395, 0.57143, 16], "texture": "#1"}, + "up": {"uv": [0, 15.81395, 0.57143, 16], "texture": "#1"}, + "down": {"uv": [0, 15.81395, 0.57143, 16], "texture": "#1"} + } + } + ] +} \ No newline at end of file diff --git a/shapes/minecraft-ten-blank/textures.json b/shapes/minecraft-ten-blank/textures.json new file mode 100644 index 00000000..24cd4436 --- /dev/null +++ b/shapes/minecraft-ten-blank/textures.json @@ -0,0 +1,18 @@ +{ + "flat": { + "author": "Ewan Howell" + }, + "creeper": { + "category": "Heads", + "author": "BitseK", + "variants": { + "creaking": {}, + "enderman": {}, + "glow_squid": {}, + "villager": {}, + "vindicator": {}, + "witch": {}, + "zombie_villager": {} + } + } +} \ No newline at end of file diff --git a/shapes/minecraft-ten-blank/textures/creaking.png b/shapes/minecraft-ten-blank/textures/creaking.png new file mode 100644 index 00000000..f7a58e57 Binary files /dev/null and b/shapes/minecraft-ten-blank/textures/creaking.png differ diff --git a/shapes/minecraft-ten-blank/textures/creeper.png b/shapes/minecraft-ten-blank/textures/creeper.png new file mode 100644 index 00000000..d11a68c6 Binary files /dev/null and b/shapes/minecraft-ten-blank/textures/creeper.png differ diff --git a/shapes/minecraft-ten-blank/textures/enderman.png b/shapes/minecraft-ten-blank/textures/enderman.png new file mode 100644 index 00000000..ab499fca Binary files /dev/null and b/shapes/minecraft-ten-blank/textures/enderman.png differ diff --git a/shapes/minecraft-ten-blank/textures/flat.png b/shapes/minecraft-ten-blank/textures/flat.png new file mode 100644 index 00000000..25a11712 Binary files /dev/null and b/shapes/minecraft-ten-blank/textures/flat.png differ diff --git a/shapes/minecraft-ten-blank/textures/glow_squid.png b/shapes/minecraft-ten-blank/textures/glow_squid.png new file mode 100644 index 00000000..27b9294a Binary files /dev/null and b/shapes/minecraft-ten-blank/textures/glow_squid.png differ diff --git a/shapes/minecraft-ten-blank/textures/villager.png b/shapes/minecraft-ten-blank/textures/villager.png new file mode 100644 index 00000000..feb878ea Binary files /dev/null and b/shapes/minecraft-ten-blank/textures/villager.png differ diff --git a/shapes/minecraft-ten-blank/textures/vindicator.png b/shapes/minecraft-ten-blank/textures/vindicator.png new file mode 100644 index 00000000..0b8b4441 Binary files /dev/null and b/shapes/minecraft-ten-blank/textures/vindicator.png differ diff --git a/shapes/minecraft-ten-blank/textures/witch.png b/shapes/minecraft-ten-blank/textures/witch.png new file mode 100644 index 00000000..613495b0 Binary files /dev/null and b/shapes/minecraft-ten-blank/textures/witch.png differ diff --git a/shapes/minecraft-ten-blank/textures/zombie_villager.png b/shapes/minecraft-ten-blank/textures/zombie_villager.png new file mode 100644 index 00000000..9df2af08 Binary files /dev/null and b/shapes/minecraft-ten-blank/textures/zombie_villager.png differ diff --git a/shapes/minecraft-ten-blank/thumbnails/creaking.png b/shapes/minecraft-ten-blank/thumbnails/creaking.png new file mode 100644 index 00000000..418fb559 Binary files /dev/null and b/shapes/minecraft-ten-blank/thumbnails/creaking.png differ diff --git a/shapes/minecraft-ten-blank/thumbnails/creeper.png b/shapes/minecraft-ten-blank/thumbnails/creeper.png new file mode 100644 index 00000000..0d27cc72 Binary files /dev/null and b/shapes/minecraft-ten-blank/thumbnails/creeper.png differ diff --git a/shapes/minecraft-ten-blank/thumbnails/enderman.png b/shapes/minecraft-ten-blank/thumbnails/enderman.png new file mode 100644 index 00000000..5ac7dd87 Binary files /dev/null and b/shapes/minecraft-ten-blank/thumbnails/enderman.png differ diff --git a/shapes/minecraft-ten-blank/thumbnails/flat.png b/shapes/minecraft-ten-blank/thumbnails/flat.png new file mode 100644 index 00000000..49d581e6 Binary files /dev/null and b/shapes/minecraft-ten-blank/thumbnails/flat.png differ diff --git a/shapes/minecraft-ten-blank/thumbnails/glow_squid.png b/shapes/minecraft-ten-blank/thumbnails/glow_squid.png new file mode 100644 index 00000000..b37d3964 Binary files /dev/null and b/shapes/minecraft-ten-blank/thumbnails/glow_squid.png differ diff --git a/shapes/minecraft-ten-blank/thumbnails/villager.png b/shapes/minecraft-ten-blank/thumbnails/villager.png new file mode 100644 index 00000000..137167b9 Binary files /dev/null and b/shapes/minecraft-ten-blank/thumbnails/villager.png differ diff --git a/shapes/minecraft-ten-blank/thumbnails/vindicator.png b/shapes/minecraft-ten-blank/thumbnails/vindicator.png new file mode 100644 index 00000000..aca04987 Binary files /dev/null and b/shapes/minecraft-ten-blank/thumbnails/vindicator.png differ diff --git a/shapes/minecraft-ten-blank/thumbnails/witch.png b/shapes/minecraft-ten-blank/thumbnails/witch.png new file mode 100644 index 00000000..63e5535a Binary files /dev/null and b/shapes/minecraft-ten-blank/thumbnails/witch.png differ diff --git a/shapes/minecraft-ten-blank/thumbnails/zombie_villager.png b/shapes/minecraft-ten-blank/thumbnails/zombie_villager.png new file mode 100644 index 00000000..056f429e Binary files /dev/null and b/shapes/minecraft-ten-blank/thumbnails/zombie_villager.png differ diff --git a/shapes/shapes.json b/shapes/shapes.json new file mode 100644 index 00000000..39c5cbba --- /dev/null +++ b/shapes/shapes.json @@ -0,0 +1 @@ +{"minecraft-ten-blank":[{"from":[-6,2,-3],"to":[22,42,19],"faces":{"north":{"uv":[0,4.09302,16,11.53488]},"south":{"uv":[16,4.09302,0,11.53488]},"up":{"uv":[16,4.09302,0,0]},"down":{"uv":[16,15.62791,0,11.53488]}},"parsed":true},{"from":[24,44,21],"to":[-8,0,-5],"faces":{"north":{"uv":[0,15.81395,0.57143,16]},"east":{"uv":[0,15.81395,0.57143,16]},"south":{"uv":[0,15.81395,0.57143,16]},"west":{"uv":[0,15.81395,0.57143,16]},"up":{"uv":[0,15.81395,0.57143,16]},"down":{"uv":[0,15.81395,0.57143,16]}},"parsed":true}]} \ No newline at end of file