001: /*
002: * Copyright (c) 2005-2008 Substance Kirill Grouchnikov. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of Substance Kirill Grouchnikov nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030: package org.jvnet.substance.painter;
031:
032: import java.awt.*;
033: import java.awt.geom.Point2D;
034: import java.awt.image.*;
035:
036: import org.jvnet.substance.color.ColorScheme;
037: import org.jvnet.substance.utils.SubstanceColorUtilities;
038: import org.jvnet.substance.utils.SubstanceCoreUtilities;
039:
040: /**
041: * Gradient painter that returns images with 3D appearance and specular shine
042: * spot. This class is part of officially supported API.
043: *
044: * @author Kirill Grouchnikov
045: */
046: public class SpecularGradientPainter extends BaseGradientPainter {
047: /*
048: * (non-Javadoc)
049: *
050: * @see org.jvnet.substance.painter.SubstanceGradientPainter#getDisplayName()
051: */
052: public String getDisplayName() {
053: return "Specular";
054: }
055:
056: /*
057: * (non-Javadoc)
058: *
059: * @see org.jvnet.substance.painter.SubstanceGradientPainter#getContourBackground(int,
060: * int, java.awt.Shape, boolean, org.jvnet.substance.color.ColorScheme,
061: * org.jvnet.substance.color.ColorScheme, float, boolean, boolean)
062: */
063: public BufferedImage getContourBackground(int width, int height,
064: Shape contour, boolean isDark, ColorScheme colorScheme1,
065: ColorScheme colorScheme2, float cyclePos, boolean hasShine,
066: boolean useCyclePosAsInterpolation) {
067:
068: BufferedImage mixResult = this .getMixContourBackground(width,
069: height, contour, isDark, colorScheme1, colorScheme2,
070: cyclePos, hasShine, useCyclePosAsInterpolation);
071: if (mixResult != null)
072: return mixResult;
073:
074: // long millis = System.nanoTime();
075:
076: BufferedImage image = SubstanceCoreUtilities.getBlankImage(
077: width, height);
078: Graphics2D graphics = (Graphics2D) image.getGraphics();
079: graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
080: RenderingHints.VALUE_ANTIALIAS_ON);
081:
082: ColorScheme interpolationScheme1 = colorScheme1;
083: ColorScheme interpolationScheme2 = useCyclePosAsInterpolation ? colorScheme2
084: : colorScheme1;
085:
086: double cycleCoef = 1.0 - cyclePos / 10.0;
087:
088: // Color topBorderColor = SubstanceColorUtilities.getTopBorderColor(
089: // interpolationScheme1, interpolationScheme2, cycleCoef);
090: // Color midBorderColor = SubstanceColorUtilities.getMidBorderColor(
091: // interpolationScheme1, interpolationScheme2, cycleCoef);
092: // Color bottomBorderColor = SubstanceColorUtilities.getBottomBorderColor(
093: // interpolationScheme1, interpolationScheme2, cycleCoef);
094: Color topFillColor = SubstanceColorUtilities.getTopFillColor(
095: interpolationScheme1, interpolationScheme2, cycleCoef,
096: useCyclePosAsInterpolation);
097: Color midFillColor = SubstanceColorUtilities.getMidFillColor(
098: interpolationScheme1, interpolationScheme2, cycleCoef,
099: useCyclePosAsInterpolation);
100: Color bottomFillColor = SubstanceColorUtilities
101: .getBottomFillColor(interpolationScheme1,
102: interpolationScheme2, cycleCoef,
103: useCyclePosAsInterpolation);
104: Color topShineColor = SubstanceColorUtilities.getTopShineColor(
105: interpolationScheme1, interpolationScheme2, cycleCoef,
106: useCyclePosAsInterpolation);
107: Color bottomShineColor = SubstanceColorUtilities
108: .getBottomShineColor(interpolationScheme1,
109: interpolationScheme2, cycleCoef,
110: useCyclePosAsInterpolation);
111:
112: graphics.setStroke(new BasicStroke((float) 1.3,
113: BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
114:
115: // Fill background
116: // long millis000 = System.nanoTime();
117: graphics.setClip(contour);
118: GradientPaint gradientTop = new GradientPaint(0, 0,
119: topFillColor, 0, height / 2, midFillColor);
120: graphics.setPaint(gradientTop);
121: graphics.fillRect(0, 0, width, height / 2);
122:
123: GradientPaint gradientBottom = new GradientPaint(0, height / 2,
124: midFillColor, 0, height - 2, bottomFillColor);
125: graphics.setPaint(gradientBottom);
126: graphics.fillRect(0, height / 2, width, height / 2);
127: // long millis001 = System.nanoTime();
128:
129: // long millis003 = 0, millis004 = 0, millis005 = 0;
130:
131: // // Draw border
132: // GradientPaint gradientBorderTop = new GradientPaint(0, 0,
133: // topBorderColor, 0, height / 2, midBorderColor);
134: // graphics.setPaint(gradientBorderTop);
135: // graphics.setClip(0, 0, width, height / 2);
136: // graphics.draw(contour);
137: //
138: // GradientPaint gradientBorderBottom = new GradientPaint(0, height / 2,
139: // midBorderColor, 0, height - 2, bottomBorderColor);
140: // graphics.setPaint(gradientBorderBottom);
141: // graphics.setClip(0, height / 2, width, 1 + height / 2);
142: // graphics.draw(contour);
143:
144: if (hasShine) {
145: graphics.setClip(null);
146: int shineHeight = (int) (height / 1.8);
147:
148: double[][] dists = new double[width][height];
149: ColorModel srcColorModel = image.getColorModel();
150: WritableRaster srcRaster = image.getRaster();
151: int[][] alphas = new int[width][height];
152: for (int x = 0; x < width; x++) {
153: for (int y = 0; y < height; y++) {
154: alphas[x][y] = srcColorModel.getAlpha(srcRaster
155: .getDataElements(x, y, null));
156: dists[x][y] = Math.max(width, height);
157: }
158: }
159:
160: // scan rows
161: for (int y = 0; y < height; y++) {
162: // from left
163: int x = 0;
164: double span = 0;
165: while (x < width) {
166: if (alphas[x][y] == 0) {
167: // transparent pixel
168: span = 0;
169: } else {
170: if ((span == 0) || (alphas[x][y] < 255))
171: span = alphas[x][y] / 255.0;
172: else
173: span += 1.0;
174: }
175: dists[x][y] = Math.min(span, dists[x][y]);
176: x++;
177: }
178: // from right
179: x = width - 1;
180: span = 0;
181: while (x >= 0) {
182: if (alphas[x][y] == 0) {
183: // transparent pixel
184: span = 0;
185: } else {
186: if ((span == 0) || (alphas[x][y] < 255))
187: span = alphas[x][y] / 255.0;
188: else
189: span += 1.0;
190: }
191: dists[x][y] = Math.min(span, dists[x][y]);
192: x--;
193: }
194: }
195:
196: // scan columns
197: for (int x = 0; x < width; x++) {
198: // from top
199: int y = 0;
200: double span = 0;
201: while (y < height) {
202: if (alphas[x][y] == 0) {
203: // transparent pixel
204: span = 0;
205: } else {
206: if ((span == 0) || (alphas[x][y] < 255))
207: span = alphas[x][y] / 255.0;
208: else
209: span += 1.0;
210: }
211: dists[x][y] = Math.min(span, dists[x][y]);
212: y++;
213: }
214: // from bottom
215: y = height - 1;
216: span = 0;
217: while (y >= 0) {
218: if (alphas[x][y] == 0) {
219: // transparent pixel
220: span = 0;
221: } else {
222: if ((span == 0) || (alphas[x][y] < 255))
223: span = alphas[x][y] / 255.0;
224: else
225: span += 1.0;
226: }
227: dists[x][y] = Math.min(span, dists[x][y]);
228: y--;
229: }
230: }
231:
232: for (int y = 0; y < shineHeight; y++) {
233: double coef = (double) y / (double) height;
234: double minDist = (0.8 + height / 20.0)
235: * (1.0 + 3 * coef);
236: double maxDist = (0.8 + height / 20.0)
237: * (1.0 + 6 * coef);
238:
239: double colorCoef = (double) y / (double) shineHeight;
240: int alpha = (int) (255 * (1.0 - 0.1 * colorCoef));
241: alpha = Math.max(alpha, 0);
242:
243: int shineR = (int) (topShineColor.getRed() + colorCoef
244: * (bottomShineColor.getRed() - topShineColor
245: .getRed()));
246: int shineG = (int) (topShineColor.getGreen() + colorCoef
247: * (bottomShineColor.getGreen() - topShineColor
248: .getGreen()));
249: int shineB = (int) (topShineColor.getBlue() + colorCoef
250: * (bottomShineColor.getBlue() - topShineColor
251: .getBlue()));
252:
253: for (int x = 0; x < width; x++) {
254: Point2D p = new Point2D.Double(x + 0.5, y + 0.5);
255: if (!contour.contains(p)) {
256: continue;
257: }
258:
259: double dist = dists[x][y];
260: if (dist <= minDist)
261: continue;
262:
263: double delta = dist - minDist;
264: int dAlpha = alpha;
265: if (delta < 1.0)
266: dAlpha = (int) (delta * dAlpha);
267:
268: if (dist < maxDist) {
269: dAlpha *= (dist - minDist)
270: / (maxDist - minDist);
271: }
272:
273: graphics.setColor(new Color(shineR, shineG, shineB,
274: dAlpha));
275: graphics.drawLine(x, y, x, y);
276: }
277: }
278: }
279:
280: // long millis006 = System.nanoTime();
281:
282: // long millis2 = System.nanoTime();
283: // if (width * height > 5000) {
284: // System.out.println("new - " + width + "*" + height + " = "
285: // + format(millis2 - millis));
286: // System.out.println("\tfill : " + format(millis001 - millis000));
287: // System.out.println("\tcontour : " + format(millis003 - millis001));
288: // System.out.println("\trevert : " + format(millis004 - millis003));
289: // System.out.println("\toverlay : " + format(millis005 - millis004));
290: // System.out.println("\tborder : " + format(millis006 - millis005));
291: // }
292:
293: return image;
294: }
295: }
|