Skip to content

Commit 2fd90f5

Browse files
committed
Add item model preview
1 parent 4fd668e commit 2fd90f5

File tree

4 files changed

+84
-2
lines changed

4 files changed

+84
-2
lines changed

public/images/single_item.png

586 Bytes
Loading

src/app/components/generator/PreviewPanel.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { useVersion } from '../../contexts/Version.jsx'
55
import { checkVersion } from '../../services/index.js'
66
import { safeJsonParse } from '../../Utils.js'
77
import { ErrorPanel } from '../ErrorPanel.jsx'
8-
import { BiomeSourcePreview, BlockStatePreview, DecoratorPreview, DensityFunctionPreview, LootTablePreview, ModelPreview, NoisePreview, NoiseSettingsPreview, RecipePreview, StructureSetPreview } from '../previews/index.js'
8+
import { BiomeSourcePreview, BlockStatePreview, DecoratorPreview, DensityFunctionPreview, ItemModelPreview, LootTablePreview, ModelPreview, NoisePreview, NoiseSettingsPreview, RecipePreview, StructureSetPreview } from '../previews/index.js'
99

10-
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']
10+
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']
1111

1212
type PreviewPanelProps = {
1313
id: string,
@@ -78,6 +78,10 @@ export function PreviewContent({ id, docAndNode, shown }: PreviewContentProps) {
7878
return <BlockStatePreview {...{ docAndNode, shown }} />
7979
}
8080

81+
if (id === 'item_definition') {
82+
return <ItemModelPreview {...{ docAndNode, shown }} />
83+
}
84+
8185
if (id === 'model') {
8286
return <ModelPreview {...{ docAndNode, shown }} />
8387
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { ItemRenderer, ItemStack, NbtString } from 'deepslate'
2+
import { Identifier, ItemModel } from 'deepslate/render'
3+
import { useVersion } from '../../contexts/index.js'
4+
import { useAsync } from '../../hooks/useAsync.js'
5+
import { AsyncCancel } from '../../hooks/useAsyncFn.js'
6+
import { getResources, ResourceWrapper } from '../../services/Resources.js'
7+
import { isObject, safeJsonParse } from '../../Utils.js'
8+
import { ErrorPanel } from '../ErrorPanel.jsx'
9+
import type { PreviewProps } from './index.js'
10+
11+
const PREVIEW_ID = Identifier.parse('misode:preview')
12+
const RENDER_SIZE = 512
13+
14+
export const ItemModelPreview = ({ docAndNode, shown }: PreviewProps) => {
15+
const { version } = useVersion()
16+
17+
const text = docAndNode.doc.getText()
18+
19+
const { value: render, error } = useAsync(async () => {
20+
if (!shown) return AsyncCancel
21+
const resources = await getResources(version, new Map())
22+
const data = safeJsonParse(text) ?? {}
23+
if (!isObject(data) || !isObject(data.model)) {
24+
return undefined
25+
}
26+
const itemModel = ItemModel.fromJson(data.model)
27+
const wrapper = new ResourceWrapper(resources, {
28+
getItemModel(id) {
29+
if (id.equals(PREVIEW_ID)) return itemModel
30+
return null
31+
},
32+
})
33+
const canvas = document.createElement('canvas')
34+
canvas.width = RENDER_SIZE
35+
canvas.height = RENDER_SIZE
36+
const gl = canvas.getContext('webgl2', { preserveDrawingBuffer: true })
37+
if (!gl) {
38+
throw new Error('Cannot get WebGL2 context')
39+
}
40+
const item = new ItemStack(PREVIEW_ID, 1, new Map(Object.entries({
41+
'minecraft:item_model': new NbtString(PREVIEW_ID.toString()),
42+
})))
43+
const renderer = new ItemRenderer(gl, item, wrapper, { display_context: 'gui' })
44+
renderer.drawItem()
45+
const url = canvas.toDataURL()
46+
console.log('DRAW', url)
47+
return url
48+
}, [shown, version, text])
49+
50+
if (error) {
51+
return <ErrorPanel error={error} prefix="Failed to initialize preview: " />
52+
}
53+
54+
return <>
55+
<div class="preview-overlay">
56+
<img src="/images/single_item.png" alt="Container background" class="pixelated" draggable={false} />
57+
{render && <div class="flex items-center justify-center" style={slotStyle()}>
58+
<img src={render} class="w-[88.888%]" />
59+
</div>}
60+
</div>
61+
</>
62+
}
63+
64+
const GUI_WIDTH = 176
65+
const GUI_HEIGHT = 81
66+
const SLOT_SIZE = 72
67+
68+
function slotStyle() {
69+
const x = 52
70+
const y = 4
71+
return {
72+
left: `${x*100/GUI_WIDTH}%`,
73+
top: `${y*100/GUI_HEIGHT}%`,
74+
width: `${SLOT_SIZE*100/GUI_WIDTH}%`,
75+
height: `${SLOT_SIZE*100/GUI_HEIGHT}%`,
76+
}
77+
}

src/app/components/previews/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export * from './BiomeSourcePreview.js'
44
export * from './BlockStatePreview.jsx'
55
export * from './DecoratorPreview.js'
66
export * from './DensityFunctionPreview.js'
7+
export * from './ItemModelPreview.jsx'
78
export * from './LootTablePreview.jsx'
89
export * from './ModelPreview.jsx'
910
export * from './NoisePreview.js'

0 commit comments

Comments
 (0)