View difference between Paste ID: 5fse1Uiv and 3vMjDgkf
SHOW: | | - or go back to the newest paste.
1-
package com.ginkage.postcard;
1+
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 = 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
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, int off)
344
	{
345
		v[offset + 0] += a[off + 0];
346
		v[offset + 1] += a[off + 1];
347
		v[offset + 2] += a[off + 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, m, t, num = ReadUnsignedShort(), unused = num, idx;
363
364
		int faceCount = num;
365
		int[] faceBuffer = new int[3*faceCount];
366
		boolean[] faceUsed = new boolean[faceCount];
367
		float[] v = new float[3]; 
368
		float[] v1 = new float[3]; 
369
		float[] v2 = new float[3]; 
370
371
		float[] vgNorm = new float[3*3*faceCount]; // per-vertex normal for each face
372
		int[] vertGroup = new int[3*faceCount]; // per-vertex group for each face
373
		boolean[] vgUsed = new boolean[3*faceCount]; // per-vertex "group used" bit for each face
374
		int[] vgNum = new int[obj.vertCount + 1]; // per-vertex face count, and then offset
375
		int[] faceGroup = new int[faceCount]; // per-face smoothing group
376
377
		int[] vgUniqs = new int[obj.vertCount + 1]; // per-vertex unique groups count
378
		int[] vertUGroup = new int[3*faceCount]; // per-vertex unique groups list for each face
379
380
		for (i = 0; i <= obj.vertCount; i++)
381
			vgNum[i] = vgUniqs[i] = 0;
382
383
		for (i = 0, idx = 0; i < faceCount; i++, idx += 3) {
384
			j = ReadUnsignedShort();
385
			k = ReadUnsignedShort();
386
			l = ReadUnsignedShort();
387
			Skip(2);
388
389
			faceUsed[i] = false;
390
			faceBuffer[idx + 0] = j;
391
			faceBuffer[idx + 2] = k;
392
			faceBuffer[idx + 1] = l;
393
394
			// initialize smoothing groups data
395
			faceGroup[i] = 0;
396
397
			for (t = 0; t < 9; t++)
398
				vgNorm[i * 9 + t] = 0;
399
400
			for (t = 0; t < 3; t++) {
401
				vertGroup[idx + t] = 0;
402
				vertUGroup[idx + t] = 0;
403
				vgUsed[idx + t] = false;
404
			}
405
406
			vgNum[j]++;
407
			vgNum[k]++;
408
			vgNum[l]++;
409
		}
410
411
		int a, sum = 0;
412
		for (i = 0; i < obj.vertCount; i++) {
413
			a = vgNum[i];
414
			vgNum[i] = sum;
415
			sum += a;
416
		}
417
		vgNum[obj.vertCount] = sum; // now we can store all the faces and their normals and groups per-vertex
418
419
		for (i = 0, idx = 0; i < faceCount; i++, idx += 3) {
420
			j = faceBuffer[idx + 0];
421
			k = faceBuffer[idx + 2];
422
			l = faceBuffer[idx + 1];
423
424
			VecSubstract(v1, obj.vertexBuffer, l*8, j*8);
425
			VecSubstract(v2, obj.vertexBuffer, k*8, j*8);
426
			CrossProduct(v, v1, v2);
427
428
			VecAdd(vgNorm, vgNum[j]*3, v, 0);
429
			VecAdd(vgNorm, vgNum[k]*3, v, 0);
430
			VecAdd(vgNorm, vgNum[l]*3, v, 0);
431
			
432
			vgNum[j]++;
433
			vgNum[k]++;
434
			vgNum[l]++;
435
		}
436
437
		for (i = obj.vertCount - 1; i > 0; i--) // offsets were shifted, so shift them back
438
			vgNum[i] = vgNum[i - 1];
439
		vgNum[0] = 0;
440
441
		boolean gotSmoothGroups = false;
442
443
		while (filePos < end) {
444
			int chunkID = ReadUnsignedShort();
445
			int chunkLen = ReadInt() - 6;
446
447
			switch (chunkID) {
448
			case CHUNK_FACEMAT:
449
				FaceMat mat = new FaceMat();
450
				String name = ChunkName(0);
451
				mat.material = scene.FindMaterial(name);
452
				num = ReadUnsignedShort();
453
				mat.indCount = num;
454
				mat.indexBuffer = new int[3*num];
455
				mat.bufOffset = obj.indCount;
456
				obj.indCount += 3*num;
457
				k = 0;
458
				for (i = 0; i < num; i++) {
459
					j = ReadUnsignedShort();
460
					if (!faceUsed[j]) {
461
						faceUsed[j] = true;
462
						unused--;
463
					}
464
					j *= 3;
465
					for (t = 0; t < 3; t++)
466
						mat.indexBuffer[k++] = j;
467
				}
468
				obj.faceMats.add(mat);
469
				break;
470
471
			case CHUNK_SMOOTHG:
472
				for (i = 0, idx = 0; i < faceCount; i++, idx += 3) {
473
					faceGroup[i] = ReadInt();
474
					
475
					for (t = 0; t < 3; t++) {
476
						j = faceBuffer[idx + t];
477
						vertGroup[vgNum[j]] = faceGroup[i];
478
						vgNum[j]++;
479
					}
480
				}
481
				for (i = obj.vertCount - 1; i > 0; i--)
482
					vgNum[i] = vgNum[i - 1];
483
				vgNum[0] = 0;
484
				gotSmoothGroups = true;
485
				break;
486
487
			default:
488
				Skip(chunkLen);
489
			}
490
		}
491
		Seek(end);
492
493
		int newVertCount = 0, g;
494
495
		if (gotSmoothGroups) {
496
			for (i = 0; i < obj.vertCount; i++) {
497
				for (m = vgNum[i]; m < vgNum[i + 1]; m++) { // for every normal and face of this vertex
498
					if (!vgUsed[m]) {
499
						// vertGroup[m] is a new group...
500
						vertUGroup[vgNum[i] + vgUniqs[i]] = vertGroup[m];
501
						vgUniqs[i]++;
502
						newVertCount++;
503
					}
504
	
505
					for (t = m; t < vgNum[i + 1]; t++) // mark all equal groups (including this one) as duplicates
506
						if (vertGroup[t] == vertGroup[m])
507
							vgUsed[t] = true;
508
				}
509
			}
510
511
			if (newVertCount == obj.vertCount)
512
				gotSmoothGroups = false;
513
		}
514
515
		if (gotSmoothGroups) {
516
			// reindex all vertices, build new normals
517
			int newIndex = 0;
518
			int[] vertIndex = new int[faceCount*3]; // new vertex indices
519
			float[] newVertexBuffer = new float[newVertCount*8];
520
521
			for (i = 0, idx = 0; i < faceCount; i++, idx += 3)
522
				for (t = 0; t < 3; t++)
523
					vertIndex[idx + t] = 0;
524
525
			idx = 3;
526
			for (i = 0; i < obj.vertCount; i++) {
527
				for (t = 0; t < vgUniqs[i]; t++) { // for every unique normal and face of this vertex
528
					for (m = 0; m < 8; m++)
529
						newVertexBuffer[newIndex*8 + m] = obj.vertexBuffer[i*8 + m]; // duplicate all vertex data (including zero normals) 
530
531
					g = vertUGroup[vgNum[i] + t]; // unique group mask for this vertex
532
					for (m = vgNum[i]; m < vgNum[i + 1]; m++) // for every NON-unique normal and face of this vertex
533
						if ((vertGroup[m] & g) != 0 || vertGroup[m] == g) // also works for zero group
534
							VecAdd(newVertexBuffer, idx, vgNorm, m*3); // add normal to vertex
535
	
536
					vertIndex[vgNum[i] + t] = newIndex;
537
					newIndex++;
538
					idx += 8;
539
				}
540
			}
541
542
			int fg, vi;
543
			for (i = 0, idx = 0; i < faceCount; i++, idx += 3) {
544
				fg = faceGroup[i];
545
				for (m = 0; m < 3; m++) {
546
					vi = faceBuffer[idx + m]; // face vertex
547
					for (t = 0; t < vgUniqs[vi]; t++) // for every unique group of this vertex
548
						if (fg == vertUGroup[vgNum[vi] + t]) { // found the right one
549
							faceBuffer[idx + m] = vertIndex[vgNum[vi] + t];
550
							break;
551
						}
552
				}
553
			}
554
555
			obj.vertCount = newVertCount;
556
			obj.vertexBuffer = newVertexBuffer;
557
		}
558
		else // nothing changed, no need to recalculate anything
559
			for (i = 0, idx = 3; i < obj.vertCount; i++, idx += 8) // just copy all the normals
560
				for (m = vgNum[i]; m < vgNum[i + 1]; m++) // for every NON-unique normal and face of this vertex
561
					VecAdd(obj.vertexBuffer, idx, vgNorm, m*3); // add normal to vertex
562
563
		for (i = 0, k = 3; i < obj.vertCount; i++, k += 8)
564
			VecNormalize(obj.vertexBuffer, k);
565
566
		for (m = 0; m < obj.faceMats.size(); m++) {
567
			FaceMat mat = obj.faceMats.get(m);
568
			k = 0;
569
			for (i = 0; i < mat.indCount; i++)
570
				for (t = 0; t < 3; t++) {
571
					j = mat.indexBuffer[k];
572
					mat.indexBuffer[k++] = faceBuffer[j + t];
573
				}
574
		}
575
576
		if (unused > 0) {
577
			FaceMat mat = new FaceMat();
578
			mat.indexBuffer = new int[3*unused];
579
			mat.bufOffset = obj.indCount;
580
			obj.indCount += 3*unused;
581
			k = 0;
582
			for (i = 0; i < faceCount; i++)
583
				if (!faceUsed[i]) {
584
					faceUsed[i] = true;
585
					j = i * 3;
586
					for (t = 0; t < 3; t++)
587
						mat.indexBuffer[k++] = faceBuffer[j + t];
588
				}
589
			obj.faceMats.add(mat);
590
		}
591
	}
592
593
	private Light3D ChunkLight(int len, String name) throws IOException
594
	{
595
		long end = filePos + len;
596
597
		Light3D light = new Light3D();
598
		light.name = name;
599
		light.pos = new float[3];
600
		ChunkVector(light.pos, 0);
601
602
		while (filePos < end) {
603
			int chunkID = ReadUnsignedShort();
604
			int chunkLen = ReadInt() - 6;
605
606
			switch (chunkID) {
607
			case CHUNK_RGBC:
608
				light.color = new float[4];
609
				ChunkRGBC(light.color);
610
				break;
611
612
			case CHUNK_RGB24:
613
				light.color = new float[4];
614
				ChunkRGB24(light.color);
615
				break;
616
617
			case CHUNK_SPOTL:
618
				light.dir = new float[4];
619
				ChunkVector(light.dir, 0);
620
				light.theta = (float) (ReadFloat() * Math.PI / 180.0f);
621
				light.phi = (float) (ReadFloat() * Math.PI / 180.0f);
622
				break;
623
624
			case CHUNK_ONOFF:
625
			default:
626
				Skip(chunkLen);
627
			}
628
		}
629
		Seek(end);
630
631
		return light;
632
	}
633
634
	private Material3D ChunkMaterial(Scene3D scene, int len) throws IOException
635
	{
636
		long end = filePos + len;
637
638
		Material3D mat = new Material3D();
639
640
		while (filePos < end) {
641
			int chunkID = ReadUnsignedShort();
642
			int chunkLen = ReadInt() - 6;
643
644
			switch (chunkID) {
645
			case CHUNK_TEXTURE:
646
				mat.texture = ChunkMap(chunkLen);
647
				break;
648
649
			case CHUNK_BUMPMAP:
650
			case CHUNK_REFLMAP:
651
				ChunkMap(chunkLen);
652
				break;
653
654
			case CHUNK_AMBIENT:
655
				mat.ambient = new float[4];
656
				ChunkColor(chunkLen, mat.ambient);
657
				break;
658
659
			case CHUNK_DIFFUSE:
660
				mat.diffuse = new float[4];
661
				ChunkColor(chunkLen, mat.diffuse);
662
				break;
663
664
			case CHUNK_SPECULAR:
665
				mat.specular = new float[4];
666
				ChunkColor(chunkLen, mat.specular);
667
				break;
668
669
			case CHUNK_MATNAME:
670
				mat.name = ChunkName(chunkLen);
671
				break;
672
673
			case CHUNK_MTLTYPE:
674
				mat.type = ReadUnsignedShort();
675
				break;
676
677
			case CHUNK_SHININES:
678
				mat.shininess = 100 - ChunkPercent(chunkLen);
679
				break;
680
681
			case CHUNK_SHINSTRN:
682
				mat.shinStren = ChunkPercent(chunkLen);
683
				break;
684
685
			case CHUNK_TRANSP:
686
				mat.transparency = ChunkPercent(chunkLen);
687
				break;
688
689
			case CHUNK_SELFILL:
690
				mat.selfIllum = ChunkPercent(chunkLen);
691
				break;
692
693
			default:
694
				Skip(chunkLen);
695
			}
696
		}
697
		Seek(end);
698
699
		return mat;
700
	}
701
702
	private String ChunkMap(int len) throws IOException
703
	{
704
		long end = filePos + len;
705
706
		String name = null;
707
708
		while (filePos < end) {
709
			int chunkID = ReadUnsignedShort();
710
			int chunkLen = ReadInt() - 6;
711
712
			switch (chunkID) {
713
			case CHUNK_MAPFILE:
714
				name = ChunkName(chunkLen);
715
				break;
716
717
			case CHUNK_MAPPARAM:
718
			default:
719
				Skip(chunkLen);
720
			}
721
		}
722
		Seek(end);
723
724
		return name;
725
	}
726
727
	private void ChunkKeyframer(Scene3D scene, int len) throws IOException
728
	{
729
		int fstart = 0, fend = 100;
730
731
		long end = filePos + len;
732
		while (filePos < end) {
733
			int chunkID = ReadUnsignedShort();
734
			int chunkLen = ReadInt() - 6;
735
736
			switch (chunkID) {
737
			case CHUNK_FRAMES:
738
				fstart = ReadInt();
739
				fend = ReadInt();
740
				break;
741
742
			case CHUNK_TRACKINFO:
743
				Animation anim = ChunkMeshTrack(chunkLen, scene);
744
				if (anim != null)
745
					scene.animations.add(anim);
746
				break;
747
748
			case CHUNK_SPOTINFO:
749
			default:
750
				Skip(chunkLen);
751
			}
752
		}
753
754
		if (fstart < fend)
755
			for (int i = 0; i < scene.animations.size(); i++) {
756
				Animation anim = scene.animations.get(i);
757
				if (anim.position != null)
758
					for (int j = 0; j < anim.position.length; j++)
759
						anim.position[j].time = (anim.position[j].time - fstart) / (fend - fstart);
760
				if (anim.rotation != null)
761
					for (int j = 0; j < anim.rotation.length; j++)
762
						anim.rotation[j].time = (anim.rotation[j].time - fstart) / (fend - fstart);
763
				if (anim.scaling != null)
764
					for (int j = 0; j < anim.scaling.length; j++)
765
						anim.scaling[j].time = (anim.scaling[j].time - fstart) / (fend - fstart);
766
			}
767
768
		Seek(end);
769
	}
770
771
	private Animation ChunkMeshTrack(int len, Scene3D scene) throws IOException
772
	{
773
		Animation anim = new Animation();
774
		int num, i, j, k;
775
776
		anim.result = new float[16];
777
		Matrix.setIdentityM(anim.result, 0);
778
779
		anim.world = new float[16];
780
		Matrix.setIdentityM(anim.world, 0);
781
782
		long end = filePos + len;
783
		while (filePos < end) {
784
			int chunkID = ReadUnsignedShort();
785
			int chunkLen = ReadInt() - 6;
786
787
			switch (chunkID) {
788
			case CHUNK_HIERARCHY:
789
				anim.id = ReadUnsignedShort();
790
				break;
791
792
			case CHUNK_OBJNAME:
793
				String name = ChunkName(0);
794
				anim.light = scene.FindLight(name);
795
				anim.object = scene.FindObject(name);
796
				Skip(4);
797
				anim.parent = scene.FindAnimation(ReadUnsignedShort());
798
				break;
799
800
			case CHUNK_PIVOT:
801
				anim.pivot = new float[3];
802
				ChunkVector(anim.pivot, 0);
803
				break;
804
805
			case CHUNK_TRACKPOS:
806
				Skip(10);
807
				num = ReadInt();
808
				anim.position = new AnimKey[num];
809
				for (i = 0; i < num; i++) {
810
					anim.position[i] = new AnimKey();
811
					anim.position[i].time = ReadInt();
812
					k = ReadUnsignedShort();
813
					for (j = 0; j < 5; j++)
814
						if ((k & (1 << j)) != 0)
815
							Skip(4);
816
					anim.position[i].data = new float[3];
817
					ChunkVector(anim.position[i].data, 0);
818
				}
819
				break;
820
821
			case CHUNK_TRACKROT:
822
				Skip(10);
823
				num = ReadInt();
824
				anim.rotation = new AnimKey[num];
825
				for (i = 0; i < num; i++) {
826
					anim.rotation[i] = new AnimKey();
827
					anim.rotation[i].time = ReadInt();
828
					k = ReadUnsignedShort();
829
					for (j = 0; j < 5; j++)
830
						if ((k & (1 << j)) != 0)
831
							Skip(4);
832
					anim.rotation[i].data = new float[4];
833
					anim.rotation[i].data[3] = ReadFloat();
834
					ChunkVector(anim.rotation[i].data, 0);
835
				}
836
				break;
837
838
			case CHUNK_TRACKSCL:
839
				Skip(10);
840
				num = ReadInt();
841
				anim.scaling = new AnimKey[num];
842
				for (i = 0; i < num; i++) {
843
					anim.scaling[i] = new AnimKey();
844
					anim.scaling[i].time = ReadInt();
845
					k = ReadUnsignedShort();
846
					for (j = 0; j < 5; j++)
847
						if ((k & (1 << j)) != 0)
848
							Skip(4);
849
					anim.scaling[i].data = new float[3];
850
					ChunkVector(anim.scaling[i].data, 0);
851
				}
852
				break;
853
854
			default:
855
				Skip(chunkLen);
856
			}
857
		}
858
		Seek(end);
859
860
		return anim;
861
	}
862
863
	private void ChunkColor(int len, float[] color) throws IOException
864
	{
865
		long end = filePos + len;
866
		while (filePos < end) {
867
			int chunkID = ReadUnsignedShort();
868
			int chunkLen = ReadInt() - 6;
869
870
			switch (chunkID) {
871
			case CHUNK_RGBC:
872
				ChunkRGBC(color);
873
				break;
874
875
			case CHUNK_RGB24:
876
				ChunkRGB24(color);
877
				break;
878
879
			default:
880
				Skip(chunkLen);
881
			}
882
		}
883
		Seek(end);
884
	}
885
886
	private float ChunkPercent(int len) throws IOException
887
	{
888
		float v = 0;
889
890
		long end = filePos + len;
891
		while (filePos < end) {
892
			int chunkID = ReadUnsignedShort();
893
			int chunkLen = ReadInt() - 6;
894
895
			switch (chunkID) {
896
			case CHUNK_SHORT:
897
				v = ReadUnsignedShort() / 100.0f;
898
				break;
899
900
			default:
901
				Skip(chunkLen);
902
			}
903
		}
904
		Seek(end);
905
906
		return v;
907
	}
908
909
	private String ChunkName(int len) throws IOException
910
	{
911
		long end = filePos + len;
912
		int slen = 0;
913
		byte[] buffer = new byte[128];
914
		byte c;
915
916
		do {
917
			c = ReadByte();
918
			if (c != 0)
919
				buffer[slen++] = c;
920
		} while (c != 0);
921
922
		if (len != 0)
923
			Seek(end);
924
925
		String name = new String(buffer, 0, slen);
926
927
		return name;
928
	}
929
930
	private void ChunkVector(float[] vec, int offset) throws IOException
931
	{
932
		vec[offset + 0] = ReadFloat();
933
		vec[offset + 2] = ReadFloat();
934
		vec[offset + 1] = ReadFloat();
935
	}
936
937
	private void ChunkRGBC(float[] c) throws IOException
938
	{
939
		c[0] = ReadFloat();
940
		c[1] = ReadFloat();
941
		c[2] = ReadFloat();
942
		c[3] = 1;
943
	}
944
945
	private void ChunkRGB24(float[] c) throws IOException
946
	{
947
		c[0] = ReadUnsignedByte() / 255.0f;
948
		c[1] = ReadUnsignedByte() / 255.0f;
949
		c[2] = ReadUnsignedByte() / 255.0f;
950
		c[3] = 1;
951
	}
952
}