]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.g2d/src/org/simantics/g2d/image/impl/Shadow.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / image / impl / Shadow.java
diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/image/impl/Shadow.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/image/impl/Shadow.java
new file mode 100644 (file)
index 0000000..cb432fd
--- /dev/null
@@ -0,0 +1,183 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.g2d.image.impl;\r
+\r
+import java.awt.AlphaComposite;\r
+import java.awt.Color;\r
+import java.awt.Graphics2D;\r
+import java.awt.geom.Point2D;\r
+import java.awt.geom.Rectangle2D;\r
+import java.awt.image.BufferedImage;\r
+import java.awt.image.ConvolveOp;\r
+import java.awt.image.Kernel;\r
+import java.util.Arrays;\r
+import java.util.EnumSet;\r
+\r
+import org.simantics.g2d.image.Image;\r
+import org.simantics.scenegraph.Node;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+\r
+/**\r
+ * Reflects to a shadow of a symbol.\r
+ * \r
+ * @author Toni Kalajainen\r
+ */\r
+public class Shadow extends ImageProxy implements Image {\r
+\r
+    public static final ShadowParameters SHADOW = new ShadowParameters(0.5, Color.BLACK, 2);\r
+    public static final class ShadowParameters {\r
+        public final double alpha;\r
+        public final Color color;\r
+        public final int size;\r
+        public ShadowParameters(double alpha, Color color, int size) {\r
+            this.alpha = alpha;\r
+            this.color = color;\r
+            this.size = size;\r
+        }\r
+    }\r
+\r
+    public final ShadowParameters shadow;\r
+    Point2D size;\r
+    ConvolveOp horiz, vert;\r
+    int shadowSizeX, shadowSizeY;\r
+    EnumSet<Feature> feats;\r
+    public ImageListener origListener;\r
+\r
+    /**\r
+     * \r
+     * @param source\r
+     * @param shadow\r
+     * @param shadowOnly\r
+     */\r
+    public Shadow(Image source, ShadowParameters shadow)\r
+    {\r
+        super(source);\r
+        this.shadow = shadow;\r
+        shadowSizeX = shadow.size;\r
+        shadowSizeY = shadow.size;\r
+        horiz          = createBlurOp(shadow.size, 1);\r
+        vert           = createBlurOp(1, shadow.size);\r
+        if (source.getFeatures().contains(Feature.Volatile)) {\r
+            feats =    EnumSet.of(Feature.Volatile);\r
+        } else\r
+            feats = EnumSet.noneOf(Feature.class);\r
+    }\r
+\r
+    public Shadow(Image source, ShadowParameters shadow, double width, double height)\r
+    {\r
+        this(source, shadow);\r
+        this.size      = new Point2D.Double(width, height);\r
+        shadowSizeX = (int) Math.round( shadow.size * width  / source.getBounds().getWidth()  );\r
+        shadowSizeY = (int) Math.round( shadow.size * height / source.getBounds().getHeight() );\r
+        if (shadowSizeX<1) shadowSizeX = 1;\r
+        if (shadowSizeY<1) shadowSizeY = 1;\r
+        horiz          = createBlurOp(shadowSizeX, 1);\r
+        vert           = createBlurOp(1, shadowSizeY);\r
+    }\r
+\r
+    @Override\r
+    public Rectangle2D getBounds() {\r
+        Rectangle2D rect = source.getBounds();\r
+        return new Rectangle2D.Double(rect.getX() - shadowSizeX, rect.getY() - shadowSizeY, rect.getWidth() + shadowSizeX*2, rect.getHeight() + shadowSizeY*2);\r
+    }\r
+\r
+    private BufferedImage createImage() {\r
+        Rectangle2D origBounds = source.getBounds();\r
+        double width =  size==null?origBounds.getWidth() :size.getX();\r
+        double height = size==null?origBounds.getHeight():size.getY();\r
+        BufferedImage subject = new BufferedImage(\r
+                (int)Math.ceil( width  + shadowSizeX * 2 ),\r
+                (int)Math.ceil( height + shadowSizeY * 2 ),\r
+                BufferedImage.TYPE_INT_ARGB);\r
+\r
+        Graphics2D g = subject.createGraphics();\r
+        g.translate(shadowSizeX, shadowSizeY);\r
+        if (size!=null)\r
+            g.scale(size.getX()/origBounds.getWidth(), size.getY()/origBounds.getHeight());\r
+        g.translate(-origBounds.getMinX(), -origBounds.getMinY());\r
+\r
+        Rectangle2D bounds = new Rectangle2D.Double(0, 0, subject.getWidth(), subject.getHeight());\r
+//        GraphicsContextImpl gc = new GraphicsContextImpl(bounds, null);\r
+//        try {\r
+//             source.paint(gc);\r
+//        } finally {\r
+//             gc.dispose();\r
+//        }\r
+\r
+        g.dispose();\r
+        return subject;\r
+    }\r
+\r
+    private BufferedImage createShadowMask(BufferedImage image) {\r
+        BufferedImage mask = new BufferedImage(image.getWidth(),\r
+                image.getHeight(),\r
+                BufferedImage.TYPE_INT_ARGB);\r
+\r
+        Graphics2D g2d = mask.createGraphics();\r
+        g2d.drawImage(image, 0, 0, null);\r
+        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN,\r
+                (float)shadow.alpha));\r
+        g2d.setColor(shadow.color);\r
+        g2d.fillRect(0, 0, image.getWidth(), image.getHeight());\r
+        g2d.dispose();\r
+\r
+        return mask;\r
+    }\r
+\r
+    public BufferedImage createShadow() {\r
+        BufferedImage i1 = createImage();\r
+        BufferedImage i2 = new BufferedImage(i1.getWidth(), i1.getHeight(), BufferedImage.TYPE_INT_ARGB);\r
+        BufferedImage shadowMask = createShadowMask(i1);\r
+        horiz.filter(shadowMask, i2);\r
+        vert.filter(i2, shadowMask);\r
+        return shadowMask;\r
+    }\r
+\r
+    private ConvolveOp createBlurOp(int width, int height) {\r
+        float[] data = new float[width * height];\r
+        float value = 1.0f / (width * height);\r
+        Arrays.fill(data, value);\r
+        return new ConvolveOp(new Kernel(width, height, data));\r
+    }\r
+\r
+\r
+    @Override\r
+    public Node init(G2DParentNode parent) {\r
+        return null;\r
+//             Graphics2D g = gc.getGraphics2D();\r
+//             BufferedImage bi = createShadow();\r
+//\r
+//     Rectangle2D origBounds = source.getBounds();\r
+//     if (size!=null) {\r
+//                     g.translate(origBounds.getMinX(), origBounds.getMinY());\r
+//                     g.scale(origBounds.getWidth()/size.getX(), origBounds.getHeight()/size.getY());\r
+//                     g.translate(-shadowSizeX, -shadowSizeY);\r
+//                     g.drawImage(bi, 0, 0, null);\r
+//                     g.translate(shadowSizeX, shadowSizeY);\r
+//                     g.scale(size.getX()/origBounds.getWidth(), size.getY()/origBounds.getHeight());\r
+//                     g.translate(-origBounds.getMinX(), -origBounds.getMinY());\r
+//             } else {\r
+//                     g.translate(-shadowSizeX, -shadowSizeY);\r
+//                     g.translate(origBounds.getMinX(), origBounds.getMinY());\r
+//                     g.drawImage(bi, 0, 0, null);\r
+//                     g.translate(shadowSizeX, shadowSizeY);\r
+//                     g.translate(-origBounds.getMinX(), -origBounds.getMinY());\r
+//             }\r
+    }\r
+\r
+    @Override\r
+    public EnumSet<Feature> getFeatures() {\r
+        return feats;\r
+    }\r
+\r
+\r
+}\r