View difference between Paste ID: 8EpNVp1e and STVqpQ8F
SHOW: | | - or go back to the newest paste.
1
import java.io.BufferedInputStream;
2
import java.io.File;
3
import java.io.FileInputStream;
4
import java.io.FileNotFoundException;
5
import java.io.IOException;
6
import java.util.ArrayList;
7
8
import android.opengl.Matrix;
9
import android.os.Environment;
10
11
public class Load3DS {
12
	private final int CHUNK_MAIN     = 0x4D4D;
13
	private final int CHUNK_OBJMESH  = 0x3D3D;
14
	private final int CHUNK_OBJBLOCK = 0x4000;
15
	private final int CHUNK_TRIMESH  = 0x4100;
16
	private final int CHUNK_VERTLIST = 0x4110;
17
	private final int CHUNK_FACELIST = 0x4120;
18
	private final int CHUNK_FACEMAT  = 0x4130;
19
	private final int CHUNK_MAPLIST  = 0x4140;
20
	private final int CHUNK_SMOOTHG  = 0x4150;
21
	private final int CHUNK_TRMATRIX = 0x4160;
22
	private final int CHUNK_LIGHT    = 0x4600;
23
	private final int CHUNK_SPOTL    = 0x4610;
24
	private final int CHUNK_ONOFF    = 0x4620;
25
	private final int CHUNK_CAMERA   = 0x4700;
26
	private final int CHUNK_RGBC     = 0x0010;
27
	private final int CHUNK_RGB24    = 0x0011;
28
	private final int CHUNK_SHORT    = 0x0030;
29
	private final int CHUNK_BACKCOL  = 0x1200;
30
	private final int CHUNK_AMB      = 0x2100;
31
	private final int CHUNK_MATERIAL = 0xAFFF;
32
	private final int CHUNK_MATNAME  = 0xA000;
33
	private final int CHUNK_AMBIENT  = 0xA010;
34
	private final int CHUNK_DIFFUSE  = 0xA020;
35
	private final int CHUNK_SPECULAR = 0xA030;
36
	private final int CHUNK_SHININES = 0xA040;
37
	private final int CHUNK_SHINSTRN = 0xA041;
38
	private final int CHUNK_TRANSP   = 0xA050;
39
	private final int CHUNK_SELFILL  = 0xA084;
40
	private final int CHUNK_MTLTYPE  = 0xA100;
41
	private final int CHUNK_TEXTURE  = 0xA200;
42
	private final int CHUNK_REFLMAP  = 0xA220;
43
	private final int CHUNK_BUMPMAP  = 0xA230;
44
	private final int CHUNK_MAPFILE  = 0xA300;
45
	private final int CHUNK_MAPPARAM = 0xA351;
46
	private final int CHUNK_KEYFRAMER = 0xB000;
47
	private final int CHUNK_TRACKINFO = 0xB002;
48
	private final int CHUNK_SPOTINFO  = 0xB007;
49
	private final int CHUNK_FRAMES    = 0xB008;
50
	private final int CHUNK_OBJNAME   = 0xB010;
51
	private final int CHUNK_PIVOT     = 0xB013;
52
	private final int CHUNK_TRACKPOS  = 0xB020;
53
	private final int CHUNK_TRACKROT  = 0xB021;
54
	private final int CHUNK_TRACKSCL  = 0xB022;
55
	private final int CHUNK_HIERARCHY = 0xB030;
56
57
	private BufferedInputStream file;
58
	private byte[] bytes = new byte[8];
59
	private long filePos;
60
61
	public Scene3D Load(String fileName)
62
	{
63
		file = null;
64
		Scene3D scene = null; 
65
		File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
66
		File fil = new File(dir.getAbsolutePath() + File.separator + fileName);
67
		if (!fil.exists()) return scene;
68
69
		try {
70
			filePos = 0;
71
			file = new BufferedInputStream(new FileInputStream(fil));
72
			scene = ProcessFile(fil.length());
73
		} catch (FileNotFoundException e) {
74
			e.printStackTrace();
75
		} catch (IOException e) {
76
			e.printStackTrace();
77
		}
78
		
79
		try {
80
			if (file != null)
81
				file.close();
82
		} catch (IOException e) {
83
			e.printStackTrace();
84
		}
85
		
86
		return scene;
87
	}
88
	
89
	private void Skip(long count) throws IOException
90
	{
91
		file.skip(count);
92
		filePos += count;
93
	}
94
95
	private void Seek(long end) throws IOException
96
	{
97
		if (filePos < end) {
98
			Skip(end - filePos);
99
			filePos = end;
100
		}
101
	}
102
103
	private byte ReadByte() throws IOException
104
	{
105
		file.read(bytes, 0, 1);
106
		filePos++;
107
		return bytes[0];
108
	}
109
110
	private int ReadUnsignedByte() throws IOException
111
	{
112
		file.read(bytes, 0, 1);
113
		filePos++;
114
		return (bytes[0]&0xff);
115
	}
116
117
	private int ReadUnsignedShort() throws IOException
118
	{
119
		file.read(bytes, 0, 2);
120
		filePos += 2;
121
		return ((bytes[1]&0xff) << 8 | (bytes[0]&0xff));
122
	}
123
124
	private int ReadInt() throws IOException
125
	{
126
		file.read(bytes, 0, 4);
127
		filePos += 4;
128
		return (bytes[3]) << 24 | (bytes[2]&0xff) << 16 | (bytes[1]&0xff) <<  8 | (bytes[0]&0xff);
129
	}
130
	
131
	private float ReadFloat() throws IOException
132
	{
133
		return Float.intBitsToFloat(ReadInt());
134
	}
135
136
	private Scene3D ProcessFile(long fileLen) throws IOException
137
	{
138
		Scene3D scene = null;
139
140
		while (filePos < fileLen) {
141
			int chunkID = ReadUnsignedShort();
142
			int chunkLen = ReadInt() - 6;
143
144
			switch (chunkID) {
145
			case CHUNK_MAIN:
146
				if (scene == null)
147
					scene = ChunkMain(chunkLen);
148
				else
149
					Skip(chunkLen);
150
				break;
151
152
			default:
153
				Skip(chunkLen);
154
			}
155
		}
156
		
157
		return scene;
158
	}
159
160
	private Scene3D ChunkMain(int len) throws IOException
161
	{
162
		Scene3D scene = new Scene3D();
163
		scene.materials = new ArrayList<Material3D>();
164
		scene.objects = new ArrayList<Object3D>();
165
		scene.lights = new ArrayList<Light3D>();
166
		scene.animations = new ArrayList<Animation>();
167
168
		long end = filePos + len;
169
		while (filePos < end) {
170
			int chunkID = ReadUnsignedShort();
171
			int chunkLen = ReadInt() - 6;
172
173
			switch (chunkID) {
174
			case CHUNK_OBJMESH:
175
				Chunk3DEditor(scene, chunkLen);
176
				break;
177
178
			case CHUNK_KEYFRAMER:
179
				ChunkKeyframer(scene, chunkLen);
180
				break;
181
182
			case CHUNK_BACKCOL:
183
				scene.background = new float[4];
184
				ChunkColor(chunkLen, scene.background);
185
				break;
186
187
			case CHUNK_AMB:
188
				scene.ambient = new float[4];
189
				ChunkColor(chunkLen, scene.ambient);
190
				break;
191
192
			default:
193
				Skip(chunkLen);
194
			}
195
		}
196
		Seek(end);
197
198
		scene.Compute(0);
199
200
		return scene;
201
	}
202
203
	private void Chunk3DEditor(Scene3D scene, int len) throws IOException
204
	{
205
		long end = filePos + len;
206
		while (filePos < end) {
207
			int chunkID = ReadUnsignedShort();
208
			int chunkLen = ReadInt() - 6;
209
210
			switch (chunkID) {
211
			case CHUNK_OBJBLOCK:
212
				ChunkObject(scene, chunkLen);
213
				break;
214
215
			case CHUNK_MATERIAL:
216
				Material3D mat = ChunkMaterial(scene, chunkLen);
217
				if (mat != null)
218
					scene.materials.add(mat);
219
				break;
220
221
			default:
222
				Skip(chunkLen);
223
			}
224
		}
225
		Seek(end);
226
	}
227
228
	private void ChunkObject(Scene3D scene, int len) throws IOException
229
	{
230
		long end = filePos + len;
231
232
		if (len == 0) return;
233
		String name = ChunkName(0);
234
235
		while (filePos < end) {
236
			int chunkID = ReadUnsignedShort();
237
			int chunkLen = ReadInt() - 6;
238
239
			switch (chunkID) {
240
			case CHUNK_TRIMESH:
241
				Object3D obj = ChunkTrimesh(chunkLen, name, scene);
242
				if (obj != null)
243
					scene.objects.add(obj);
244
				break;
245
246
			case CHUNK_LIGHT:
247
				Light3D light = ChunkLight(chunkLen, name);
248
				if (light != null)
249
					scene.lights.add(light);
250
				break;
251
252
			case CHUNK_CAMERA:
253
			default:
254
				Skip(chunkLen);
255
			}
256
		}
257
		Seek(end);
258
	}
259
260
	private Object3D ChunkTrimesh(int len, String name, Scene3D scene) throws IOException
261
	{
262
		long end = filePos + len;
263
264
		Object3D obj = new Object3D();
265
		obj.name = name;
266
		obj.faceMats = new ArrayList<FaceMat>();
267
		obj.indCount = 0;
268
269
		int i, k, num;
270
271
		while (filePos < end) {
272
			int chunkID = ReadUnsignedShort();
273
			int chunkLen = ReadInt() - 6;
274
275
			switch (chunkID) {
276
			case CHUNK_FACELIST:
277
				ChunkFaceList(chunkLen, obj, scene);
278
				break;
279
280
			case CHUNK_MAPLIST:
281-
				num = 2 * ReadUnsignedShort();
281+
282-
				obj.textureBuffer = new float[num];
282+
				for (i = 0, k = 6; i < num; i++, k += 8) {
283-
				for (i = 0; i < num; i++)
283+
					obj.vertexBuffer[k + 0] = ReadFloat();
284-
					obj.textureBuffer[i] = ReadFloat();
284+
					obj.vertexBuffer[k + 1] = 1 - ReadFloat();
285
				}
286
				break;
287
288
			case CHUNK_VERTLIST:
289
				num = ReadUnsignedShort();
290-
				obj.vertexBuffer = new float[6*num];
290+
291-
				for (i = 0, k = 0; i < num; i++, k += 6) {
291+
				obj.vertexBuffer = new float[8*num];
292
				for (i = 0, k = 0; i < num; i++, k += 8) {
293
					ChunkVector(obj.vertexBuffer, k);
294
					obj.vertexBuffer[k + 3] = 0;
295
					obj.vertexBuffer[k + 4] = 0;
296
					obj.vertexBuffer[k + 5] = 0;
297
					obj.vertexBuffer[k + 6] = 0;
298
					obj.vertexBuffer[k + 7] = 0;
299
				}
300
				break;
301
302
			case CHUNK_TRMATRIX:
303
				float[] localCoord = new float[16];
304
				ChunkVector(localCoord, 4*0);
305
				ChunkVector(localCoord, 4*2);
306
				ChunkVector(localCoord, 4*1);
307
				ChunkVector(localCoord, 4*3);
308
				localCoord[3] = localCoord[7] = localCoord[11] = 0;
309
				localCoord[15] = 1;
310
311
				obj.trMatrix = new float[16];
312
				Matrix.invertM(obj.trMatrix, 0, localCoord, 0);
313
				break;
314
315
			default:
316
				Skip(chunkLen);
317
			}
318
		}
319
		Seek(end);
320
321
		return obj;
322
	}
323
	
324
	private static void CrossProduct(float[] res, float[] v1, float[] v2)
325
	{
326
		res[0] = v1[1]*v2[2] - v1[2]*v2[1];
327
		res[1] = v1[2]*v2[0] - v1[0]*v2[2];
328
		res[2] = v1[0]*v2[1] - v1[1]*v2[0];
329
	}
330
331
	private static float DotSquare(float[] v, int offset)
332
	{
333
		return v[offset + 0]*v[offset + 0] + v[offset + 1]*v[offset + 1] + v[offset + 2]*v[offset + 2];
334
	}
335
336
	private static void VecSubstract(float[] res, float[] v, int offset1, int offset2)
337
	{
338
		res[0] = v[offset1 + 0] - v[offset2 + 0];
339
		res[1] = v[offset1 + 1] - v[offset2 + 1];
340
		res[2] = v[offset1 + 2] - v[offset2 + 2];
341
	}
342
343
	private static void VecAdd(float[] v, int offset, float[] a)
344
	{
345
		v[offset + 0] += a[0];
346
		v[offset + 1] += a[1];
347
		v[offset + 2] += a[2];
348
	}
349
	
350
	private void VecNormalize(float[] v, int offset)
351
	{
352
		double nlen = 1 / Math.sqrt(DotSquare(v, offset));
353
		v[offset + 0] *= nlen;
354
		v[offset + 1] *= nlen;
355
		v[offset + 2] *= nlen;
356
	}
357
358
	private void ChunkFaceList(int len, Object3D obj, Scene3D scene) throws IOException
359
	{
360
		long end = filePos + len;
361
362
		int i, j, k, l, num = ReadUnsignedShort(), unused = num, idx;
363
364
		obj.faceCount = num;
365
		obj.faceBuffer = new int[3*num];
366
		obj.faceUsed = new boolean[num];
367
		float[] v = new float[3]; 
368
		float[] v1 = new float[3]; 
369
		float[] v2 = new float[3]; 
370
371
		for (i = 0, idx = 0; i < num; i++, idx += 3) {
372
			j = ReadUnsignedShort();
373
			k = ReadUnsignedShort();
374
			l = ReadUnsignedShort();
375
			Skip(2);
376
377
			obj.faceUsed[i] = false;
378
			obj.faceBuffer[idx + 0] = j;
379-
			j *= 6;
379+
380-
			k *= 6;
380+
381-
			l *= 6;
381+
382
			j *= 8;
383
			k *= 8;
384
			l *= 8;
385
			VecSubstract(v1, obj.vertexBuffer, l, j);
386
			VecSubstract(v2, obj.vertexBuffer, k, j);
387
			CrossProduct(v, v1, v2);
388
389
			VecAdd(obj.vertexBuffer, j + 3, v);
390
			VecAdd(obj.vertexBuffer, k + 3, v);
391-
		for (i = 0, k = 3; i < obj.vertCount; i++, k += 6)
391+
392
		}
393
394
		for (i = 0, k = 3; i < obj.vertCount; i++, k += 8)
395
			VecNormalize(obj.vertexBuffer, k);
396
397
		v = null;
398
		v1 = null;
399
		v2 = null;
400
401
		while (filePos < end) {
402
			int chunkID = ReadUnsignedShort();
403
			int chunkLen = ReadInt() - 6;
404
405
			switch (chunkID) {
406
			case CHUNK_FACEMAT:
407
				FaceMat mat = new FaceMat();
408
				String name = ChunkName(0);
409
				mat.material = scene.FindMaterial(name);
410
				num = ReadUnsignedShort();
411
				mat.faces = num;
412
				mat.indexBuffer = new short[3*num];
413
				mat.bufOffset = obj.indCount;
414
				obj.indCount += 3*num;
415
				k = 0;
416
				for (i = 0; i < num; i++) {
417
					j = ReadUnsignedShort();
418
					if (!obj.faceUsed[j]) {
419
						obj.faceUsed[j] = true;
420
						unused--;
421
					}
422
					j *= 3;
423
					mat.indexBuffer[k++] = (short) obj.faceBuffer[j + 0];
424
					mat.indexBuffer[k++] = (short) obj.faceBuffer[j + 1];
425
					mat.indexBuffer[k++] = (short) obj.faceBuffer[j + 2];
426
				}
427
				obj.faceMats.add(mat);
428
				break;
429
430
			case CHUNK_SMOOTHG:
431
			default:
432
				Skip(chunkLen);
433
			}
434
		}
435
		Seek(end);
436
		
437
		if (unused > 0) {
438
			FaceMat mat = new FaceMat();
439
			mat.faces = unused;
440
			mat.indexBuffer = new short[3*unused];
441
			mat.bufOffset = obj.indCount;
442
			obj.indCount += 3*unused;
443
			k = 0;
444
			for (i = 0; i < obj.faceCount; i++)
445
				if (!obj.faceUsed[i]) {
446
					obj.faceUsed[i] = true;
447
					j = i * 3;
448
					mat.indexBuffer[k++] = (short) obj.faceBuffer[j + 0];
449
					mat.indexBuffer[k++] = (short) obj.faceBuffer[j + 1];
450
					mat.indexBuffer[k++] = (short) obj.faceBuffer[j + 2];
451
				}
452
			obj.faceMats.add(mat);
453
		}
454
455
		obj.faceBuffer = null;
456
		obj.faceUsed = null;
457
	}
458
459
	private Light3D ChunkLight(int len, String name) throws IOException
460
	{
461
		long end = filePos + len;
462
463
		Light3D light = new Light3D();
464
		light.name = name;
465
		light.pos = new float[3];
466
		ChunkVector(light.pos, 0);
467
468
		while (filePos < end) {
469
			int chunkID = ReadUnsignedShort();
470
			int chunkLen = ReadInt() - 6;
471
472
			switch (chunkID) {
473
			case CHUNK_RGBC:
474
				light.color = new float[4];
475
				ChunkRGBC(light.color);
476
				break;
477
478
			case CHUNK_RGB24:
479
				light.color = new float[4];
480
				ChunkRGB24(light.color);
481
				break;
482
483
			case CHUNK_SPOTL:
484
				light.dir = new float[4];
485
				ChunkVector(light.dir, 0);
486
				light.theta = (float) (ReadFloat() * Math.PI / 180.0f);
487
				light.phi = (float) (ReadFloat() * Math.PI / 180.0f);
488
				break;
489
490
			case CHUNK_ONOFF:
491
			default:
492
				Skip(chunkLen);
493
			}
494
		}
495
		Seek(end);
496
		
497
		return light;
498
	}
499
500
	private Material3D ChunkMaterial(Scene3D scene, int len) throws IOException
501
	{
502
		long end = filePos + len;
503
		
504
		Material3D mat = new Material3D();
505
506
		while (filePos < end) {
507
			int chunkID = ReadUnsignedShort();
508
			int chunkLen = ReadInt() - 6;
509
510
			switch (chunkID) {
511
			case CHUNK_TEXTURE:
512
				mat.texture = ChunkMap(chunkLen);
513
				break;
514
515
			case CHUNK_BUMPMAP:
516
			case CHUNK_REFLMAP:
517
				ChunkMap(chunkLen);
518
				break;
519
520
			case CHUNK_AMBIENT:
521
				mat.ambient = new float[4];
522
				ChunkColor(chunkLen, mat.ambient);
523
				break;
524
525
			case CHUNK_DIFFUSE:
526
				mat.diffuse = new float[4];
527
				ChunkColor(chunkLen, mat.diffuse);
528
				break;
529
530
			case CHUNK_SPECULAR:
531
				mat.specular = new float[4];
532
				ChunkColor(chunkLen, mat.specular);
533
				break;
534
535
			case CHUNK_MATNAME:
536
				mat.name = ChunkName(chunkLen);
537
				break;
538
539
			case CHUNK_MTLTYPE:
540
				mat.type = ReadUnsignedShort();
541
				break;
542
543
			case CHUNK_SHININES:
544
				mat.shininess = ChunkPercent(chunkLen) * 1000;
545
				break;
546
547
			case CHUNK_SHINSTRN:
548
				mat.shinStren = ChunkPercent(chunkLen);
549
				break;
550
551
			case CHUNK_TRANSP:
552
				mat.transparency = ChunkPercent(chunkLen);
553
				break;
554
555
			case CHUNK_SELFILL:
556
				mat.selfIllum = ChunkPercent(chunkLen);
557
				break;
558
559
			default:
560
				Skip(chunkLen);
561
			}
562
		}
563
		Seek(end);
564
		
565
		return mat;
566
	}
567
568
	private String ChunkMap(int len) throws IOException
569
	{
570
		long end = filePos + len;
571
572
		String name = null;
573
574
		while (filePos < end) {
575
			int chunkID = ReadUnsignedShort();
576
			int chunkLen = ReadInt() - 6;
577
578
			switch (chunkID) {
579
			case CHUNK_MAPFILE:
580
				name = ChunkName(chunkLen);
581
				break;
582
583
			case CHUNK_MAPPARAM:
584
			default:
585
				Skip(chunkLen);
586
			}
587
		}
588
		Seek(end);
589
		
590
		return name;
591
	}
592
593
	private void ChunkKeyframer(Scene3D scene, int len) throws IOException
594
	{
595
		int fstart = 0, fend = 100;
596
597
		long end = filePos + len;
598
		while (filePos < end) {
599
			int chunkID = ReadUnsignedShort();
600
			int chunkLen = ReadInt() - 6;
601
602
			switch (chunkID) {
603
			case CHUNK_FRAMES:
604
				fstart = ReadInt();
605
				fend = ReadInt();
606
				break;
607
608
			case CHUNK_TRACKINFO:
609
				Animation anim = ChunkMeshTrack(chunkLen, scene);
610
				if (anim != null)
611
					scene.animations.add(anim);
612
				break;
613
614
			case CHUNK_SPOTINFO:
615
			default:
616
				Skip(chunkLen);
617
			}
618
		}
619
620
		if (fstart < fend)
621
			for (int i = 0; i < scene.animations.size(); i++) {
622
				Animation anim = scene.animations.get(i);
623
				if (anim.position != null)
624
					for (int j = 0; j < anim.position.length; j++)
625
						anim.position[j].time = (anim.position[j].time - fstart) / (fend - fstart);
626
				if (anim.rotation != null)
627
					for (int j = 0; j < anim.rotation.length; j++)
628
						anim.rotation[j].time = (anim.rotation[j].time - fstart) / (fend - fstart);
629
				if (anim.scaling != null)
630
					for (int j = 0; j < anim.scaling.length; j++)
631
						anim.scaling[j].time = (anim.scaling[j].time - fstart) / (fend - fstart);
632
			}
633
634
		Seek(end);
635
	}
636
637
	private Animation ChunkMeshTrack(int len, Scene3D scene) throws IOException
638
	{
639
		Animation anim = new Animation();
640
		int num, i, j, k;
641
		
642
		anim.result = new float[16];
643
		Matrix.setIdentityM(anim.result, 0);
644
645
		anim.world = new float[16];
646
		Matrix.setIdentityM(anim.world, 0);
647
648
		long end = filePos + len;
649
		while (filePos < end) {
650
			int chunkID = ReadUnsignedShort();
651
			int chunkLen = ReadInt() - 6;
652
653
			switch (chunkID) {
654
			case CHUNK_HIERARCHY:
655
				anim.id = ReadUnsignedShort();
656
				break;
657
658
			case CHUNK_OBJNAME:
659
				String name = ChunkName(0);
660
				anim.light = scene.FindLight(name);
661
				anim.object = scene.FindObject(name);
662
				Skip(4);
663
				anim.idParent = ReadUnsignedShort();
664
				anim.parent = scene.FindAnimation(anim.idParent);
665
				if (anim.parent != null) {
666
					anim.parent.childNext = anim.parent.childFirst;
667
					anim.parent.childFirst = anim;
668
				}
669
				break;
670
671
			case CHUNK_PIVOT:
672
				anim.pivot = new float[3];
673
				ChunkVector(anim.pivot, 0);
674
				break;
675
676
			case CHUNK_TRACKPOS:
677
				Skip(10);
678
				num = ReadInt();
679
				anim.position = new AnimKey[num];
680
				for (i = 0; i < num; i++) {
681
					anim.position[i] = new AnimKey();
682
					anim.position[i].time = ReadInt();
683
					k = ReadUnsignedShort();
684
					for (j = 0; j < 5; j++)
685
						if ((k & (1 << j)) != 0)
686
							Skip(4);
687
					anim.position[i].data = new float[3];
688
					ChunkVector(anim.position[i].data, 0);
689
				}
690
				break;
691
692
			case CHUNK_TRACKROT:
693
				Skip(10);
694
				num = ReadInt();
695
				anim.rotation = new AnimKey[num];
696
				for (i = 0; i < num; i++) {
697
					anim.rotation[i] = new AnimKey();
698
					anim.rotation[i].time = ReadInt();
699
					k = ReadUnsignedShort();
700
					for (j = 0; j < 5; j++)
701
						if ((k & (1 << j)) != 0)
702
							Skip(4);
703
704
					anim.rotation[i].data = new float[4];
705
					anim.rotation[i].data[3] = ReadFloat();
706
					ChunkVector(anim.rotation[i].data, 0);
707
				}
708
				break;
709
710
			case CHUNK_TRACKSCL:
711
				Skip(10);
712
				num = ReadInt();
713
				anim.scaling = new AnimKey[num];
714
				for (i = 0; i < num; i++) {
715
					anim.scaling[i] = new AnimKey();
716
					anim.scaling[i].time = ReadInt();
717
					k = ReadUnsignedShort();
718
					for (j = 0; j < 5; j++)
719
						if ((k & (1 << j)) != 0)
720
							Skip(4);
721
					anim.scaling[i].data = new float[3];
722
					ChunkVector(anim.scaling[i].data, 0);
723
				}
724
				break;
725
726
			default:
727
				Skip(chunkLen);
728
			}
729
		}
730
		Seek(end);
731
732
		return anim;
733
	}
734
735
	private void ChunkColor(int len, float[] color) throws IOException
736
	{
737
		long end = filePos + len;
738
		while (filePos < end) {
739
			int chunkID = ReadUnsignedShort();
740
			int chunkLen = ReadInt() - 6;
741
742
			switch (chunkID) {
743
			case CHUNK_RGBC:
744
				ChunkRGBC(color);
745
				break;
746
747
			case CHUNK_RGB24:
748
				ChunkRGB24(color);
749
				break;
750
751
			default:
752
				Skip(chunkLen);
753
			}
754
		}
755
		Seek(end);
756
	}
757
758
	private float ChunkPercent(int len) throws IOException
759
	{
760
		float v = 0;
761
762
		long end = filePos + len;
763
		while (filePos < end) {
764
			int chunkID = ReadUnsignedShort();
765
			int chunkLen = ReadInt() - 6;
766
767
			switch (chunkID) {
768
			case CHUNK_SHORT:
769
				v = ReadUnsignedShort() / 100.0f;
770
				break;
771
772
			default:
773
				Skip(chunkLen);
774
			}
775
		}
776
		Seek(end);
777
778
		return v;
779
	}
780
781
	private String ChunkName(int len) throws IOException
782
	{
783
		long end = filePos + len;
784
		int slen = 0;
785
		byte[] buffer = new byte[128];
786
		byte c;
787
788
		do {
789
			c = ReadByte();
790
			if (c != 0)
791
				buffer[slen++] = c;
792
		} while (c != 0);
793
794
		if (len != 0)
795
			Seek(end);
796
797
		String name = new String(buffer, 0, slen);
798
799
		return name;
800
	}
801
802
	private void ChunkVector(float[] vec, int offset) throws IOException
803
	{
804
		vec[offset + 0] = ReadFloat();
805
		vec[offset + 2] = ReadFloat();
806
		vec[offset + 1] = ReadFloat();
807
	}
808
809
	private void ChunkRGBC(float[] c) throws IOException
810
	{
811
		c[0] = ReadFloat();
812
		c[1] = ReadFloat();
813
		c[2] = ReadFloat();
814
		c[3] = 1;
815
	}
816
817
	private void ChunkRGB24(float[] c) throws IOException
818
	{
819
		c[0] = ReadUnsignedByte() / 255.0f;
820
		c[1] = ReadUnsignedByte() / 255.0f;
821
		c[2] = ReadUnsignedByte() / 255.0f;
822
		c[3] = 1;
823
	}
824
}