View difference between Paste ID: QcyMmhqq and 7YLjjkBz
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-
		
78+
79
		try {
80
			if (file != null)
81
				file.close();
82
		} catch (IOException e) {
83
			e.printStackTrace();
84
		}
85-
		
85+
86
		return scene;
87
	}
88-
	
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-
	
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-
		
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 = ReadUnsignedShort();
282
				for (i = 0, k = 6; i < num; i++, k += 8) {
283
					obj.vertexBuffer[k + 0] = ReadFloat();
284
					obj.vertexBuffer[k + 1] = 1 - ReadFloat();
285
				}
286
				break;
287
288
			case CHUNK_VERTLIST:
289
				num = ReadUnsignedShort();
290
				obj.vertCount = num;
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-
	
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-
	
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
		int faceCount = num;
365
		int[] faceBuffer = new int[3*num];
366
		boolean[] 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
			faceUsed[i] = false;
378
			faceBuffer[idx + 0] = j;
379
			faceBuffer[idx + 2] = k;
380
			faceBuffer[idx + 1] = l;
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
			VecAdd(obj.vertexBuffer, l + 3, v);
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.indexBuffer = new short[3*num];
412
				mat.bufOffset = obj.indCount;
413
				obj.indCount += 3*num;
414
				k = 0;
415
				for (i = 0; i < num; i++) {
416
					j = ReadUnsignedShort();
417
					if (!faceUsed[j]) {
418
						faceUsed[j] = true;
419
						unused--;
420
					}
421
					j *= 3;
422
					mat.indexBuffer[k++] = (short) faceBuffer[j + 0];
423
					mat.indexBuffer[k++] = (short) faceBuffer[j + 1];
424
					mat.indexBuffer[k++] = (short) faceBuffer[j + 2];
425
				}
426
				obj.faceMats.add(mat);
427
				break;
428
429
			case CHUNK_SMOOTHG:
430
			default:
431
				Skip(chunkLen);
432
			}
433
		}
434
		Seek(end);
435
436
		if (unused > 0) {
437
			FaceMat mat = new FaceMat();
438
			mat.indexBuffer = new short[3*unused];
439
			mat.bufOffset = obj.indCount;
440
			obj.indCount += 3*unused;
441
			k = 0;
442
			for (i = 0; i < faceCount; i++)
443
				if (!faceUsed[i]) {
444
					faceUsed[i] = true;
445
					j = i * 3;
446
					mat.indexBuffer[k++] = (short) faceBuffer[j + 0];
447
					mat.indexBuffer[k++] = (short) faceBuffer[j + 1];
448
					mat.indexBuffer[k++] = (short) faceBuffer[j + 2];
449
				}
450
			obj.faceMats.add(mat);
451
		}
452
453
		faceBuffer = null;
454
		faceUsed = null;
455
	}
456
457
	private Light3D ChunkLight(int len, String name) throws IOException
458
	{
459
		long end = filePos + len;
460
461
		Light3D light = new Light3D();
462
		light.name = name;
463
		light.pos = new float[3];
464
		ChunkVector(light.pos, 0);
465
466
		while (filePos < end) {
467
			int chunkID = ReadUnsignedShort();
468
			int chunkLen = ReadInt() - 6;
469
470
			switch (chunkID) {
471
			case CHUNK_RGBC:
472
				light.color = new float[4];
473
				ChunkRGBC(light.color);
474
				break;
475
476
			case CHUNK_RGB24:
477
				light.color = new float[4];
478
				ChunkRGB24(light.color);
479
				break;
480
481
			case CHUNK_SPOTL:
482
				light.dir = new float[4];
483
				ChunkVector(light.dir, 0);
484
				light.theta = (float) (ReadFloat() * Math.PI / 180.0f);
485
				light.phi = (float) (ReadFloat() * Math.PI / 180.0f);
486
				break;
487
488
			case CHUNK_ONOFF:
489
			default:
490
				Skip(chunkLen);
491
			}
492
		}
493
		Seek(end);
494-
		
494+
495
		return light;
496
	}
497
498
	private Material3D ChunkMaterial(Scene3D scene, int len) throws IOException
499
	{
500
		long end = filePos + len;
501
502
		Material3D mat = new Material3D();
503
504
		while (filePos < end) {
505
			int chunkID = ReadUnsignedShort();
506
			int chunkLen = ReadInt() - 6;
507
508
			switch (chunkID) {
509
			case CHUNK_TEXTURE:
510
				mat.texture = ChunkMap(chunkLen);
511
				break;
512
513
			case CHUNK_BUMPMAP:
514
			case CHUNK_REFLMAP:
515
				ChunkMap(chunkLen);
516
				break;
517
518
			case CHUNK_AMBIENT:
519
				mat.ambient = new float[4];
520
				ChunkColor(chunkLen, mat.ambient);
521
				break;
522
523
			case CHUNK_DIFFUSE:
524
				mat.diffuse = new float[4];
525
				ChunkColor(chunkLen, mat.diffuse);
526
				break;
527
528
			case CHUNK_SPECULAR:
529
				mat.specular = new float[4];
530
				ChunkColor(chunkLen, mat.specular);
531
				break;
532
533
			case CHUNK_MATNAME:
534
				mat.name = ChunkName(chunkLen);
535
				break;
536
537
			case CHUNK_MTLTYPE:
538
				mat.type = ReadUnsignedShort();
539
				break;
540
541
			case CHUNK_SHININES:
542-
				mat.shininess = ChunkPercent(chunkLen) * 1000;
542+
				mat.shininess = 100 - ChunkPercent(chunkLen);
543
				break;
544
545
			case CHUNK_SHINSTRN:
546
				mat.shinStren = ChunkPercent(chunkLen);
547
				break;
548
549
			case CHUNK_TRANSP:
550
				mat.transparency = ChunkPercent(chunkLen);
551
				break;
552
553
			case CHUNK_SELFILL:
554
				mat.selfIllum = ChunkPercent(chunkLen);
555
				break;
556
557
			default:
558
				Skip(chunkLen);
559
			}
560
		}
561
		Seek(end);
562-
		
562+
563
		return mat;
564
	}
565
566
	private String ChunkMap(int len) throws IOException
567
	{
568
		long end = filePos + len;
569
570
		String name = null;
571
572
		while (filePos < end) {
573
			int chunkID = ReadUnsignedShort();
574
			int chunkLen = ReadInt() - 6;
575
576
			switch (chunkID) {
577
			case CHUNK_MAPFILE:
578
				name = ChunkName(chunkLen);
579
				break;
580
581
			case CHUNK_MAPPARAM:
582
			default:
583
				Skip(chunkLen);
584
			}
585
		}
586
		Seek(end);
587-
		
587+
588
		return name;
589
	}
590
591
	private void ChunkKeyframer(Scene3D scene, int len) throws IOException
592
	{
593
		int fstart = 0, fend = 100;
594
595
		long end = filePos + len;
596
		while (filePos < end) {
597
			int chunkID = ReadUnsignedShort();
598
			int chunkLen = ReadInt() - 6;
599
600
			switch (chunkID) {
601
			case CHUNK_FRAMES:
602
				fstart = ReadInt();
603
				fend = ReadInt();
604
				break;
605
606
			case CHUNK_TRACKINFO:
607
				Animation anim = ChunkMeshTrack(chunkLen, scene);
608
				if (anim != null)
609
					scene.animations.add(anim);
610
				break;
611
612
			case CHUNK_SPOTINFO:
613
			default:
614
				Skip(chunkLen);
615
			}
616
		}
617
618
		if (fstart < fend)
619
			for (int i = 0; i < scene.animations.size(); i++) {
620
				Animation anim = scene.animations.get(i);
621
				if (anim.position != null)
622
					for (int j = 0; j < anim.position.length; j++)
623
						anim.position[j].time = (anim.position[j].time - fstart) / (fend - fstart);
624
				if (anim.rotation != null)
625
					for (int j = 0; j < anim.rotation.length; j++)
626
						anim.rotation[j].time = (anim.rotation[j].time - fstart) / (fend - fstart);
627
				if (anim.scaling != null)
628
					for (int j = 0; j < anim.scaling.length; j++)
629
						anim.scaling[j].time = (anim.scaling[j].time - fstart) / (fend - fstart);
630
			}
631
632
		Seek(end);
633
	}
634
635
	private Animation ChunkMeshTrack(int len, Scene3D scene) throws IOException
636
	{
637
		Animation anim = new Animation();
638
		int num, i, j, k;
639-
		
639+
640
		anim.result = new float[16];
641
		Matrix.setIdentityM(anim.result, 0);
642
643
		anim.world = new float[16];
644
		Matrix.setIdentityM(anim.world, 0);
645
646
		long end = filePos + len;
647
		while (filePos < end) {
648
			int chunkID = ReadUnsignedShort();
649
			int chunkLen = ReadInt() - 6;
650
651
			switch (chunkID) {
652
			case CHUNK_HIERARCHY:
653
				anim.id = ReadUnsignedShort();
654
				break;
655
656
			case CHUNK_OBJNAME:
657
				String name = ChunkName(0);
658
				anim.light = scene.FindLight(name);
659
				anim.object = scene.FindObject(name);
660
				Skip(4);
661-
				anim.idParent = ReadUnsignedShort();
661+
				anim.parent = scene.FindAnimation(ReadUnsignedShort());
662-
				anim.parent = scene.FindAnimation(anim.idParent);
662+
663
664
			case CHUNK_PIVOT:
665
				anim.pivot = new float[3];
666
				ChunkVector(anim.pivot, 0);
667
				break;
668
669
			case CHUNK_TRACKPOS:
670
				Skip(10);
671
				num = ReadInt();
672
				anim.position = new AnimKey[num];
673
				for (i = 0; i < num; i++) {
674
					anim.position[i] = new AnimKey();
675
					anim.position[i].time = ReadInt();
676
					k = ReadUnsignedShort();
677
					for (j = 0; j < 5; j++)
678
						if ((k & (1 << j)) != 0)
679
							Skip(4);
680
					anim.position[i].data = new float[3];
681
					ChunkVector(anim.position[i].data, 0);
682
				}
683
				break;
684
685
			case CHUNK_TRACKROT:
686
				Skip(10);
687
				num = ReadInt();
688
				anim.rotation = new AnimKey[num];
689
				for (i = 0; i < num; i++) {
690
					anim.rotation[i] = new AnimKey();
691
					anim.rotation[i].time = ReadInt();
692
					k = ReadUnsignedShort();
693
					for (j = 0; j < 5; j++)
694
						if ((k & (1 << j)) != 0)
695
							Skip(4);
696
					anim.rotation[i].data = new float[4];
697
					anim.rotation[i].data[3] = ReadFloat();
698
					ChunkVector(anim.rotation[i].data, 0);
699
				}
700
				break;
701
702
			case CHUNK_TRACKSCL:
703
				Skip(10);
704
				num = ReadInt();
705
				anim.scaling = new AnimKey[num];
706
				for (i = 0; i < num; i++) {
707
					anim.scaling[i] = new AnimKey();
708
					anim.scaling[i].time = ReadInt();
709
					k = ReadUnsignedShort();
710
					for (j = 0; j < 5; j++)
711
						if ((k & (1 << j)) != 0)
712
							Skip(4);
713
					anim.scaling[i].data = new float[3];
714
					ChunkVector(anim.scaling[i].data, 0);
715
				}
716
				break;
717
718
			default:
719
				Skip(chunkLen);
720
			}
721
		}
722
		Seek(end);
723
724
		return anim;
725
	}
726
727
	private void ChunkColor(int len, float[] color) throws IOException
728
	{
729
		long end = filePos + len;
730
		while (filePos < end) {
731
			int chunkID = ReadUnsignedShort();
732
			int chunkLen = ReadInt() - 6;
733
734
			switch (chunkID) {
735
			case CHUNK_RGBC:
736
				ChunkRGBC(color);
737
				break;
738
739
			case CHUNK_RGB24:
740
				ChunkRGB24(color);
741
				break;
742
743
			default:
744
				Skip(chunkLen);
745
			}
746
		}
747
		Seek(end);
748
	}
749
750
	private float ChunkPercent(int len) throws IOException
751
	{
752
		float v = 0;
753
754
		long end = filePos + len;
755
		while (filePos < end) {
756
			int chunkID = ReadUnsignedShort();
757
			int chunkLen = ReadInt() - 6;
758
759
			switch (chunkID) {
760
			case CHUNK_SHORT:
761
				v = ReadUnsignedShort() / 100.0f;
762
				break;
763
764
			default:
765
				Skip(chunkLen);
766
			}
767
		}
768
		Seek(end);
769
770
		return v;
771
	}
772
773
	private String ChunkName(int len) throws IOException
774
	{
775
		long end = filePos + len;
776
		int slen = 0;
777
		byte[] buffer = new byte[128];
778
		byte c;
779
780
		do {
781
			c = ReadByte();
782
			if (c != 0)
783
				buffer[slen++] = c;
784
		} while (c != 0);
785
786
		if (len != 0)
787
			Seek(end);
788
789
		String name = new String(buffer, 0, slen);
790
791
		return name;
792
	}
793
794
	private void ChunkVector(float[] vec, int offset) throws IOException
795
	{
796
		vec[offset + 0] = ReadFloat();
797
		vec[offset + 2] = ReadFloat();
798
		vec[offset + 1] = ReadFloat();
799
	}
800
801
	private void ChunkRGBC(float[] c) throws IOException
802
	{
803
		c[0] = ReadFloat();
804
		c[1] = ReadFloat();
805
		c[2] = ReadFloat();
806
		c[3] = 1;
807
	}
808
809
	private void ChunkRGB24(float[] c) throws IOException
810
	{
811
		c[0] = ReadUnsignedByte() / 255.0f;
812
		c[1] = ReadUnsignedByte() / 255.0f;
813
		c[2] = ReadUnsignedByte() / 255.0f;
814
		c[3] = 1;
815
	}
816
}