1<?php
2
3class Image_3D_Chunk {
4
5    protected $type;
6    protected $content;
7    protected $size;
8
9    protected $chunks;
10
11 //>------ Primary chunk
12    const    MAIN3DS            = 0x4D4D;
13
14 //>------ Main Chunks
15     const    EDIT3DS            = 0x3D3D;  // this is the start of the editor config
16     const    KEYF3DS            = 0xB000;  // this is the start of the keyframer config
17
18 //>------ sub defines of EDIT3DS
19     const    EDIT_MATERIAL    = 0xAFFF;
20     const    EDIT_CONFIG1    = 0x0100;
21     const    EDIT_CONFIG2    = 0x3E3D;
22     const    EDIT_VIEW_P1    = 0x7012;
23     const    EDIT_VIEW_P2    = 0x7011;
24     const    EDIT_VIEW_P3    = 0x7020;
25     const    EDIT_VIEW1        = 0x7001;
26     const    EDIT_BACKGR        = 0x1200;
27     const    EDIT_AMBIENT    = 0x2100;
28     const    EDIT_OBJECT        = 0x4000;
29
30 //>------ sub defines of EDIT_OBJECT
31     const    OBJ_TRIMESH        = 0x4100;
32     const    OBJ_LIGHT        = 0x4600;
33     const    OBJ_CAMERA        = 0x4700;
34
35     const    OBJ_UNKNWN01    = 0x4010;
36     const    OBJ_UNKNWN02    = 0x4012;
37
38 //>------ sub defines of OBJ_CAMERA
39     const    CAM_UNKNWN01    = 0x4710;
40     const    CAM_UNKNWN02    = 0x4720;
41
42 //>------ sub defines of OBJ_LIGHT
43     const    LIT_OFF            = 0x4620;
44     const    LIT_SPOT        = 0x4610;
45     const    LIT_UNKNWN01    = 0x465A;
46
47 //>------ sub defines of OBJ_TRIMESH
48     const    TRI_VERTEXL        = 0x4110;
49     const    TRI_FACEL2        = 0x4111;
50     const    TRI_FACEL1        = 0x4120;
51     const    TRI_SMOOTH        = 0x4150;
52     const    TRI_LOCAL        = 0x4160;
53     const    TRI_VISIBLE        = 0x4165;
54
55 //>>------ sub defs of KEYF3DS
56     const    KEYF_UNKNWN01    = 0xB009;
57     const    KEYF_UNKNWN02    = 0xB00A;
58     const    KEYF_FRAMES        = 0xB008;
59     const    KEYF_OBJDES        = 0xB002;
60
61 //>>------  these define the different color chunk types
62     const    COL_RGB            = 0x0010;
63     const    COL_TRU            = 0x0011;
64     const    COL_UNK            = 0x0013;
65
66 //>>------ defines for viewport chunks
67     const    TOP                = 0x0001;
68     const    BOTTOM            = 0x0002;
69     const    LEFT            = 0x0003;
70     const    RIGHT            = 0x0004;
71     const    FRONT            = 0x0005;
72     const    BACK            = 0x0006;
73     const    USER            = 0x0007;
74     const    CAMERA            = 0x0008;
75     const    LIGHT            = 0x0009;
76     const    DISABLED        = 0x0010;
77     const    BOGUS            = 0x0011;
78
79    public function __construct($type, $content)
80    {
81        $this->type = (int) $type;
82        $this->size = strlen($content);
83        $this->content = $content;
84    }
85
86    public function readChunks() {
87
88        if (count($this->chunks) || ($this->size < 6)) return false;
89
90        $position = 0;
91        $string = $this->content;
92        $length = $this->size - 6;
93
94        while ($position <= $length) {
95            $type = $this->getWord(substr($string, $position, 2));
96            $position += 2;
97            $chunkLength = $this->getDWord(substr($string, $position, 4)) - 6;
98            $position += 4;
99
100            $this->chunks[] = new Image_3D_Chunk($type, substr($string, $position, $chunkLength));
101            $position += $chunkLength;
102        }
103    }
104
105    public function debug() {
106        printf("Typ: %6d (0x%04x) (%6d bytes) | Objects:%4d | Content:%6d\n", $this->type, $this->type, $this->size, count($this->chunks), strlen($this->content));
107    }
108
109    protected function getWord($string) {
110        return (ord($string{1}) << 8) | ord($string{0});
111    }
112
113    protected function getDWord($string) {
114        return ord($string{0}) | (ord($string{1}) << 8) | (ord($string{2}) << 16) | (ord($string{3}) << 32);
115    }
116
117    protected function getUnsignedInt($string) {
118        return (ord($string{0}) << 8) | ord($string{1});
119    }
120
121    protected function getFloat($string) {
122        // Convert C-Float to PHP-Float
123        return (ord($string{3}) & 128 ? -1 : 1) * (1 + (float) (ord($string{2}) & 127) / 127 + (float) (ord($string{1})) / 256 / 127 + (float) (ord($string{0})) / 256 / 256 / 127) * pow(2., ((((ord($string{3}) & 127) << 1) | (ord($string{2}) >> 7)) - 127));
124    }
125
126    public function getChunks() {
127        return $this->chunks;
128    }
129
130    public function getType() {
131        return $this->type;
132    }
133
134    public function getContent() {
135        return $this->content;
136    }
137
138    public function getFirstChunkByType($type) {
139        if (!is_int($type)) $type = hexdec($type);
140
141        foreach ($this->chunks as $chunk) if ($chunk->getType() === $type) return $chunk;
142        return false;
143    }
144
145    public function getChunksByType($type) {
146        if (!is_int($type)) $type = hexdec($type);
147
148        $chunks = array();
149        foreach ($this->chunks as $chunk) if ($chunk->getType() === $type) $chunks[] = $chunk;
150        return $chunks;
151    }
152}
153
154class Image_3D_Chunk_Object extends Image_3D_Chunk {
155
156    protected $name;
157
158    public function __construct($type, $content) {
159        parent::__construct($type, $content);
160        $this->getName();
161    }
162
163    protected function getName()
164    {
165        $i = 0;
166        while ((ord($this->content{$i}) !== 0) && ($i < $this->size)) $this->name .= $this->content{$i++};
167        $this->content = substr($this->content, $i + 1);
168    }
169
170    public function readChunks(Image_3D_Object_3ds $k3ds)
171    {
172        $subtype = $this->getWord(substr($this->content, 0, 2));
173        $subcontent = substr($this->content, 6);
174
175        switch ($subtype) {
176            case self::OBJ_TRIMESH:
177                $object = $k3ds->addObject($this->name);
178                $this->chunks[] = new Image_3D_Chunk_TriMesh($subtype, $subcontent, $object);
179            break;
180        }
181    }
182
183    public function debug() {
184        echo 'Object: ', $this->name, "\n";
185        parent::debug();
186    }
187}
188
189class Image_3D_Chunk_TriMesh extends Image_3D_Chunk {
190
191    protected $matrix;
192
193    protected $object;
194
195    public function __construct($type, $content, $object) {
196        parent::__construct($type, $content);
197
198        $this->object = $object;
199
200        $this->readChunks();
201
202        $this->getPoints();
203        $this->getFaces();
204    }
205
206    protected function getPoints()
207    {
208        $vertexlists = $this->getChunksByType(Image_3D_Chunk::TRI_VERTEXL);
209        foreach ($vertexlists as $vertexlist) {
210            $points = $vertexlist->getContent();
211            $count = $this->getWord(substr($points, 0, 2));
212            $points = substr($points, 2);
213
214            for ($i = 0; $i < $count; $i++) {
215                $x = $this->getFloat(substr($points, 0, 4));
216                $y = $this->getFloat(substr($points, 4, 4));
217                $z = $this->getFloat(substr($points, 8, 4));
218                $this->object->newPoint($x, $y, $z);
219                $points = substr($points, 12);
220            }
221        }
222    }
223
224    protected function getFaces()
225    {
226        $facelists = $this->getChunksByType(Image_3D_Chunk::TRI_FACEL1);
227        foreach ($facelists as $facelist) {
228            $faces = $facelist->getContent();
229            $count = $this->getWord(substr($faces, 0, 2));
230            $faces = substr($faces, 2);
231
232            for ($i = 0; $i < $count; $i++) {
233                $p1 = $this->getWord(substr($faces, 0, 2));
234                $p2 = $this->getWord(substr($faces, 2, 2));
235                $p3 = $this->getWord(substr($faces, 4, 2));
236                $this->object->newPolygon($p1, $p2, $p3);
237                $faces = substr($faces, 8);
238            }
239        }
240    }
241
242    protected function getTranslations()
243    {
244        $translists = $this->getChunksByType(Image_3D_Chunk::TRI_LOCAL);
245        foreach ($translists as $translist) {
246            $trans = $translist->getContent();
247
248            echo "Trans: " . strlen($trans), "\n";
249        }
250    }
251
252    public function debug() {
253        parent::debug();
254        printf("Trimesh with %d (0x%04x) points - Pointsize: %.2f\n", $this->pointCount, $this->pointCount, $this->size / $this->pointCount);
255    }
256}
257
258class Image_3D_Object_3ds_Object extends Image_3D_Object {
259
260    protected $_points;
261
262    public function __construct() {
263        parent::__construct();
264
265        $this->_points = array();
266    }
267
268    public function newPoint($x, $y, $z)
269    {
270        $this->_points[] = new Image_3D_Point($x, $y, $z);
271//        echo "New Point: $x, $y, $z -> ", count($this->_points), "\n";
272    }
273
274    public function newPolygon($p1, $p2, $p3) {
275        if (!isset($this->_points[$p1]) || !isset($this->_points[$p2]) || !isset($this->_points[$p3])) {
276//            printf("ERROR: Unknown point (%d, %d, %d of %d)\n", $p1, $p2, $p3, count($this->_points) - 1);
277            return false;
278        }
279        $this->_addPolygon(new Image_3D_Polygon($this->_points[$p1], $this->_points[$p2], $this->_points[$p3]));
280//        echo "New Polygon: $p1, $p2, $p3 -> ", count($this->_polygones), "\n";
281    }
282
283    public function debug() {
284        printf("Points: %d | Polygones: %d (%d)\n", count($this->_points), count($this->_polygones), $this->_polygonCount);
285    }
286}
287
288?>
289