Add item model preview
Some checks failed
Deploy to GitHub Pages / build (push) Has been cancelled
Deploy to GitHub Pages / deploy (push) Has been cancelled

This commit is contained in:
Misode
2025-01-03 05:17:19 +01:00
parent 4fd668e44c
commit 2fd90f5dd4
4 changed files with 84 additions and 2 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

View File

@@ -5,9 +5,9 @@ import { useVersion } from '../../contexts/Version.jsx'
import { checkVersion } from '../../services/index.js'
import { safeJsonParse } from '../../Utils.js'
import { ErrorPanel } from '../ErrorPanel.jsx'
import { BiomeSourcePreview, BlockStatePreview, DecoratorPreview, DensityFunctionPreview, LootTablePreview, ModelPreview, NoisePreview, NoiseSettingsPreview, RecipePreview, StructureSetPreview } from '../previews/index.js'
import { BiomeSourcePreview, BlockStatePreview, DecoratorPreview, DensityFunctionPreview, ItemModelPreview, LootTablePreview, ModelPreview, NoisePreview, NoiseSettingsPreview, RecipePreview, StructureSetPreview } from '../previews/index.js'
export const HasPreview = ['loot_table', 'recipe', 'dimension', 'worldgen/density_function', 'worldgen/noise', 'worldgen/noise_settings', 'worldgen/configured_feature', 'worldgen/placed_feature', 'worldgen/structure_set', 'block_definition', 'model']
export const HasPreview = ['loot_table', 'recipe', 'dimension', 'worldgen/density_function', 'worldgen/noise', 'worldgen/noise_settings', 'worldgen/configured_feature', 'worldgen/placed_feature', 'worldgen/structure_set', 'block_definition', 'item_definition', 'model']
type PreviewPanelProps = {
id: string,
@@ -78,6 +78,10 @@ export function PreviewContent({ id, docAndNode, shown }: PreviewContentProps) {
return <BlockStatePreview {...{ docAndNode, shown }} />
}
if (id === 'item_definition') {
return <ItemModelPreview {...{ docAndNode, shown }} />
}
if (id === 'model') {
return <ModelPreview {...{ docAndNode, shown }} />
}

View File

@@ -0,0 +1,77 @@
import { ItemRenderer, ItemStack, NbtString } from 'deepslate'
import { Identifier, ItemModel } from 'deepslate/render'
import { useVersion } from '../../contexts/index.js'
import { useAsync } from '../../hooks/useAsync.js'
import { AsyncCancel } from '../../hooks/useAsyncFn.js'
import { getResources, ResourceWrapper } from '../../services/Resources.js'
import { isObject, safeJsonParse } from '../../Utils.js'
import { ErrorPanel } from '../ErrorPanel.jsx'
import type { PreviewProps } from './index.js'
const PREVIEW_ID = Identifier.parse('misode:preview')
const RENDER_SIZE = 512
export const ItemModelPreview = ({ docAndNode, shown }: PreviewProps) => {
const { version } = useVersion()
const text = docAndNode.doc.getText()
const { value: render, error } = useAsync(async () => {
if (!shown) return AsyncCancel
const resources = await getResources(version, new Map())
const data = safeJsonParse(text) ?? {}
if (!isObject(data) || !isObject(data.model)) {
return undefined
}
const itemModel = ItemModel.fromJson(data.model)
const wrapper = new ResourceWrapper(resources, {
getItemModel(id) {
if (id.equals(PREVIEW_ID)) return itemModel
return null
},
})
const canvas = document.createElement('canvas')
canvas.width = RENDER_SIZE
canvas.height = RENDER_SIZE
const gl = canvas.getContext('webgl2', { preserveDrawingBuffer: true })
if (!gl) {
throw new Error('Cannot get WebGL2 context')
}
const item = new ItemStack(PREVIEW_ID, 1, new Map(Object.entries({
'minecraft:item_model': new NbtString(PREVIEW_ID.toString()),
})))
const renderer = new ItemRenderer(gl, item, wrapper, { display_context: 'gui' })
renderer.drawItem()
const url = canvas.toDataURL()
console.log('DRAW', url)
return url
}, [shown, version, text])
if (error) {
return <ErrorPanel error={error} prefix="Failed to initialize preview: " />
}
return <>
<div class="preview-overlay">
<img src="/images/single_item.png" alt="Container background" class="pixelated" draggable={false} />
{render && <div class="flex items-center justify-center" style={slotStyle()}>
<img src={render} class="w-[88.888%]" />
</div>}
</div>
</>
}
const GUI_WIDTH = 176
const GUI_HEIGHT = 81
const SLOT_SIZE = 72
function slotStyle() {
const x = 52
const y = 4
return {
left: `${x*100/GUI_WIDTH}%`,
top: `${y*100/GUI_HEIGHT}%`,
width: `${SLOT_SIZE*100/GUI_WIDTH}%`,
height: `${SLOT_SIZE*100/GUI_HEIGHT}%`,
}
}

View File

@@ -4,6 +4,7 @@ export * from './BiomeSourcePreview.js'
export * from './BlockStatePreview.jsx'
export * from './DecoratorPreview.js'
export * from './DensityFunctionPreview.js'
export * from './ItemModelPreview.jsx'
export * from './LootTablePreview.jsx'
export * from './ModelPreview.jsx'
export * from './NoisePreview.js'