Bug 13834 fixed: NPE when too many strings are drawn
[scilab.git] / scilab / modules / renderer / src / java / org / scilab / modules / renderer / JoGLView / text / TextManager.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
4  * Copyright (C) 2012 - DIGITEO - Manuel Juliachs
5  *
6  * This file must be used under the terms of the CeCILL.
7  * This source file is licensed as described in the file COPYING, which
8  * you should have received as part of this distribution.  The terms
9  * are also available at
10  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
11  */
12
13 package org.scilab.modules.renderer.JoGLView.text;
14
15 import org.scilab.forge.scirenderer.DrawingTools;
16 import org.scilab.forge.scirenderer.SciRendererException;
17 import org.scilab.forge.scirenderer.texture.AnchorPosition;
18 import org.scilab.forge.scirenderer.texture.Texture;
19 import org.scilab.forge.scirenderer.texture.TextureManager;
20 import org.scilab.forge.scirenderer.tranformations.DegenerateMatrixException;
21 import org.scilab.forge.scirenderer.tranformations.Transformation;
22 import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
23 import org.scilab.forge.scirenderer.tranformations.Vector3d;
24 import org.scilab.modules.graphic_objects.axes.Axes;
25 import org.scilab.modules.graphic_objects.figure.ColorMap;
26 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
27 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
28 import org.scilab.modules.graphic_objects.textObject.Text;
29 import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
30 import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
31
32 import java.awt.Dimension;
33 import java.util.Map;
34 import java.util.concurrent.ConcurrentHashMap;
35
36 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_FONT_ANGLE__;
37 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_POSITION__;
38
39 /**
40  *
41  * This class manage scilab text entity drawing.
42  *
43  *
44  * TODO, Manage: {auto_dimensionning}
45  *
46  *
47  * @author Pierre Lando
48  */
49 public class TextManager {
50
51     /**
52      * The {@see Map} off existing {@see TextEntity}.
53      */
54     protected final Map<Integer, Texture> spriteMap = new ConcurrentHashMap<Integer, Texture>();
55
56     /**
57      * The used texture manager.
58      */
59     protected final TextureManager textureManager;
60
61     /**
62      * The bounds of the scale factor range for which the texture does not
63      * need to be updated.
64      */
65     protected double[] FACTOR_UPDATE_INTERVAL = {0.99, 1.01};
66
67     /**
68      * Default constructor.
69      * @param textureManager the texture manager.
70      */
71     public TextManager(TextureManager textureManager) {
72         this.textureManager = textureManager;
73     }
74
75     /**
76      * Draw the given Scilab {@see Text} with the given {@see DrawingTools}.
77      * @param drawingTools the given {@see DrawingTools}.
78      * @param colorMap the current {@see ColorMap}
79      * @param text the given Scilab {@see Text}
80      * @throws SciRendererException if the draw fails.
81      */
82     public final void draw(final DrawingTools drawingTools, final ColorMap colorMap, final Text text) throws SciRendererException {
83         Texture texture = getTexture(colorMap, text);
84
85         /* The unscaled texture's dimensions */
86         Dimension spriteDims = getSpriteDims(colorMap, text);
87
88         Transformation projection = drawingTools.getTransformationManager().getCanvasProjection();
89
90         Integer parentAxesId = text.getParentAxes();
91         Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentAxesId);
92         if (parentAxes != null) {
93             double[][] factors = parentAxes.getScaleTranslateFactors();
94             Double[] pos = text.getPosition();
95             pos[0] = pos[0] * factors[0][0] + factors[1][0];
96             pos[1] = pos[1] * factors[0][1] + factors[1][1];
97             pos[2] = pos[2] * factors[0][2] + factors[1][2];
98
99             Vector3d textPosition = new Vector3d(pos);
100
101             /* Compute the text box vectors and the text box to texture dimension ratios */
102             Vector3d[] textBoxVectors =  computeTextBoxVectors(projection, text, texture.getDataProvider().getTextureSize(), parentAxes);
103             double[] ratios = computeRatios(projection, text, textBoxVectors, texture.getDataProvider().getTextureSize(), spriteDims);
104
105             /* If text box mode is equal to filled, the texture must be updated */
106             if (text.getTextBoxMode() == 2 && ratios[0] != 1.0) {
107                 texture = updateSprite(colorMap, text, ratios[0], ratios[1]);
108             }
109
110             /* Compute the text texture's actual position, which depends on the object's text box mode property */
111             Vector3d[] cornerPositions = computeTextPosition(projection, text, textBoxVectors, texture.getDataProvider().getTextureSize());
112
113             /* Draw in window coordinates */
114             drawingTools.getTransformationManager().useWindowCoordinate();
115
116             /* The Text object's rotation direction convention is opposite to the standard one, its angle is expressed in radians. */
117             drawingTools.draw(texture, AnchorPosition.LOWER_LEFT, cornerPositions[0], -180.0 * text.getFontAngle() / Math.PI);
118
119             drawingTools.getTransformationManager().useSceneCoordinate();
120
121             /* Compute the corners of the text's bounding box in window coordinates */
122             Vector3d[] projCorners;
123             if (text.getTextBoxMode() == 2) {
124                 projCorners = computeProjTextBoxCorners(cornerPositions[1], text.getFontAngle(), textBoxVectors);
125             } else {
126                 projCorners = computeProjCorners(cornerPositions[0], text.getFontAngle(), texture.getDataProvider().getTextureSize());
127             }
128
129             Vector3d[] corners = computeCorners(projection, projCorners, parentAxes);
130             Double[] coordinates = cornersToCoordinateArray(corners);
131
132             /* Set the computed coordinates */
133             text.setCorners(coordinates);
134         }
135     }
136
137     /**
138      * Computes and returns the two vectors (in window coordinates) respectively corresponding
139      * to the text box's base and side (also named the text box width and height vectors). If the
140      * Text's text box mode is equal to off, the vectors are then equal to the Text label's base
141      * and side vectors.  The Text's rotation is ignored, as it is not required for now.
142      * @param projection the projection from object coordinates to window coordinates.
143      * @param text the Scilab {@see Text}.
144      * @param dimension the current text texture's dimension (in pixels).
145      * @param parentAxes the Axes for which the coordinates are computed.
146      * @return the text box width and height vectors (in window coordinates).
147      */
148     protected Vector3d[] computeTextBoxVectors(Transformation projection, Text text, Dimension dimension, Axes parentAxes) {
149         Double[] textBox = text.getTextBox();
150         Vector3d[] textBoxVectors = new Vector3d[2];
151         double[][] factors = parentAxes.getScaleTranslateFactors();
152         Double[] pos = text.getPosition();
153
154         /* The text position vector before logarithmic scaling */
155         Vector3d textPosition = new Vector3d(pos);
156
157         boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
158
159         /* Apply logarithmic scaling and then project */
160         textPosition = ScaleUtils.applyLogScale(textPosition, logFlags);
161         textPosition = new Vector3d(textPosition.getX() * factors[0][0] + factors[1][0], textPosition.getY() * factors[0][1] + factors[1][1], textPosition.getZ() * factors[0][2] + factors[1][2]);
162         Vector3d projTextPosition = projection.project(textPosition);
163
164         /* Compute the text label vectors in window coordinates */
165         Vector3d width = new Vector3d(dimension.getWidth(), 0.0, 0.0);
166         Vector3d height = new Vector3d(0.0, dimension.getHeight(), 0.0);
167
168         Vector3d projTextWidth = projTextPosition.plus(width);
169         Vector3d projTextHeight = projTextPosition.plus(height);
170
171         /*
172          * Compute the text box's vectors in object coordinates, from the object coordinate text label vectors.
173          * Their norms are unaffected by the text's rotation, which is thus ignored.
174          */
175         Vector3d textWidth = projection.unproject(projTextWidth);
176         Vector3d textHeight = projection.unproject(projTextHeight);
177
178         /* Applies inverse logarithmic scaling */
179         textWidth = ScaleUtils.applyInverseLogScale(textWidth, logFlags);
180         textHeight = ScaleUtils.applyInverseLogScale(textHeight, logFlags);
181
182         textWidth = textWidth.minus(textPosition);
183         textHeight = textHeight.minus(textPosition);
184
185         if (text.getTextBoxMode() >= 1) {
186             textWidth = textWidth.getNormalized().times(textBox[0] * factors[0][0]);
187             textHeight = textHeight.getNormalized().times(textBox[1] * factors[0][1]);
188         }
189
190         /*
191          * We take into account the reverse axes flags in order to
192          * compute the actual text box corners, and hence the correct vectors,
193          * which is necessary when logarithmic scaling is applied.
194          */
195         if (parentAxes.getXAxisReverse()) {
196             textWidth = textWidth.setX(Math.abs(textWidth.getX()));
197             textHeight = textHeight.setX(Math.abs(textHeight.getX()));
198         }
199         if (parentAxes.getYAxisReverse()) {
200             textWidth = textWidth.setY(Math.abs(textWidth.getY()));
201             textHeight = textHeight.setY(Math.abs(textHeight.getY()));
202         }
203         if (parentAxes.getZAxisReverse()) {
204             textWidth = textWidth.setZ(Math.abs(textWidth.getZ()));
205             textHeight = textHeight.setZ(Math.abs(textHeight.getZ()));
206         }
207
208         /* Computes the lower-right and upper-left corners. */
209         textWidth = textWidth.plus(textPosition);
210         textHeight = textHeight.plus(textPosition);
211
212         /* Finally re-apply logarithmic scaling, compute the vectors and project */
213         textWidth = ScaleUtils.applyLogScale(textWidth, logFlags);
214         textHeight = ScaleUtils.applyLogScale(textHeight, logFlags);
215
216         textWidth = textWidth.minus(textPosition);
217         textHeight = textHeight.minus(textPosition);
218
219         projTextWidth = projection.projectDirection(textWidth);
220         projTextHeight = projection.projectDirection(textHeight);
221
222         /*
223          * Ensures that the two window-coordinate base vectors respectively point to the right
224          * and to the top, as taking reversed axes into account may have reversed them (see above).
225          */
226         projTextWidth = projTextWidth.setX(Math.abs(projTextWidth.getX()));
227         projTextHeight = projTextHeight.setX(Math.abs(projTextHeight.getX()));
228         projTextWidth = projTextWidth.setY(Math.abs(projTextWidth.getY()));
229         projTextHeight = projTextHeight.setY(Math.abs(projTextHeight.getY()));
230
231         textBoxVectors[0] = projTextWidth;
232         textBoxVectors[1] = projTextHeight;
233
234         return textBoxVectors;
235     }
236
237     /**
238      * Computes and returns the minimum of the ratios between the text box and the text texture's dimensions.
239      * This minimum ratio is determined for both the current text texture and the unscaled text texture.
240      * @param projection the projection from object coordinates to window coordinates.
241      * @param text the Scilab {@see Text}.
242      * @param textBoxVectors the text box width and height vectors (in window coordinates).
243      * @param spriteDimension the current text texture's dimension (in pixels).
244      * @param baseSpriteDimension the unscaled text texture's dimension (in pixels).
245      * @return the minimum ratios (2 elements: text box to current texture and text box to unscaled texture ratios).
246      */
247     protected double[] computeRatios(Transformation projection, Text text, Vector3d[] textBoxVectors, Dimension spriteDimension,
248                                      Dimension baseSpriteDimension) {
249         /* 1st element: ratio for the current texture, 2nd element: ratio for the unscaled texture */
250         double[] ratios = new double[] {1.0, 1.0};
251
252         /* Ratios are relevant only to the filled text box mode */
253         if (text.getTextBoxMode() == 2) {
254             Vector3d textBoxWidth = textBoxVectors[0];
255             Vector3d textBoxHeight = textBoxVectors[1];
256
257             /* Compute the ratios. */
258             double minRatio = Math.min(Math.abs(textBoxWidth.getX() / spriteDimension.width), Math.abs(textBoxHeight.getY() / spriteDimension.height));
259             double baseMinRatio = Math.min(Math.abs(textBoxWidth.getX() / baseSpriteDimension.width), Math.abs(textBoxHeight.getY() / baseSpriteDimension.height));
260
261             ratios[0] = minRatio;
262             ratios[1] = baseMinRatio;
263         }
264
265         return ratios;
266     }
267
268     /**
269      * Computes and returns the positions of a Scilab {@see Text} object and its text box in window coordinates, as a function
270      * of its text box mode and text box properties. They are the position of the Text's lower-left corner,
271      * which may differ from the text's unmodified position, depending on its text box properties, and
272      * the position of the text box's lower-left corner. If the text box mode is set to off, the text lower-left corner's position
273      * is simply the text's projected position, and its text box's position is equal to the former.
274      * @param projection the projection from object coordinates to window coordinates.
275      * @param text the Scilab {@see Text}.
276      * @param textBoxVectors the text box width and height vectors (in window coordinates).
277      * @param spriteDim the text texture's dimension (in pixels).
278      * @return the lower-left corners of the Scilab {@see Text}'s text and of its text box in window coordinates (2 elements).
279      * @throws DegenerateMatrixException if the projection is not possible.
280      */
281     protected Vector3d[] computeTextPosition(Transformation projection, Text text, Vector3d[] textBoxVectors, Dimension spriteDim) throws DegenerateMatrixException {
282         Vector3d[] cornerPositions = new Vector3d[2];
283         Integer parentAxesId = text.getParentAxes();
284         Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentAxesId);
285         double[][] factors = parentAxes.getScaleTranslateFactors();
286         Double[] pos = text.getPosition();
287         Vector3d textPosition = new Vector3d(pos);
288
289         /* Apply logarithmic scaling */
290         boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
291         textPosition = ScaleUtils.applyLogScale(textPosition, logFlags);
292         textPosition = new Vector3d(textPosition.getX() * factors[0][0] + factors[1][0], textPosition.getY() * factors[0][1] + factors[1][1], textPosition.getZ() * factors[0][2] + factors[1][2]);
293
294         textPosition = projection.project(textPosition);
295
296         cornerPositions[0] = new Vector3d(textPosition);
297         cornerPositions[1] = new Vector3d(textPosition);
298
299         if (text.getTextBoxMode() >= 1) {
300             Vector3d textBoxWidth = new Vector3d(textBoxVectors[0]);
301             Vector3d textBoxHeight = new Vector3d(textBoxVectors[1]);
302
303             double[] textBoxWidthData = textBoxWidth.getData();
304             double[] textBoxHeightData = textBoxHeight.getData();
305
306             /* Reversed axes must be taken into account to correctly compute the text texture's lower-left corner. */
307             if (parentAxes.getXAxisReverse()) {
308                 textBoxWidthData[0] = -textBoxWidthData[0];
309                 textBoxHeightData[0] = -textBoxHeightData[0];
310             }
311
312             if (parentAxes.getYAxisReverse()) {
313                 textBoxWidthData[1] = -textBoxWidthData[1];
314                 textBoxHeightData[1] = -textBoxHeightData[1];
315             }
316
317             if (parentAxes.getZAxisReverse()) {
318                 textBoxWidthData[2] = -textBoxWidthData[2];
319                 textBoxHeightData[2] = -textBoxHeightData[2];
320             }
321
322             Vector3d revTextBoxWidth = new Vector3d(textBoxWidthData);
323             Vector3d revTextBoxHeight = new Vector3d(textBoxHeightData);
324
325             Vector3d[] projCorners = computeProjCorners(textPosition, text.getFontAngle(), spriteDim);
326
327             Vector3d textWidth = projCorners[1].minus(projCorners[0]);
328             Vector3d textHeight = projCorners[2].minus(projCorners[0]);
329
330             /*
331              * Compute the final text box's and text's half-length vectors,
332              * using the rotated text label vectors.
333              */
334             revTextBoxWidth = textWidth.getNormalized().times(0.5 * revTextBoxWidth.getX());
335             revTextBoxHeight = textHeight.getNormalized().times(0.5 * revTextBoxHeight.getY());
336
337             textBoxWidth = textWidth.getNormalized().times(0.5 * textBoxWidth.getX());
338             textBoxHeight = textHeight.getNormalized().times(0.5 * textBoxHeight.getY());
339
340             textWidth = textWidth.times(0.5);
341             textHeight = textHeight.times(0.5);
342
343             /* Compute the actual corner positions from the initial projected position and the half-length vectors */
344             textPosition = textPosition.plus(revTextBoxWidth);
345             textPosition = textPosition.plus(revTextBoxHeight);
346
347             Vector3d textBoxCorner = textPosition.minus(textBoxWidth);
348             textBoxCorner = textBoxCorner.minus(textBoxHeight);
349
350             textPosition = textPosition.minus(textWidth);
351             textPosition = textPosition.minus(textHeight);
352
353             cornerPositions[0] = textPosition;
354             cornerPositions[1] = textBoxCorner;
355         }
356
357         return cornerPositions;
358     }
359
360     /**
361      * Computes and returns the corners of a {@see Text} object's bounding box, in window coordinates.
362      * The returned corners are in the following order: lower-left, lower-right, upper-left and upper-right.
363      * @param canvasProj the projection from object coordinates to window coordinates.
364      * @param position the text's position in object coordinates.
365      * @param fontAngle the text's font angle (radians).
366      * @param spriteDim the text texture's dimension (in pixels).
367      * @return the corners' window coordinates (4-element array).
368      * @throws DegenerateMatrixException if the projection is not possible.
369      */
370     protected Vector3d[] computeProjCorners(Transformation canvasProj, Vector3d position, double fontAngle, Dimension spriteDim) throws DegenerateMatrixException {
371         position = canvasProj.project(position);
372         return computeProjCorners(position, fontAngle, spriteDim);
373     }
374
375     /**
376      * Computes the corners of a {@see Text} object's text box, in window coordinates.
377      * @param position the position of the text box's lower-left corner in window cordinates.
378      * @param fontAngle the text's font angle (radians).
379      * @param textBoxVectors the text box width and height vectors (in window coordinates).
380      * @return the corners' window coordinates (4-element array).
381      * @throws DegenerateMatrixException if the projection is not possible.
382      */
383     protected Vector3d[] computeProjTextBoxCorners(Vector3d position, double fontAngle, Vector3d[] textBoxVectors) throws DegenerateMatrixException {
384         double projTextBoxWidth = textBoxVectors[0].getNorm();
385         double projTextBoxHeight = textBoxVectors[1].getNorm();
386
387         return computeProjCorners(position, fontAngle, new Dimension((int) projTextBoxWidth, (int) projTextBoxHeight));
388     }
389
390     /**
391      * Computes and returns the corners of a {@see Text} object's bounding box, in window coordinates.
392      * The returned corners are in the following order: lower-left, lower-right, upper-left and upper-right.
393      * @param projPosition the text's position in window coordinates.
394      * @param fontAngle the text's font angle (radians).
395      * @param spriteDim the text texture's dimension (in pixels).
396      * @return the corners' window coordinates (4-element array).
397      * @throws DegenerateMatrixException if the projection is not possible.
398      */
399     protected Vector3d[] computeProjCorners(Vector3d projPosition, double fontAngle, Dimension spriteDim) throws DegenerateMatrixException {
400         Vector3d[] projCorners = new Vector3d[4];
401
402         /*
403          * Should be -fontAngle, as positive angle values are measured clockwise for texts.
404          * Apparently uses the same convention as the texts (clockwise positive directions).
405          * To be verified.
406          */
407         Transformation projRotation = TransformationFactory.getRotationTransformation(180.0 * fontAngle / Math.PI, 0.0, 0.0, 1.0);
408
409         projCorners[0] = projPosition;
410
411         Vector3d width = new Vector3d(spriteDim.width, 0.0, 0.0);
412         Vector3d height = new Vector3d(0.0, spriteDim.height, 0.0);
413
414         width = projRotation.projectDirection(width);
415         height = projRotation.projectDirection(height);
416
417         projCorners[1] = projCorners[0].plus(width);
418         projCorners[2] = projCorners[0].plus(height);
419         projCorners[3] = projCorners[2].plus(width);
420
421         return projCorners;
422     }
423
424     /**
425      * Computes and returns the corners (in user coordinates) of a text's bounding box.
426      * @param projection the projection from object coordinates to window coordinates.
427      * @param projCorners the corners of the text's bounding box in window coordinates (4-element array).
428      * @param parentAxes the Axes for which the coordinates are computed.
429      * @return the corners of the text's bounding box in user coordinates (4-element array).
430      */
431     protected Vector3d[] computeCorners(Transformation projection, Vector3d[] projCorners, Axes parentAxes) {
432         Vector3d[] corners = new Vector3d[4];
433         boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
434
435         corners[0] = projection.unproject(projCorners[0]);
436         corners[1] = projection.unproject(projCorners[1]);
437         corners[2] = projection.unproject(projCorners[2]);
438         corners[3] = projection.unproject(projCorners[3]);
439
440         /* Apply inverse logarithmic scaling in order to obtain user coordinates */
441         corners[0] = ScaleUtils.applyInverseLogScale(corners[0], logFlags);
442         corners[1] = ScaleUtils.applyInverseLogScale(corners[1], logFlags);
443         corners[2] = ScaleUtils.applyInverseLogScale(corners[2], logFlags);
444         corners[3] = ScaleUtils.applyInverseLogScale(corners[3], logFlags);
445
446         return corners;
447     }
448
449     /**
450      * Returns the positions of a bounding box's corners as an array of (x,y,z) coordinate triplets.
451      * The output corners are reordered to match their order in the {@see Text} object's
452      * equivalent array, respectively: lower-left, lower-right, upper-left, upper-right in the input array,
453      * starting from the lower-left and going in clockwise order in the returned array.
454      * @param corners of the bounding box (4-element array).
455      * @return the corners' coordinates (12-element array).
456      */
457     protected Double[] cornersToCoordinateArray(Vector3d[] corners) {
458         Double[] coordinates = new Double[12];
459         coordinates[0] = corners[0].getX();
460         coordinates[1] = corners[0].getY();
461         coordinates[2] = corners[0].getZ();
462
463         coordinates[3] = corners[2].getX();
464         coordinates[4] = corners[2].getY();
465         coordinates[5] = corners[2].getZ();
466
467         coordinates[6] = corners[3].getX();
468         coordinates[7] = corners[3].getY();
469         coordinates[8] = corners[3].getZ();
470
471         coordinates[9] = corners[1].getX();
472         coordinates[10] = corners[1].getY();
473         coordinates[11] = corners[1].getZ();
474
475         return coordinates;
476     }
477
478     /**
479      * Update the data if needed.
480      * @param id the modified object.
481      * @param property the changed property.
482      */
483     public void update(Integer id, int property) {
484         if (!(__GO_POSITION__ == property) && !(__GO_FONT_ANGLE__ == property)) {
485             dispose(id);
486         }
487     }
488
489     /**
490      * Return the SciRenderer {@see Texture} corresponding to the given Scilab {@see Text}.
491      * @param colorMap the current color map.
492      * @param text the given Scilab {@see Text}.
493      * @return the SciRenderer {@see Texture} corresponding to the given Scilab {@see Text}.
494      */
495     protected Texture getTexture(final ColorMap colorMap, final Text text) {
496         Texture texture = spriteMap.get(text.getIdentifier());
497         if (texture == null) {
498             if (text.getTextBoxMode() == 2) {
499                 /* Create an unscaled texture (scale factor equal to 1) */
500                 texture = createSprite(colorMap, text, 1.0);
501             } else {
502                 texture = createSprite(colorMap, text);
503             }
504             spriteMap.put(text.getIdentifier(), texture);
505         }
506         return texture;
507     }
508
509     /**
510      * Updates a texture according to a scale factor, which is the ratio by which the texture is enlarged.
511      * @param colorMap the current color map.
512      * @param text the Scilab Text.
513      * @param scaleFactor the scale factor relative to the current texture's dimensions.
514      * @param baseScaleFactor the scale factor relative to the unscaled texture's dimensions.
515      * @return the corresponding texture.
516      */
517     protected Texture updateSprite(final ColorMap colorMap, final Text text, double scaleFactor, double baseScaleFactor) {
518         Texture texture = spriteMap.get(text.getIdentifier());
519
520         /* Create a new texture if the scale factor falls outside of the range */
521         if (scaleFactor < FACTOR_UPDATE_INTERVAL[0] || scaleFactor > FACTOR_UPDATE_INTERVAL[1]) {
522             dispose(text.getIdentifier());
523             texture = createSprite(colorMap, text, baseScaleFactor);
524             spriteMap.put(text.getIdentifier(), texture);
525         }
526
527         return texture;
528     }
529
530     /**
531      * Returns the dimensions of the SciRenderer {@see Texture} corresponding to the given Scilab {@see Text}.
532      * The dimensions are in pixels (width, height).
533      * @param colorMap the current color map.
534      * @param text the given Scilab {@see Text}.
535      * @return the texture's dimension.
536      */
537     protected Dimension getSpriteDims(final ColorMap colorMap, final Text text) {
538         TextSpriteDrawer spriteDrawer;
539
540         if (text.getTextBoxMode() == 2) {
541             /* Set the scale factor to 1 in order to return the dimensions of an unscaled texture. */
542             spriteDrawer = new TextSpriteDrawer(colorMap, text, 1.0);
543         } else {
544             spriteDrawer = new TextSpriteDrawer(colorMap, text);
545         }
546
547         return spriteDrawer.getTextureSize();
548     }
549
550     /**
551      * Create a texture for the given text object.
552      * @param colorMap the current colormap.
553      * @param textObject the given text object.
554      * @return a new texture for the given text object.
555      */
556     protected Texture createSprite(final ColorMap colorMap, final Text textObject) {
557         TextSpriteDrawer spriteDrawer = new TextSpriteDrawer(colorMap, textObject);
558         Texture texture = textureManager.createTexture();
559         texture.setMagnificationFilter(Texture.Filter.LINEAR);
560         texture.setMinifyingFilter(Texture.Filter.LINEAR);
561         texture.setDrawer(spriteDrawer);
562         return texture;
563     }
564
565     /**
566      * Creates a texture for the given text object, scaled by the given scale factor.
567      * @param colorMap the current colormap.
568      * @param textObject the given text object.
569      * @param scaleFactor the scale factor to apply.
570      * @return a new texture for the given text object.
571      */
572     protected Texture createSprite(final ColorMap colorMap, final Text textObject, double scaleFactor) {
573         TextSpriteDrawer spriteDrawer = new TextSpriteDrawer(colorMap, textObject, scaleFactor);
574         Texture texture = textureManager.createTexture();
575         texture.setMagnificationFilter(Texture.Filter.LINEAR);
576         texture.setMinifyingFilter(Texture.Filter.LINEAR);
577         texture.setDrawer(spriteDrawer);
578         return texture;
579     }
580
581     /**
582      * Dispose the texture corresponding to the given id.
583      * @param id the given id.
584      */
585     public void dispose(Integer id) {
586         Texture texture = spriteMap.get(id);
587         if (texture != null) {
588             textureManager.dispose(texture);
589             spriteMap.remove(id);
590         }
591     }
592
593     /**
594      * Dispose all the text sprites.
595      */
596     public void disposeAll() {
597         textureManager.dispose(spriteMap.values());
598         spriteMap.clear();
599     }
600
601     /**
602      * Computes and updates the corners of the given Scilab {@see Text}.
603      * @param text the given Scilab {@see Text}.
604      */
605     public static void updateTextCorners(Text text) {
606         Vector3d[] projCorners = null;
607
608         DrawerVisitor currentVisitor = DrawerVisitor.getVisitor(text.getParentFrameOrFigure());
609         Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(text.getParentAxes());
610
611         /* Compute the corners */
612         try {
613             Transformation currentProj = currentVisitor.getAxesDrawer().getCurrentProjection(parentAxes);
614
615             Dimension spriteDim = currentVisitor.getTextManager().getSpriteDims(currentVisitor.getColorMap(), text);
616
617             Vector3d[] textBoxVectors = currentVisitor.getTextManager().computeTextBoxVectors(currentProj, text, spriteDim, parentAxes);
618             Vector3d[] cornerPositions = currentVisitor.getTextManager().computeTextPosition(currentProj, text, textBoxVectors, spriteDim);
619
620             if (text.getTextBoxMode() == 2) {
621                 projCorners = currentVisitor.getTextManager().computeProjTextBoxCorners(cornerPositions[1], text.getFontAngle(), textBoxVectors);
622             } else {
623                 projCorners = currentVisitor.getTextManager().computeProjCorners(cornerPositions[0], text.getFontAngle(), spriteDim);
624             }
625
626             Vector3d[] corners = currentVisitor.getTextManager().computeCorners(currentProj, projCorners, parentAxes);
627             Double[] coordinates = currentVisitor.getTextManager().cornersToCoordinateArray(corners);
628
629             double[][] factors = parentAxes.getScaleTranslateFactors();
630             coordinates[0] = (coordinates[0] - factors[1][0]) / factors[0][0];
631             coordinates[1] = (coordinates[1] - factors[1][1]) / factors[0][1];
632             coordinates[2] = (coordinates[2] - factors[1][2]) / factors[0][2];
633             coordinates[3] = (coordinates[3] - factors[1][0]) / factors[0][0];
634             coordinates[4] = (coordinates[4] - factors[1][1]) / factors[0][1];
635             coordinates[5] = (coordinates[5] - factors[1][2]) / factors[0][2];
636             coordinates[6] = (coordinates[6] - factors[1][0]) / factors[0][0];
637             coordinates[7] = (coordinates[7] - factors[1][1]) / factors[0][1];
638             coordinates[8] = (coordinates[8] - factors[1][2]) / factors[0][2];
639             coordinates[9] = (coordinates[9] - factors[1][0]) / factors[0][0];
640             coordinates[10] = (coordinates[10] - factors[1][1]) / factors[0][1];
641             coordinates[11] = (coordinates[11] - factors[1][2]) / factors[0][2];
642
643             /* Set the computed coordinates */
644             text.setCorners(coordinates);
645
646         } catch (DegenerateMatrixException e) {
647             // TODO Auto-generated catch block
648             e.printStackTrace();
649         }
650     }
651 }