1+ import { ItemDisplayMode } from 'src/outliner/vanillaItemDisplay'
12import { mergeGeometries } from '../../util/bufferGeometryUtils'
23import { getPathFromResourceLocation , parseResourceLocation } from '../../util/minecraftUtil'
34import { assetsLoaded , getJSONAsset , getPngAssetAsDataUrl } from './assetManager'
45import { parseBlockModel } from './blockModelManager'
56import type { IItemModel } from './model'
67import { TEXTURE_FRAG_SHADER , TEXTURE_VERT_SHADER } from './textureShaders'
78
8- interface ItemModelMesh {
9+ interface ItemMesh {
910 mesh : THREE . Mesh
1011 outline : THREE . LineSegments
1112 boundingBox : THREE . BufferGeometry
1213 isBlock ?: boolean
1314}
1415
1516const LOADER = new THREE . TextureLoader ( )
16- const ITEM_MODEL_CACHE = new Map < string , ItemModelMesh > ( )
17+ const ITEM_MODEL_CACHE = new Map < string , ItemMesh > ( )
1718
18- export async function getItemModel ( item : string ) : Promise < ItemModelMesh | undefined > {
19+ export async function getItemModel (
20+ item : string ,
21+ itemDisplay : ItemDisplayMode
22+ ) : Promise < ItemMesh | undefined > {
1923 await assetsLoaded ( )
20- let result = ITEM_MODEL_CACHE . get ( item )
24+ const cacheKey = item + '|' + itemDisplay
25+ let result = ITEM_MODEL_CACHE . get ( cacheKey )
2126 if ( ! result ) {
22- // console.warn(`Found no cached item model mesh for '${item}'`)
23- result = await parseItemModel ( getItemResourceLocation ( item ) )
24- ITEM_MODEL_CACHE . set ( item , result )
27+ result = await parseItemModel ( getItemResourceLocation ( item ) , itemDisplay )
28+ ITEM_MODEL_CACHE . set ( cacheKey , result )
2529 }
2630 if ( ! result ) return undefined
2731 result = {
@@ -48,7 +52,64 @@ function getItemResourceLocation(item: string) {
4852 return resource . namespace + ':' + 'item/' + resource . path
4953}
5054
51- async function parseItemModel ( location : string , childModel ?: IItemModel ) : Promise < ItemModelMesh > {
55+ const GENERATED_ITEM_DISPLAY_SETTINGS : NonNullable < IItemModel [ 'display' ] > = {
56+ thirdperson_righthand : { translation : [ 0 , 3 , 1 ] , scale : [ 0.55 , 0.55 , 0.55 ] } ,
57+ thirdperson_lefthand : { translation : [ 0 , 3 , 1 ] , scale : [ 0.55 , 0.55 , 0.55 ] } ,
58+ firstperson_righthand : {
59+ rotation : [ 0 , - 90 , 25 ] ,
60+ translation : [ 1.13 , 3.2 , 1.13 ] ,
61+ scale : [ 0.68 , 0.68 , 0.68 ] ,
62+ } ,
63+ firstperson_lefthand : {
64+ rotation : [ 0 , - 90 , 25 ] ,
65+ translation : [ 1.13 , 3.2 , 1.13 ] ,
66+ scale : [ 0.68 , 0.68 , 0.68 ] ,
67+ } ,
68+ ground : { translation : [ 0 , 2 , 0 ] , scale : [ 0.5 , 0.5 , 0.5 ] } ,
69+ head : { rotation : [ 0 , - 180 , 0 ] , translation : [ 0 , 13 , 7 ] } ,
70+ fixed : { rotation : [ 0 , - 180 , 0 ] } ,
71+ }
72+
73+ export function applyModelDisplayTransform (
74+ itemModel : ItemMesh ,
75+ model : IItemModel ,
76+ itemDisplay : ItemDisplayMode
77+ ) {
78+ if ( itemDisplay === 'none' ) return
79+
80+ // default to right hand if left hand display is not defined
81+ if ( itemDisplay === 'thirdperson_lefthand' && ! model . display ?. thirdperson_lefthand ) {
82+ itemDisplay = 'thirdperson_righthand'
83+ }
84+ if ( itemDisplay === 'firstperson_lefthand' && ! model . display ?. firstperson_lefthand ) {
85+ itemDisplay = 'firstperson_righthand'
86+ }
87+
88+ const display = model . display ?. [ itemDisplay ]
89+ if ( ! display ) return
90+
91+ const matrix = new THREE . Matrix4 ( )
92+ if ( display . rotation ) {
93+ const rot = display . rotation . map ( ( n : number ) => ( n * Math . PI ) / 180 )
94+ matrix . makeRotationFromEuler ( new THREE . Euler ( rot [ 0 ] , rot [ 1 ] , rot [ 2 ] ) )
95+ }
96+ if ( display . translation ) {
97+ matrix . setPosition ( new THREE . Vector3 ( ...display . translation ) )
98+ }
99+ if ( display . scale ) {
100+ matrix . scale ( new THREE . Vector3 ( ...display . scale ) )
101+ }
102+
103+ itemModel . boundingBox . applyMatrix4 ( matrix )
104+ itemModel . outline . geometry . applyMatrix4 ( matrix )
105+ itemModel . mesh . applyMatrix4 ( matrix )
106+ }
107+
108+ async function parseItemModel (
109+ location : string ,
110+ itemDisplay : ItemDisplayMode ,
111+ childModel ?: IItemModel
112+ ) : Promise < ItemMesh > {
52113 const modelPath = getPathFromResourceLocation ( location , 'models' )
53114 let model : IItemModel
54115 try {
@@ -75,22 +136,27 @@ async function parseItemModel(location: string, childModel?: IItemModel): Promis
75136
76137 if ( model . parent ) {
77138 const resource = parseResourceLocation ( model . parent )
78- console . log ( 'Parsed resource:' , resource )
79139 if ( resource . type === 'block' ) {
80- return await parseBlockModel ( { model : model . parent , isItemModel : true } , model )
81- }
82- if ( resource . path === 'item/generated' ) {
83- return await generateItemMesh ( location , model )
140+ return await parseBlockModel (
141+ { model : model . parent , isItemModel : true } ,
142+ model ,
143+ itemDisplay
144+ )
145+ } else if ( resource . path === 'item/generated' ) {
146+ const itemMesh = await generateItemMesh ( location , model )
147+ model . display ??= GENERATED_ITEM_DISPLAY_SETTINGS
148+ applyModelDisplayTransform ( itemMesh , model , itemDisplay )
149+ return itemMesh
84150 } else {
85- return await parseItemModel ( model . parent , model )
151+ return await parseItemModel ( model . parent , itemDisplay , model )
86152 }
87153 } else {
88154 // The block model parser handles custom item models made from elements just fine, so we can use it here
89- return await parseBlockModel ( { model : location , isItemModel : true } , model )
155+ return await parseBlockModel ( { model : location , isItemModel : true } , model , itemDisplay )
90156 }
91157}
92158
93- async function generateItemMesh ( location : string , model : IItemModel ) : Promise < ItemModelMesh > {
159+ async function generateItemMesh ( location : string , model : IItemModel ) : Promise < ItemMesh > {
94160 const masterMesh = new THREE . Mesh ( )
95161 const boundingBoxes : THREE . BufferGeometry [ ] = [ ]
96162 const outlineGeos : THREE . BufferGeometry [ ] = [ ]
0 commit comments