001: /*
002: * $Id: CXForm.java,v 1.3 2002/08/12 21:18:28 skavish Exp $
003: *
004: * ==========================================================================
005: *
006: * The JGenerator Software License, Version 1.0
007: *
008: * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
009: *
010: * Redistribution and use in source and binary forms, with or without
011: * modification, are permitted provided that the following conditions are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution, if
022: * any, must include the following acknowlegement:
023: * "This product includes software developed by Dmitry Skavish
024: * (skavish@usa.net, http://www.flashgap.com/)."
025: * Alternately, this acknowlegement may appear in the software itself,
026: * if and wherever such third-party acknowlegements normally appear.
027: *
028: * 4. The name "The JGenerator" must not be used to endorse or promote
029: * products derived from this software without prior written permission.
030: * For written permission, please contact skavish@usa.net.
031: *
032: * 5. Products derived from this software may not be called "The JGenerator"
033: * nor may "The JGenerator" appear in their names without prior written
034: * permission of Dmitry Skavish.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
040: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: *
049: */
050:
051: package org.openlaszlo.iv.flash.api;
052:
053: import java.io.*;
054: import org.openlaszlo.iv.flash.parser.*;
055: import org.openlaszlo.iv.flash.util.*;
056:
057: /**
058: * Class defines a simple transform that can be applied to the color space of a graphic object.<BR>
059: * There are two types of transform possible:
060: * <P>
061: * 1. Multiplication Transforms<BR>
062: * 2. Addition Transforms<BR>
063: * <P>
064: * Multiplication transforms multiply the red, green, and blue components by an 8.8 fixed-point multiplication term.
065: * The fixed-point representation of 1.0 is 0x100 or 256 decimal.
066: * Therefore, the result of a multiplication operation should be divided by 256.<BR>
067: * <P>
068: * For any color (R,G,B,A) the transformed color (R', G', B', A') is calculated as follows:
069: * <P>
070: * R' = (R * RedMultTerm) / 256<BR>
071: * G' = (G * GreenMultTerm) / 256<BR>
072: * B' = (B * BlueMultTerm) / 256<BR>
073: * A' = (A * AlphaMultTerm) / 256<br>
074: * <P>
075: * Addition transforms simply add an addition term (positive or negative) to the red, green and blue components of
076: * the object being displayed. If the result is greater than 255, the result is clamped to 255.
077: * If the result is less than zero, the result is clamped to zero.
078: * <P>
079: * For any color (R,G,B,A) the transformed color (R', G', B', A') is calculated as follows:
080: * <P>
081: * R' = max(0, min(R + RedAddTerm, 255))<BR>
082: * G' = max(0, min(G + GreenAddTerm, 255))<BR>
083: * B' = max(0, min(B + BlueAddTerm, 255))<BR>
084: * A' = max(0, min(A + AlphaAddTerm, 255))<br>
085: * <P>
086: * Addition and Multiplication transforms can be combined as below.
087: * The multiplication operation is performed first.
088: * <P>
089: * R' = max(0, min(((R * RedMultTerm) / 256) + RedAddTerm, 255))<BR>
090: * G' = max(0, min(((G * GreenMultTerm) / 256) + GreenAddTerm, 255))<BR>
091: * B' = max(0, min(((B * BlueMultTerm) / 256) + BlueAddTerm, 255))<BR>
092: * A' = max(0, min(((A * AlphaMultTerm) / 256) + AlphaAddTerm, 255))<br>
093: *
094: * @author Dmitry Skavish
095: */
096: public final class CXForm extends FlashItem {
097:
098: private int rAdd;
099: private int gAdd;
100: private int bAdd;
101: private int aAdd;
102: private int rMul;
103: private int gMul;
104: private int bMul;
105: private int aMul;
106: private boolean withAlpha;
107:
108: public CXForm() {
109: }
110:
111: /**
112: * Creates color transformation
113: *
114: * @param withAlpha if true creates transformation with alpha
115: */
116: public CXForm(boolean withAlpha) {
117: this .withAlpha = withAlpha;
118: }
119:
120: public int getRedAdd() {
121: return rAdd;
122: }
123:
124: public int getGreenAdd() {
125: return gAdd;
126: }
127:
128: public int getBlueAdd() {
129: return bAdd;
130: }
131:
132: public int getAlphaAdd() {
133: return aAdd;
134: }
135:
136: public int getRedMul() {
137: return rMul;
138: }
139:
140: public int getGreenMul() {
141: return gMul;
142: }
143:
144: public int getBlueMul() {
145: return bMul;
146: }
147:
148: public int getAlphaMul() {
149: return aMul;
150: }
151:
152: public void setRedAdd(int v) {
153: rAdd = v;
154: }
155:
156: public void setGreenAdd(int v) {
157: gAdd = v;
158: }
159:
160: public void setBlueAdd(int v) {
161: bAdd = v;
162: }
163:
164: public void setAlphaAdd(int v) {
165: aAdd = v;
166: }
167:
168: public void setRedMul(int v) {
169: rMul = v;
170: }
171:
172: public void setGreenMul(int v) {
173: gMul = v;
174: }
175:
176: public void setBlueMul(int v) {
177: bMul = v;
178: }
179:
180: public void setAlphaMul(int v) {
181: aMul = v;
182: }
183:
184: public void setWithAlpha(boolean withAlpha) {
185: this .withAlpha = withAlpha;
186: }
187:
188: private boolean hasAdd() {
189: return rAdd != 0 || gAdd != 0 || bAdd != 0 || aAdd != 0;
190: }
191:
192: private boolean hasMul() {
193: return rMul != 256 || gMul != 256 || bMul != 256 || aMul != 256;
194: }
195:
196: /**
197: * Creates transformation which being applied to colors reduces or increases brightness
198: *
199: * @param f value between -1.0 and 1.0<br>
200: * from -1 to 0 - reduce brightness<br>
201: * from 0 to 1 - increase brightness
202: * @param withAlpha if true this transformation will be with alpha
203: * @return new transformation
204: */
205: public static CXForm newBrightness(double f, boolean withAlpha) {
206: CXForm cx = newIdentity(withAlpha);
207: if (f < 0.0) {
208: int ff = (int) ((1.0 + f) * 256.0);
209: cx.setRedMul(ff);
210: cx.setGreenMul(ff);
211: cx.setBlueMul(ff);
212: } else {
213: int ff = (int) (f * 256.0);
214: cx.setRedAdd(ff);
215: cx.setGreenAdd(ff);
216: cx.setBlueAdd(ff);
217: ff = 256 - ff;
218: cx.setRedMul(ff);
219: cx.setGreenMul(ff);
220: cx.setBlueMul(ff);
221: }
222: return cx;
223: }
224:
225: /**
226: * Creates identity transformation (no tranformation at all)
227: *
228: * @param withAlpha if true then create transformation with alpha
229: * @return default transformation
230: */
231: public static CXForm newIdentity(boolean withAlpha) {
232: CXForm cx = new CXForm(withAlpha);
233: cx.initDefault();
234: return cx;
235: }
236:
237: /**
238: * Creates transformation which being to applied to colors sets their alpha to specified value
239: *
240: * @param alpha alpha in range 0..256
241: * @return transformation with specified alpha
242: */
243: public static CXForm newAlpha(int alpha) {
244: CXForm cx = new CXForm(true);
245: cx.initDefault();
246: cx.aMul = alpha;
247: return cx;
248: }
249:
250: private void initDefault() {
251: rMul = gMul = bMul = aMul = 256;
252: rAdd = gAdd = bAdd = aAdd = 0;
253: }
254:
255: /**
256: * Creates linear interpolation of the two specified transformation
257: *
258: * @param t coefficient of the interpolation [0..1]
259: * @param c1 first matrix
260: * @param c2 second matrix
261: * @return interpolation of two specified matrixes
262: */
263: public static CXForm interLinear(double t, CXForm c1, CXForm c2) {
264: double t1 = 1.0 - t;
265: CXForm n = new CXForm();
266: n.withAlpha = c1.withAlpha || c2.withAlpha;
267: n.rAdd = (int) (c1.rAdd * t1 + c2.rAdd * t);
268: n.gAdd = (int) (c1.gAdd * t1 + c2.gAdd * t);
269: n.bAdd = (int) (c1.bAdd * t1 + c2.bAdd * t);
270: n.aAdd = (int) (c1.aAdd * t1 + c2.aAdd * t);
271: n.rMul = (int) (c1.rMul * t1 + c2.rMul * t);
272: n.gMul = (int) (c1.gMul * t1 + c2.gMul * t);
273: n.bMul = (int) (c1.bMul * t1 + c2.bMul * t);
274: n.aMul = (int) (c1.aMul * t1 + c2.aMul * t);
275: return n;
276:
277: }
278:
279: /**
280: * Transforms specified color
281: *
282: * @param color specified color to be transformed
283: * @return new transformed color
284: */
285: public AlphaColor transform(AlphaColor color) {
286: int r = Math.max(0, Math.min(((color.getRed() * rMul) / 256)
287: + rAdd, 255));
288: int g = Math.max(0, Math.min(((color.getGreen() * gMul) / 256)
289: + gAdd, 255));
290: int b = Math.max(0, Math.min(((color.getBlue() * bMul) / 256)
291: + bAdd, 255));
292: int a = Math.max(0, Math.min(((color.getAlpha() * aMul) / 256)
293: + aAdd, 255));
294:
295: return new AlphaColor(r, g, b, a);
296: }
297:
298: /**
299: * Transforms specified color
300: *
301: * @param color specified color to be transformed
302: * @return new transformed color
303: */
304: public Color transform(Color color) {
305: if (color instanceof AlphaColor)
306: return transform((AlphaColor) color);
307:
308: int r = Math.max(0, Math.min(((color.getRed() * rMul) / 256)
309: + rAdd, 255));
310: int g = Math.max(0, Math.min(((color.getGreen() * gMul) / 256)
311: + gAdd, 255));
312: int b = Math.max(0, Math.min(((color.getBlue() * bMul) / 256)
313: + bAdd, 255));
314:
315: return new Color(r, g, b);
316: }
317:
318: public static CXForm parse(Parser p, boolean withAlpha) {
319: p.initBits();
320: CXForm f = new CXForm();
321: f.withAlpha = withAlpha;
322: boolean hasAdd = p.getBool();
323: boolean hasMul = p.getBool();
324: int nBits = p.getBits(4);
325: if (hasMul) {
326: f.rMul = p.getSBits(nBits);
327: f.gMul = p.getSBits(nBits);
328: f.bMul = p.getSBits(nBits);
329: if (withAlpha)
330: f.aMul = p.getSBits(nBits);
331: else
332: f.aMul = 256;
333: } else {
334: f.rMul = f.gMul = f.bMul = f.aMul = 256;
335: }
336: if (hasAdd) {
337: f.rAdd = p.getSBits(nBits);
338: f.gAdd = p.getSBits(nBits);
339: f.bAdd = p.getSBits(nBits);
340: if (withAlpha)
341: f.aAdd = p.getSBits(nBits);
342: else
343: f.aAdd = 0;
344: } else {
345: f.rAdd = f.gAdd = f.bAdd = f.aAdd = 0;
346: }
347: return f;
348: }
349:
350: public void write(FlashOutput fob) {
351: fob.initBits();
352: if (withAlpha)
353: writeWithAlpha(fob);
354: else
355: writeNoAlpha(fob);
356: fob.flushBits();
357: }
358:
359: protected final void writeWithAlpha(FlashOutput fob) {
360: int nBits;
361: boolean hasAdd = hasAdd();
362: boolean hasMul = hasMul();
363: if (hasAdd && hasMul) {
364: int max1 = Util.getMax(rAdd, gAdd, bAdd, aAdd);
365: int max2 = Util.getMax(rMul, gMul, bMul, aMul);
366: nBits = Util.getMinBitsS(Util.getMax(max1, max2));
367: fob.writeBits(0x3, 2);
368: } else if (hasAdd) {
369: nBits = Util.getMinBitsS(Util
370: .getMax(rAdd, gAdd, bAdd, aAdd));
371: fob.writeBits(0x2, 2);
372: } else if (hasMul) {
373: nBits = Util.getMinBitsS(Util
374: .getMax(rMul, gMul, bMul, aMul));
375: fob.writeBits(0x1, 2);
376: } else {
377: nBits = 0;
378: fob.writeBits(0x0, 2);
379: }
380: fob.writeBits(nBits, 4);
381: if (hasMul) {
382: fob.writeBits(rMul, nBits);
383: fob.writeBits(gMul, nBits);
384: fob.writeBits(bMul, nBits);
385: fob.writeBits(aMul, nBits);
386: }
387: if (hasAdd) {
388: fob.writeBits(rAdd, nBits);
389: fob.writeBits(gAdd, nBits);
390: fob.writeBits(bAdd, nBits);
391: fob.writeBits(aAdd, nBits);
392: }
393: }
394:
395: protected final void writeNoAlpha(FlashOutput fob) {
396: int nBits;
397: boolean hasAdd = hasAdd();
398: boolean hasMul = hasMul();
399: if (hasAdd && hasMul) {
400: int max1 = Util.getMax(rAdd, gAdd, bAdd);
401: int max2 = Util.getMax(rMul, gMul, bMul);
402: nBits = Util.getMinBitsS(Util.getMax(max1, max2));
403: fob.writeBits(0x3, 2);
404: } else if (hasAdd) {
405: nBits = Util.getMinBitsS(Util.getMax(rAdd, gAdd, bAdd));
406: fob.writeBits(0x2, 2);
407: } else if (hasMul) {
408: nBits = Util.getMinBitsS(Util.getMax(rMul, gMul, bMul));
409: fob.writeBits(0x1, 2);
410: } else {
411: nBits = 0;
412: fob.writeBits(0x0, 2);
413: }
414: fob.writeBits(nBits, 4);
415: if (hasMul) {
416: fob.writeBits(rMul, nBits);
417: fob.writeBits(gMul, nBits);
418: fob.writeBits(bMul, nBits);
419: }
420: if (hasAdd) {
421: fob.writeBits(rAdd, nBits);
422: fob.writeBits(gAdd, nBits);
423: fob.writeBits(bAdd, nBits);
424: }
425: }
426:
427: public void printContent(PrintStream out, String indent) {
428: out.println(indent + "CXForm: withAlpha=" + withAlpha);
429: out.println(indent + " Add: |0x" + Util.b2h(rAdd) + ",0x"
430: + Util.b2h(gAdd) + ",0x" + Util.b2h(bAdd) + ",0x"
431: + Util.b2h(aAdd) + "|");
432: out.println(indent + " Mul: |0x" + Util.w2h(rMul) + ",0x"
433: + Util.w2h(gMul) + ",0x" + Util.w2h(bMul) + ",0x"
434: + Util.w2h(aMul) + "|");
435: }
436:
437: protected FlashItem copyInto(FlashItem item, ScriptCopier copier) {
438: super .copyInto(item, copier);
439: ((CXForm) item).rAdd = rAdd;
440: ((CXForm) item).gAdd = gAdd;
441: ((CXForm) item).bAdd = bAdd;
442: ((CXForm) item).aAdd = aAdd;
443: ((CXForm) item).rMul = rMul;
444: ((CXForm) item).gMul = gMul;
445: ((CXForm) item).bMul = bMul;
446: ((CXForm) item).aMul = aMul;
447: ((CXForm) item).withAlpha = withAlpha;
448: return item;
449: }
450:
451: public FlashItem getCopy(ScriptCopier copier) {
452: return copyInto(new CXForm(), copier);
453: }
454: }
|