a4371f82e630266a9100a29b33117691ac1efd90
[scilab.git] / scilab / modules / scirenderer / src / org / scilab / forge / scirenderer / implementation / g2d / motor / SpritedRectangle.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  */
11
12 package org.scilab.forge.scirenderer.implementation.g2d.motor;
13
14 import java.awt.Color;
15 import java.awt.Dimension;
16 import java.awt.Graphics2D;
17 import java.awt.RenderingHints;
18 import java.awt.Stroke;
19 import java.awt.geom.AffineTransform;
20 import java.awt.geom.Path2D;
21 import java.awt.image.BufferedImage;
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.scilab.forge.scirenderer.implementation.g2d.texture.G2DTextureDrawingTools;
26 import org.scilab.forge.scirenderer.texture.Texture;
27 import org.scilab.forge.scirenderer.texture.AnchorPosition;
28 import org.scilab.forge.scirenderer.tranformations.Transformation;
29 import org.scilab.forge.scirenderer.tranformations.Vector3d;
30 import org.scilab.forge.scirenderer.tranformations.Vector4d;
31
32 /**
33  * @author Calixte DENIZET
34  */
35 public class SpritedRectangle extends ConvexObject {
36
37     private static final Color[] COLORS = new Color[] {Color.BLACK, Color.BLACK, Color.BLACK};
38
39     private Texture sprite;
40     private BufferedImage image;
41     private G2DTextureDrawingTools drawingTools;
42     private double rotationAngle;
43     private Texture.Filter filter;
44     private Vector3d position;
45     private Color fillColor;
46
47     public SpritedRectangle(Vector3d vertex, Texture sprite, AnchorPosition anchor, G2DTextureDrawingTools drawingTools, double rotationAngle, Color fillColor) throws InvalidPolygonException {
48         super(getSpriteVertices(vertex, sprite, anchor, rotationAngle), null);
49         this.sprite = sprite;
50         this.drawingTools = drawingTools;
51         this.rotationAngle = rotationAngle;
52         this.position = vertex;
53         this.fillColor = fillColor;
54     }
55
56     public SpritedRectangle(Vector3d vertex, Transformation transf, BufferedImage image, Texture.Filter filter) throws InvalidPolygonException {
57         super(getSpriteVertices(vertex, transf, image), null);
58         this.image = image;
59         this.filter = filter;
60         this.position = vertex;
61     }
62
63     @Override
64     public List<ConvexObject> breakObject(ConvexObject o) {
65         if (o instanceof Triangle) {
66             return breakObject((Triangle) o);
67         } else if (o instanceof Segment) {
68             return breakObject((Segment) o);
69         } else if (o instanceof SpritedRectangle) {
70             return breakObject((SpritedRectangle) o);
71         }
72         return null;
73     }
74
75     public List<ConvexObject> breakObject(Triangle o) {
76         try {
77             Vector3d[] v1 = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
78             Vector3d[] v2 = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
79             Triangle t1 = new Triangle(v1, COLORS);
80             Triangle t2 = new Triangle(v2, COLORS);
81             t1.setSprite(this);
82             t2.setSprite(this);
83             List<ConvexObject> list = new ArrayList<ConvexObject>();
84             if (o.isBehind(t1) == 2) {
85                 List<ConvexObject> list2 = o.breakObject(t1);
86                 if (list2 != null) {
87                     list.addAll(list2);
88                 }
89             } else {
90                 list.add(t1);
91             }
92             if (o.isBehind(t2) == 2) {
93                 List<ConvexObject> list2 = o.breakObject(t2);
94                 if (list2 != null) {
95                     list.addAll(list2);
96                 }
97             } else {
98                 list.add(t2);
99             }
100
101             return list;
102         } catch (InvalidPolygonException e) { }
103
104         return null;
105     }
106
107     public List<ConvexObject> breakObject(Segment o) {
108         try {
109             Vector3d[] v = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
110             Triangle t1 = new Triangle(v, COLORS);
111             t1.setSprite(this);
112             v = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
113             Triangle t2 = new Triangle(v, COLORS);
114             t2.setSprite(this);
115             List<ConvexObject> list = t1.breakObject(o);
116             if (list != null) {
117                 list.add(t2);
118                 return list;
119             }
120
121             list = t2.breakObject(o);
122             if (list != null) {
123                 list.add(t1);
124                 return list;
125             }
126         } catch (InvalidPolygonException e) { }
127
128         return null;
129     }
130
131     public List<ConvexObject> breakObject(SpritedRectangle o) {
132         try {
133             Vector3d[] v1 = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
134             Vector3d[] v2 = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
135             Triangle t1 = new Triangle(v1, COLORS);
136             Triangle t2 = new Triangle(v2, COLORS);
137             t1.setSprite(this);
138             t2.setSprite(this);
139             List<ConvexObject> list = o.breakObject(t1);
140             if (list == null) {
141                 list = o.breakObject(t2);
142             } else {
143                 List<ConvexObject> list2 = o.breakObject(t2);
144                 if (list2 != null) {
145                     list.addAll(list2);
146                 }
147             }
148
149             return list;
150         } catch (InvalidPolygonException e) { }
151
152         return null;
153     }
154
155     public List<ConvexObject> breakObject(Vector4d v) {
156         try {
157             double[] vv = v.getData();
158             Vector3d np = new Vector3d(vv);
159             int ret = isBehind(np, vv[3]);
160             if (ret == 1) {
161                 List<ConvexObject> list = new ArrayList<ConvexObject>();
162                 list.add(this);
163                 return list;
164             } else if (ret == -1) {
165                 return null;
166             }
167
168             Vector3d[] v1 = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
169             Vector3d[] v2 = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
170             Triangle t1 = new Triangle(v1, COLORS);
171             Triangle t2 = new Triangle(v2, COLORS);
172             t1.setSprite(this);
173             t2.setSprite(this);
174             List<ConvexObject> list = t1.breakObject(v);
175             if (list != null) {
176                 List<ConvexObject> list2 = t2.breakObject(v);
177                 if (list2 != null) {
178                     list.addAll(list2);
179                 }
180                 return list;
181             } else {
182                 return t2.breakObject(v);
183             }
184         } catch (InvalidPolygonException e) { }
185
186         return null;
187     }
188
189     private static Vector3d[] getSpriteVertices(Vector3d vertex, Transformation transf, BufferedImage image) {
190         int w = image.getWidth();
191         int h = image.getHeight();
192         double x = vertex.getX();
193         double y = vertex.getY();
194         double z = vertex.getZ();
195
196         return new Vector3d[] {transf.project(new Vector3d(x, y, z)), transf.project(new Vector3d(x + w, y, z)), transf.project(new Vector3d(x + w, y + h, z)), transf.project(new Vector3d(x, y + h, z))};
197     }
198
199     private static Vector3d[] getSpriteVertices(Vector3d vertex, Texture sprite, AnchorPosition anchor) {
200         Dimension d = sprite.getDataProvider().getTextureSize();
201         double spriteWidth = d.getWidth();
202         double spriteHeight = d.getHeight();
203         double deltaX = 0;
204         double deltaY = 0;
205
206         switch (anchor) {
207             case LEFT:
208                 deltaX = spriteWidth / 2;
209                 break;
210             case LOWER_LEFT:
211                 deltaX = spriteWidth / 2;
212                 deltaY = spriteHeight / 2;
213                 break;
214             case UPPER_LEFT:
215                 deltaX = spriteWidth / 2;
216                 deltaY = -spriteHeight / 2;
217                 break;
218             case UP:
219                 deltaY = -spriteHeight / 2;
220                 break;
221             case CENTER:
222                 break;
223             case DOWN:
224                 deltaY = spriteHeight / 2;
225                 break;
226             case RIGHT:
227                 deltaX = -spriteWidth / 2;
228                 break;
229             case LOWER_RIGHT:
230                 deltaX = -spriteWidth / 2;
231                 deltaY = spriteHeight / 2;
232                 break;
233             case UPPER_RIGHT:
234                 deltaX = -spriteWidth / 2;
235                 deltaY = -spriteHeight / 2;
236                 break;
237             default:
238         }
239
240         double x = deltaX;
241         double y = -deltaY;
242         double z = vertex.getZ();
243
244         return new Vector3d[] {new Vector3d(x - spriteWidth / 2, y - spriteHeight / 2, z),
245                    new Vector3d(x - spriteWidth / 2, y + spriteHeight / 2, z),
246                    new Vector3d(x + spriteWidth / 2, y + spriteHeight / 2, z),
247                    new Vector3d(x + spriteWidth / 2, y - spriteHeight / 2, z)
248         };
249     }
250
251     private static Vector3d[] getSpriteVertices(Vector3d vertex, Texture sprite, AnchorPosition anchor, double rotationAngle) {
252         Vector3d[] points = getSpriteVertices(vertex, sprite, anchor);
253
254         if (rotationAngle != 0) {
255             final double a = -rotationAngle * Math.PI / 180;
256             final double ca = Math.cos(a);
257             final double sa = Math.sin(a);
258
259             for (int i = 0; i < 4; i++) {
260                 points[i] = new Vector3d(vertex.getX() + ca * points[i].getX() - sa * points[i].getY(), vertex.getY() + sa * points[i].getX() + ca * points[i].getY(), vertex.getZ());
261             }
262         } else {
263             for (int i = 0; i < 4; i++) {
264                 points[i] = new Vector3d(vertex.getX() + points[i].getX(), vertex.getY() + points[i].getY(), vertex.getZ());
265             }
266         }
267
268         return points;
269     }
270
271     private static Vector3d unrotate(Vector3d v, Vector3d t, double rotationAngle) {
272         v = v.minus(t);
273         final double a = rotationAngle * Math.PI / 180;
274         final double ca = Math.cos(a);
275         final double sa = Math.sin(a);
276
277         return new Vector3d(ca * v.getX() - sa * v.getY(), sa * v.getX() + ca * v.getY(), v.getZ());
278     }
279
280     public Texture getSprite() {
281         return sprite;
282     }
283
284     @Override
285     public void draw(Graphics2D g2d) {
286         if (sprite != null) {
287             Path2D contour = getProjectedContour();
288             AffineTransform oldTransf = g2d.getTransform();
289             Stroke oldStroke = g2d.getStroke();
290
291             if (rotationAngle != 0) {
292                 g2d.translate(position.getX(), position.getY());
293                 g2d.rotate(-rotationAngle * Math.PI / 180);
294                 Vector3d v = unrotate(vertices[0], position, rotationAngle);
295                 g2d.translate(v.getX(), v.getY());
296             } else {
297                 g2d.translate(vertices[0].getX(), vertices[0].getY());
298             }
299
300             drawingTools.accept(sprite, fillColor);
301             g2d.setTransform(oldTransf);
302             g2d.setStroke(oldStroke);
303         } else {
304             Object key = filter == Texture.Filter.LINEAR ? RenderingHints.VALUE_INTERPOLATION_BILINEAR : RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
305             DrawTools.drawParallelogramTexture(g2d, image, new double[] {0, 1, 1, 0}, new double[] {0, 0, 1, 1},
306                                                new double[] {vertices[3].getX(), vertices[2].getX(), vertices[1].getX(), vertices[0].getX()},
307                                                new double[] {vertices[3].getY(), vertices[2].getY(), vertices[1].getY(), vertices[0].getY()}, key);
308         }
309     }
310
311     public String toString() {
312         return "SpritedRectangle: " + vertices[0].toString() + " " + vertices[1].toString() + " " + vertices[2].toString() + " " + vertices[3].toString() + "\nPrecedence: " + precedence;
313     }
314 }