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 | } |