1+ ( function ( exports ) {
2+ "use strict" ;
3+
4+ // SM64 .bmd format
5+
6+ function readString ( buffer , offs , length ) {
7+ var buf = new Uint8Array ( buffer , offs , length ) ;
8+ var S = '' ;
9+ for ( var i = 0 ; i < length ; i ++ ) {
10+ if ( buf [ i ] === 0 )
11+ break ;
12+ S += String . fromCharCode ( buf [ i ] ) ;
13+ }
14+ return S ;
15+ }
16+
17+ function parseModel ( bmd , view , idx ) {
18+ var offs = bmd . modelOffsBase + idx * 0x40 ;
19+
20+ var model = { } ;
21+ model . id = view . getUint32 ( offs + 0x00 , true ) ;
22+ model . name = readString ( view . buffer , view . getUint32 ( offs + 0x04 , true ) , 0xFF ) ;
23+
24+ model . parentID = view . getUint16 ( offs + 0x08 , true ) ;
25+
26+ // Local transform.
27+ var xs = view . getUint32 ( offs + 0x10 , true ) ;
28+ var ys = view . getUint32 ( offs + 0x14 , true ) ;
29+ var zs = view . getUint32 ( offs + 0x18 , true ) ;
30+ var xr = view . getUint16 ( offs + 0x1C , true ) ;
31+ var yr = view . getUint16 ( offs + 0x1E , true ) ;
32+ var zr = view . getUint16 ( offs + 0x20 , true ) ;
33+ var xt = view . getUint16 ( offs + 0x24 , true ) ;
34+ var yt = view . getUint16 ( offs + 0x28 , true ) ;
35+ var zt = view . getUint16 ( offs + 0x2C , true ) ;
36+
37+ // A "batch" is a combination of a material and a poly.
38+ var batchCount = view . getUint32 ( offs + 0x30 , true ) ;
39+ var batchMaterialOffs = view . getUint32 ( offs + 0x34 , true ) ;
40+ var batchPolyOffs = view . getUint32 ( offs + 0x38 , true ) ;
41+
42+ model . batches = [ ] ;
43+
44+ for ( var i = 0 ; i < batchCount ; i ++ ) {
45+ var materialIdx = view . getUint8 ( batchMaterialOffs + i ) ;
46+ var material = parseMaterial ( bmd , view , materialIdx ) ;
47+ var baseCtx = { s_color : material . diffuse , alpha : material . alpha } ;
48+
49+ var polyIdx = view . getUint8 ( batchPolyOffs + i ) ;
50+ var poly = parsePoly ( bmd , view , polyIdx , baseCtx ) ;
51+
52+ model . batches . push ( { material : material , poly : poly } ) ;
53+ }
54+
55+ return model ;
56+ }
57+
58+ function parsePoly ( bmd , view , idx , baseCtx ) {
59+ var offs = view . getUint32 ( ( bmd . polyOffsBase + idx * 0x08 ) + 0x04 , true ) ;
60+
61+ var gxCmdSize = view . getUint32 ( offs + 0x08 , true ) ;
62+ var gxCmdOffs = view . getUint32 ( offs + 0x0C , true ) ;
63+
64+ var gxCmdBuf = view . buffer . slice ( gxCmdOffs , gxCmdOffs + gxCmdSize ) ;
65+
66+ return { packets : NITRO_GX . readCmds ( gxCmdBuf , baseCtx ) } ;
67+ }
68+
69+ function parseMaterial ( bmd , view , idx ) {
70+ var offs = bmd . materialOffsBase + idx * 0x30 ;
71+
72+ var material = { } ;
73+ material . name = readString ( view . buffer , view . getUint32 ( offs + 0x00 , true ) , 0xFF ) ;
74+ material . texCoordMat = mat4 . create ( ) ;
75+
76+ var textureIdx = view . getUint32 ( offs + 0x04 , true ) ;
77+ if ( textureIdx !== 0xFFFFFFFF ) {
78+ var paletteIdx = view . getUint32 ( offs + 0x08 , true ) ;
79+ material . texture = parseTexture ( bmd , view , textureIdx , paletteIdx ) ;
80+ material . texParams = material . texture . params | view . getUint32 ( offs + 0x20 , true ) ;
81+
82+ if ( material . texParams >> 30 ) {
83+ var scaleS = view . getInt32 ( offs + 0x0C , true ) / 4096.0 ;
84+ var scaleT = view . getInt32 ( offs + 0x10 , true ) / 4096.0 ;
85+ var transS = view . getInt32 ( offs + 0x18 , true ) / 4096.0 ;
86+ var transT = view . getInt32 ( offs + 0x1C , true ) / 4096.0 ;
87+ mat4 . translate ( material . texCoordMat , material . texCoordMat , [ transS , transT , 0.0 ] ) ;
88+ mat4 . scale ( material . texCoordMat , material . texCoordMat , [ scaleS , scaleT , 1.0 ] ) ;
89+ }
90+ mat4 . scale ( material . texCoordMat , material . texCoordMat , [ 1 / material . texture . width , 1 / material . texture . height , 1 ] ) ;
91+ } else {
92+ material . texture = null ;
93+ material . texParams = 0 ;
94+ }
95+
96+ var polyAttribs = view . getUint32 ( offs + 0x24 , true ) ;
97+ var alpha = ( polyAttribs >> 16 ) & 0x1F ;
98+ alpha = ( alpha << ( 8 - 5 ) ) | ( alpha >>> ( 10 - 8 ) ) ;
99+
100+ // NITRO's Rendering Engine uses two passes. Opaque, then Transparent.
101+ // A transparent polygon is one that has an alpha of < 0xFF, or uses
102+ // A5I3 / A3I5 textures.
103+
104+ material . isTranslucent = ( alpha < 0xFF ) || ( material . texture && material . texture . isTranslucent ) ;
105+
106+ // Do transparent polys write to the depth buffer?
107+ var xl = ( polyAttribs >>> 1 ) & 0x01 ;
108+ if ( xl )
109+ material . depthWrite = true ;
110+ else
111+ material . depthWrite = ! material . isTranslucent ;
112+
113+ var difAmb = view . getUint32 ( offs + 0x28 , true ) ;
114+ if ( difAmb & 0x8000 )
115+ material . diffuse = NITRO_GX . rgb5 ( difAmb & 0x07FF ) ;
116+ else
117+ material . diffuse = [ 0xFF , 0xFF , 0xFF ] ;
118+
119+ material . alpha = alpha ;
120+
121+ return material ;
122+ }
123+
124+ function textureToCanvas ( texture ) {
125+ var canvas = document . createElement ( "canvas" ) ;
126+ canvas . width = texture . width ;
127+ canvas . height = texture . height ;
128+
129+ var ctx = canvas . getContext ( "2d" ) ;
130+ var imgData = ctx . createImageData ( canvas . width , canvas . height ) ;
131+
132+ for ( var i = 0 ; i < imgData . data . length ; i ++ )
133+ imgData . data [ i ] = texture . pixels [ i ] ;
134+
135+ canvas . title = texture . name ;
136+
137+ ctx . putImageData ( imgData , 0 , 0 ) ;
138+ return canvas ;
139+ }
140+
141+ function parseTexture ( bmd , view , texIdx , palIdx ) {
142+ var texOffs = bmd . textureOffsBase + texIdx * 0x14 ;
143+
144+ var texture = { } ;
145+ texture . id = texIdx ;
146+ texture . name = readString ( view . buffer , view . getUint32 ( texOffs + 0x00 , true ) , 0xFF ) ;
147+
148+ var texDataOffs = view . getUint32 ( texOffs + 0x04 , true ) ;
149+ var texDataSize = view . getUint32 ( texOffs + 0x08 , true ) ;
150+ var texData = view . buffer . slice ( texDataOffs ) ;
151+
152+ texture . params = view . getUint32 ( texOffs + 0x10 , true ) ;
153+ texture . format = ( texture . params >> 26 ) & 0x07 ;
154+ texture . width = 8 << ( ( texture . params >> 20 ) & 0x07 ) ;
155+ texture . height = 8 << ( ( texture . params >> 23 ) & 0x07 ) ;
156+ var color0 = ( texture . params >> 29 ) & 0x01 ;
157+
158+ var palData = null ;
159+ if ( palIdx != 0xFFFFFFFF ) {
160+ var palOffs = bmd . paletteOffsBase + palIdx * 0x10 ;
161+ texture . paletteName = readString ( view . buffer , view . getUint32 ( palOffs + 0x00 , true ) , 0xFF ) ;
162+ var palDataOffs = view . getUint32 ( palOffs + 0x04 , true ) ;
163+ var palDataSize = view . getUint32 ( palOffs + 0x08 , true ) ;
164+ palData = view . buffer . slice ( palDataOffs , palDataOffs + palDataSize ) ;
165+ }
166+
167+ texture . pixels = NITRO_Tex . readTexture ( texture . format , texture . width , texture . height , texData , palData , color0 ) ;
168+
169+ if ( texture . pixels )
170+ document . querySelector ( '#textures' ) . appendChild ( textureToCanvas ( texture ) ) ;
171+
172+ texture . isTranslucent = ( texture . format === NITRO_Tex . Format . Tex_A5I3 ||
173+ texture . format === NITRO_Tex . Format . Tex_A3I5 ) ;
174+
175+ return texture ;
176+ }
177+
178+ var BMD = { } ;
179+ BMD . parse = function ( buffer ) {
180+ var view = new DataView ( buffer ) ;
181+
182+ var bmd = { } ;
183+
184+ bmd . scaleFactor = ( 1 << view . getUint32 ( 0x00 , true ) ) ;
185+
186+ bmd . modelCount = view . getUint32 ( 0x04 , true ) ;
187+ bmd . modelOffsBase = view . getUint32 ( 0x08 , true ) ;
188+ bmd . polyCount = view . getUint32 ( 0x0C , true ) ;
189+ bmd . polyOffsBase = view . getUint32 ( 0x10 , true ) ;
190+ bmd . textureCount = view . getUint32 ( 0x14 , true ) ;
191+ bmd . textureOffsBase = view . getUint32 ( 0x18 , true ) ;
192+ bmd . paletteCount = view . getUint32 ( 0x1C , true ) ;
193+ bmd . paletteOffsBase = view . getUint32 ( 0x20 , true ) ;
194+ bmd . materialCount = view . getUint32 ( 0x24 , true ) ;
195+ bmd . materialOffsBase = view . getUint32 ( 0x28 , true ) ;
196+
197+ bmd . models = [ ] ;
198+ for ( var i = 0 ; i < bmd . modelCount ; i ++ )
199+ bmd . models . push ( parseModel ( bmd , view , i ) ) ;
200+
201+ return bmd ;
202+ } ;
203+ exports . BMD = BMD ;
204+
205+ } ) ( window ) ;
0 commit comments