diff --git a/prismarine-viewer/viewer/prepare/atlas.ts b/prismarine-viewer/viewer/prepare/atlas.ts index cb30b727..fc3e4029 100644 --- a/prismarine-viewer/viewer/prepare/atlas.ts +++ b/prismarine-viewer/viewer/prepare/atlas.ts @@ -35,7 +35,7 @@ export type JsonAtlas = { } } -export const makeTextureAtlas = (input: string[], getInputData: (name) => { contents: string, tileWidthMult?: number }, tilesCount = input.length, suSvOptimize: 'remove' | null = null): { +export const makeTextureAtlas = (input: string[], getInputData: (name) => { contents: string, tileWidthMult?: number, origSizeTextures?}, tilesCount = input.length, suSvOptimize: 'remove' | null = null): { image: Buffer, canvas: Canvas, json: JsonAtlas @@ -49,6 +49,7 @@ export const makeTextureAtlas = (input: string[], getInputData: (name) => { cont const texturesIndex = {} + let skipXY = [] as [x: number, y: number][] let offset = 0 const suSv = tileSize / imgSize for (const i in input) { @@ -56,20 +57,44 @@ export const makeTextureAtlas = (input: string[], getInputData: (name) => { cont const x = (pos % texSize) * tileSize const y = Math.floor(pos / texSize) * tileSize + if (skipXY.some(([sx, sy]) => sx === x + 1 && sy === y)) { + // todo more offsets + offset++ + } + const img = new Image() - const keyValue = input[i]; - const inputData = getInputData(keyValue); + const keyValue = input[i] + const inputData = getInputData(keyValue) img.src = inputData.contents - const renderWidth = tileSize * (inputData.tileWidthMult ?? 1) - g.drawImage(img, 0, 0, renderWidth, tileSize, x, y, renderWidth, tileSize) + let su = suSv + let sv = suSv + let renderWidth = tileSize * (inputData.tileWidthMult ?? 1) + let renderHeight = tileSize + if (inputData.origSizeTextures?.[keyValue]) { + // todo check have enough space + renderWidth = Math.ceil(img.width / tileSize) * tileSize + renderHeight = Math.ceil(img.height / tileSize) * tileSize + su = renderWidth / imgSize + sv = renderHeight / imgSize + if (renderWidth > tileSize) { + offset += Math.ceil(renderWidth / tileSize) - 1 + } + if (renderHeight > tileSize) { + const skipYs = Math.ceil(renderHeight / tileSize) - 1 + for (let i = 1; i <= skipYs; i++) { + skipXY.push([x, y + i]) + } + } + } + g.drawImage(img, 0, 0, renderWidth, renderHeight, x, y, renderWidth, renderHeight) const cleanName = keyValue.split('.').slice(0, -1).join('.') || keyValue texturesIndex[cleanName] = { u: x / imgSize, v: y / imgSize, ...suSvOptimize === 'remove' ? {} : { - su: suSv, - sv: suSv + su: su, + sv: sv } } } @@ -91,7 +116,7 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) { // const textureFiles = mostEncounteredBlocks.map(x => x + '.png') textureFiles.unshift(...localTextures) - const { generated: additionalTextures, twoTileTextures } = getAdditionalTextures() + const { generated: additionalTextures, twoTileTextures, origSizeTextures } = getAdditionalTextures() textureFiles.push(...Object.keys(additionalTextures)) const atlas = makeTextureAtlas(textureFiles, name => { @@ -105,6 +130,7 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) { return { contents, tileWidthMult: twoTileTextures.includes(name) ? 2 : undefined, + origSizeTextures } }) return atlas diff --git a/prismarine-viewer/viewer/prepare/blockModels/decorated_pot.json b/prismarine-viewer/viewer/prepare/blockModels/decorated_pot.json new file mode 100644 index 00000000..364c72d4 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/blockModels/decorated_pot.json @@ -0,0 +1,47 @@ +{ + "texture_size": [32, 32], + "textures": { + "0": "entity/decorated_pot/decorated_pot_base" + }, + "elements": [ + { + "name": "Body", + "from": [1, 0, 1], + "to": [15, 16, 15], + "faces": { + "north": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "east": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "south": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "west": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "up": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"}, + "down": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"} + } + }, + { + "name": "Neck", + "from": [5, 16, 5], + "to": [11, 17, 11], + "faces": { + "north": {"uv": [6, 5.5, 9, 6], "texture": "#0"}, + "east": {"uv": [9, 5.5, 12, 6], "texture": "#0"}, + "south": {"uv": [2.5, 5.5, 5.5, 6], "texture": "#0"}, + "west": {"uv": [0, 5.5, 3, 6], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 3], "texture": "#0"}, + "down": {"uv": [0, 0, 3, 3], "texture": "#0"} + } + }, + { + "name": "Head", + "from": [4, 17, 4], + "to": [12, 20, 12], + "faces": { + "north": {"uv": [0, 4, 4, 5.5], "texture": "#0"}, + "east": {"uv": [4, 4, 8, 5.5], "texture": "#0"}, + "south": {"uv": [8, 4, 12, 5.5], "texture": "#0"}, + "west": {"uv": [12, 4, 16, 5.5], "texture": "#0"}, + "up": {"uv": [4, 0, 8, 4], "texture": "#0"}, + "down": {"uv": [8, 0, 12, 4], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/blockStates/decorated_pot.json b/prismarine-viewer/viewer/prepare/blockStates/decorated_pot.json new file mode 100644 index 00000000..5b46a220 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/blockStates/decorated_pot.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "decorated_pot", + "y": 90 + }, + "facing=south": { + "model": "decorated_pot", + "y": 180 + }, + "facing=west": { + "model": "decorated_pot", + "y": 270 + }, + "facing=north": { + "model": "decorated_pot" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts index ffb1a705..6b21380a 100644 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts @@ -7,6 +7,7 @@ import { fileURLToPath } from 'url' // todo refactor const twoTileTextures: string[] = [] +const origSizeTextures: string[] = [] let currentImage: Jimp let currentBlockName: string let currentMcAssets: McAssets @@ -82,7 +83,7 @@ const getBlockTexturesFromJimp = async > (sides: for (const [side, jimp] of Object.entries(sides)) { const textureName = `${textureNameBase}_${side}` const sideTexture = withUv ? { uv: [0, 0, jimp.getWidth(), jimp.getHeight()], texture: textureName } : textureName - const base64 = await jimp.getBase64Async(jimp.getMIME()) + const base64Url = await jimp.getBase64Async(jimp.getMIME()) if (side === 'side') { sidesTextures['north'] = sideTexture sidesTextures['east'] = sideTexture @@ -91,7 +92,7 @@ const getBlockTexturesFromJimp = async > (sides: } else { sidesTextures[side] = sideTexture } - generatedImageTextures[textureName] = base64 + generatedImageTextures[textureName] = base64Url } return sidesTextures @@ -401,6 +402,20 @@ const handleChest = async (dataBase: string, match: RegExpExecArray) => { currentMcAssets.blocksStates[currentBlockName] = blockStates } +const handleDecoratedPot = async (dataBase: string, match: RegExpExecArray) => { + currentMcAssets.blocksStates[currentBlockName] = JSON.parse(fs.readFileSync(path.join(__dirname, 'blockStates/decorated_pot.json'), 'utf-8')) + const blockModel = JSON.parse(fs.readFileSync(path.join(__dirname, 'blockModels/decorated_pot.json'), 'utf-8')) + currentImage = await Jimp.read(dataBase + `entity/decorated_pot/decorated_pot_base.png`) + // resize from 32x32 to 16x16 without cropping the image + // const baseBase64 = await currentImage.clone().resize(16, 16).getBase64Async(Jimp.MIME_PNG) + // const baseBase64 = await currentImage.getBase64Async(Jimp.MIME_PNG) + blockModel.textures.particle = 'flower_pot' + generatedImageTextures['decorated_pot_base'] = `data:image/png;base64,${fs.readFileSync(path.join(dataBase, 'entity/decorated_pot/decorated_pot_base.png'), 'base64')}` + // generatedImageTextures['decorated_pot_base'] = baseBase64 + origSizeTextures['decorated_pot_base'] = true + currentMcAssets.blocksModels[currentBlockName] = blockModel +} + const handlers = [ [/(.+)_shulker_box$/, handleShulkerBox], [/^shulker_box$/, handleShulkerBox], @@ -410,6 +425,7 @@ const handlers = [ [/(.+)_wall_sign$/, handleSign], [/(.+)_sign$/, handleSign], [/^(?:(ender|trapped)_)?chest$/, handleChest], + [/^decorated_pot$/, handleDecoratedPot], // [/(^|(.+)_)bed$/, handleBed], // no-op just suppress warning [/(^light|^moving_piston$)/, true], @@ -462,5 +478,5 @@ export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { } export const getAdditionalTextures = () => { - return { generated: generatedImageTextures, twoTileTextures } + return { generated: generatedImageTextures, twoTileTextures, origSizeTextures } }