1<?php
2/**
3 * 3d Library
4 *
5 * PHP versions 5
6 *
7 * LICENSE:
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 */
22
23/**
24 * Creates a HTML document, with embedded javascript code to draw, move, rotate
25 * and export the 3D-object at runtime
26 *
27 * @category Image
28 * @package  Image_3D
29 * @author   Jakob Westhoff <jakob@westhoffswelt.de>
30 */
31class Image_3D_Driver_DynamicCanvas extends Image_3D_Driver
32{
33
34    /**
35     * Width of the image
36     *
37     * @var integer
38     */
39    protected $_x;
40    /**
41     * Height of the image
42     *
43     * @var integer
44     */
45    protected $_y;
46
47    /**
48     * Polygones created during the rendering process
49     *
50     * @var array
51     */
52    protected $_polygones;
53
54    /**
55     * Background Color of the rendered image
56     *
57     * @var string
58     */
59    protected $_background;
60
61
62    /**
63     * Name of the Render created from the filename
64     * Needed for the correct creation of the Image3D java class
65     *
66     * @var mixed
67     */
68    protected $_name;
69
70    /**
71     * Class constructor
72     */
73    public function __construct()
74    {
75        $this->_image = '';
76
77        $this->_polygones  = array();
78        $this->_background = array();
79    }
80
81    /**
82     * Create the inital image
83     *
84     * @param float $x Width of the image
85     * @param float $y Height of the image
86     *
87     * @return void
88     */
89    public function createImage($x, $y)
90    {
91        $this->_x = (int) $x;
92        $this->_y = (int) $y;
93    }
94
95    /**
96     * Set the background color of the image
97     *
98     * @param Image_3D_Color $color Desired background color of the image
99     *
100     * @return void
101     */
102    public function setBackground(Image_3D_Color $color)
103    {
104        $colorarray = $this->_getRgba($color);
105
106        $this->_background = sprintf("{ r: %d, g: %d, b: %d, a:%.2f }",
107                                     $colorarray['r'], $colorarray['g'],
108                                     $colorarray['b'], $colorarray['a']);
109    }
110
111    /**
112     * Create an appropriate array representation from a Image_3D_Color object
113     *
114     * @param Image_3D_Color $color Color to transform to rgba syntax
115     * @param float          $alpha optional Override the alpha value set in the Image_3D_Color object
116     *
117     * @return array Array of color values reflecting the different color
118     *               components of the input object
119     */
120    protected function _getRgba(Image_3D_Color $color, $alpha = null)
121    {
122        $values = $color->getValues();
123
124        $values[0] = (int) round($values[0] * 255);
125        $values[1] = (int) round($values[1] * 255);
126        $values[2] = (int) round($values[2] * 255);
127
128        if ($alpha !== null) {
129            $values[3] = 1.0 - $alpha;
130        } else {
131            $values[3] = 1.0 - $values[3];
132        }
133
134        return array('r' => $values[0], 'g' => $values[1], 'b' => $values[2], 'a' => $values[3]);
135    }
136
137    /**
138     * Add a polygon to the polygones array
139     *
140     * @param array $points Array of points which represent the polygon to add
141     * @param array $colors Array of maximal three colors. The second and the
142     *                      third color are allowed to be null
143     *
144     * @return void
145     */
146    protected function _addPolygon(array $points, array $colors)
147    {
148        $this->_polygones[] = array("points" => $points, "colors" => $colors);
149    }
150
151    /**
152     * Draw a specified polygon
153     *
154     * @param Image_3D_Polygon $polygon Polygon to draw
155     *
156     * @return void
157     */
158    public function drawPolygon(Image_3D_Polygon $polygon)
159    {
160        $pointarray = array();
161
162        $points = $polygon->getPoints();
163        foreach ($points as $key => $point) {
164            $pointarray[$key] = array('x' => $point->getX(), 'y' => $point->getY(), 'z' => $point->getZ());
165        }
166
167        $this->_addPolygon($pointarray,
168            array($this->_getRgba($polygon->getColor()),
169                null,
170                null));
171    }
172
173    /**
174     * Draw a specified polygon utilizing gradients between his points for
175     * color representation (Gauroud-Shading)
176     *
177     * @param Image_3D_Polygon $polygon Polygon to draw
178     *
179     * @return void
180     */
181    public function drawGradientPolygon(Image_3D_Polygon $polygon)
182    {
183        $pointarray = array();
184        $colorarray = array();
185
186        $points = $polygon->getPoints();
187        foreach ($points as $key => $point) {
188            $pointarray[$key] = array('x' => $point->getX(), 'y' => $point->getY(), 'z' => $point->getZ());
189            $colorarray[$key] = $this->_getRgba($point->getColor());
190        }
191
192        $this->_addPolygon($pointarray, $colorarray);
193    }
194
195    /**
196     * Convert php array to a javascript parsable data structure
197     *
198     * @param array $data Array to convert
199     *
200     * @return string Javascript readable representation of the given php array
201     */
202    private function _arrayToJs(array $data)
203    {
204        $output = array();
205
206        $assoiative = false;
207        // Is our array associative?
208        // Does anyone know a better/faster way to check this?
209        foreach (array_keys($data) as $key) {
210            if (is_int($key) === false) {
211                $assoiative = true;
212                break;
213            }
214        }
215        $output[] = $assoiative === true ? "{" : "[";
216        foreach ($data as $key => $value) {
217            $line = '';
218
219            if ($assoiative === true) {
220                $line .= "\"$key\": ";
221            }
222
223            switch (gettype($value)) {
224            case "array":
225                $line .= $this->_arrayToJs($value);
226                break;
227            case "integer":
228            case "boolean":
229                $line .= $value;
230                break;
231            case "double":
232                $line .= sprintf("%.2f", $value);
233                break;
234            case "string":
235                $line .= "\"$value\"";
236                break;
237            case "NULL":
238            case "resource":
239            case "object":
240                $line .= "undefined";
241                break;
242            }
243
244            if ($key !== end(array_keys($data))) {
245                $line .= ",";
246            }
247            $output[] = $line;
248        }
249
250        $output[] = $assoiative === true ? "}" : "]";
251
252        // If the output array has more than 5 entries seperate them by a new line.
253        return implode(count($data) > 5 ? "\n" : " ", $output);
254    }
255
256    /**
257     * Get the Javascript needed for dynamic rendering, moving, rotating
258     * and exporting of the 3D Object
259     *
260     * @return string needed javascript code (with <script> tags)
261     */
262    private function _getJs()
263    {
264        $identifiers = array(
265            "%polygones%",
266            "%background%",
267            "%width%",
268            "%height%",
269            "%uid%");
270
271        $replacements = array(
272            $this->_arrayToJs($this->_polygones) . ";\n",
273            $this->_background,
274            $this->_x,
275            $this->_y,
276            sha1(mt_rand() . mt_rand() . mt_rand() . mt_rand() . mt_rand() . mt_rand() . mt_rand()));
277
278        $jsfiles = array(
279            'Init.js',
280            'Renderer.js',
281            'CanvasDriver.js',
282            'PngDriver.js',
283            'SvgDriver.js',
284            'MouseEventGenerator.js',
285            'RotateAnimationEventGenerator.js',
286            'Toolbar.js',
287            'Base64.js',
288            'Image3D.js',
289            'Startup.js');
290
291        return str_replace($identifiers,
292            $replacements,
293            implode("\n\n",
294                array_map(create_function('$jsfile',
295                         (is_dir(dirname(__FILE__) . '/../../../data/DynamicCanvas'))
296                         ? ('return file_get_contents(dirname(__FILE__) . "/../../../data/DynamicCanvas/" . $jsfile);')
297                         : ('return file_get_contents("@data_dir@/Image_3D/data/DynamicCanvas/" . $jsfile);')),
298                    $jsfiles)));
299    }
300
301    /**
302     * Save all the gathered information to a html file
303     *
304     * @param string $file File to write output to
305     *
306     * @return void
307     */
308    public function save($file)
309    {
310        file_put_contents($file, $this->_getJs());
311    }
312
313    /**
314     * Return the shading methods this output driver is capable of
315     *
316     * @return array Shading methods supported by this driver
317     */
318    public function getSupportedShading()
319    {
320        return array(Image_3D_Renderer::SHADE_NO, Image_3D_Renderer::SHADE_FLAT);
321    }
322}
323
324?>
325