/*
* @(#)ColorCycle.java 1.1 2010-08-03
*
* Copyright (c) 2009-2010 Werner Randelshofer, Goldau, Switzerland.
* All rights reserved.
*
* You may not use, copy or modify this file, except in compliance with the
* license agreement you entered into with Werner Randelshofer.
* For details see accompanying license terms.
*/
package org.monte.media.ilbm;
/**
* Implements CRNG and CCRT color cycling for an IFF ILBM image.
* <p>
* This class supports CRNG and CCRT color cycling as published in
* AMIGA ROM Kernel Reference Manual: Devices,
* Third Edition,
* Addison-Wesley, Reading
* ISBN 0-201-56775-X
*
* <pre>
* //ILBM CRNG Color range cycling
* //--------------------------------------------
*
* #define RNG_NORATE 36 // Dpaint uses this rate to mean non-active
* set {
* active = 1, reverse = 2
* } crngActive;
*
* // A CRange is store in a CRNG chunk.
* typedef struct {
* WORD pad1; // reserved for future use; store 0 here *
* WORD rate; // 60/sec=16384, 30/sec=8192, 1/sec=16384/60=273
* WORD set crngActive flags; // bit0 set = active, bit 1 set = reverse
* UBYTE low; UBYTE high; // lower and upper color registers selected
* } ilbmColorRegisterRangeChunk;
* </pre>
*
* <pre>
* ILBM CCRT Color cycling range and timing
* --------------------------------------------
* /
* enum {
* dontCycle = 0, forward = 1, backwards = -1
* } ccrtDirection;
* typedef struct {
* WORD enum ccrtDirection direction; /* 0=don't cycle, 1=forward, -1=backwards * /
* UBYTE start; /* range lower * /
* UBYTE end; /* range upper * /
* LONG seconds; /* seconds between cycling * /
* LONG microseconds; /* msecs between cycling * /
* WORD pad; /* future exp - store 0 here * /
* } ilbmColorCyclingAndTimingChunk;
*
* </pre>
*
* @author Werner Randelshofer
* @version 1.1 2010-08-03 Added support for blended color cycles.
* <br>1.0.1 2010-11-08 Fixed color cycling rate.
* <br>1.0 2009-12-23 Created.
*/
public class CRNGColorCycle extends ColorCycle {
/** Lowest color register of the range. */
private int low;
/** Highest color register of the range. */
private int high;
/** Whether the color cycle is reverse. */
private boolean isReverse;
/** Whether the image is in EHB mode. */
private boolean isEHB;
public CRNGColorCycle(int rate, int timeScale, int low, int high, boolean isActive, boolean isReverse, boolean isEHB) {
super(rate, timeScale, isActive);
this.low = low;
this.high = high;
this.isReverse = isReverse;
this.isEHB = isEHB;
}
public boolean isReverse() {
return isReverse;
}
public int getLow() {
return low;
}
public int getHigh() {
return high;
}
@Override
public void doCycle(int[] rgbs, long time) {
if (isBlended) {
doBlendedCycle(rgbs, time);
} else {
doHardCycle(rgbs,time);
}
}
public void doBlendedCycle(int[] rgbs, long time) {
if (isActive) {
doHardCycle(rgbs, time);
double blendf = Math.IEEEremainder((time * rate / timeScale / 1000f), high - low + 1);
blendf = blendf - Math.floor(blendf);
int blend = 255-(int)(blendf*255);
if (isReverse) {
{
blend=255-blend;
int tmp = rgbs[high];
for (int i = high; i > low; i--) {
rgbs[i] = ((((rgbs[i]&0xff)*blend+(rgbs[i - 1]&0xff)*(255-blend))>>8)&0xff)
|((((rgbs[i]&0xff00)*blend+(rgbs[i - 1]&0xff00)*(255-blend))>>8)&0xff00)
|((((rgbs[i]&0xff0000)*blend+(rgbs[i - 1]&0xff0000)*(255-blend))>>8)&0xff0000);
}
rgbs[low] = ((((rgbs[low]&0xff)*blend+(tmp&0xff)*(255-blend))>>8)&0xff)
|((((rgbs[low]&0xff00)*blend+(tmp&0xff00)*(255-blend))>>8)&0xff00)
|((((rgbs[low]&0xff0000)*blend+(tmp&0xff0000)*(255-blend))>>8)&0xff0000);;
}
if (isEHB) {
// TO DO
}
} else {
{
int tmp = rgbs[high];
for (int i = high; i > low; i--) {
rgbs[i] = ((((rgbs[i]&0xff)*blend+(rgbs[i - 1]&0xff)*(255-blend))>>8)&0xff)
|((((rgbs[i]&0xff00)*blend+(rgbs[i - 1]&0xff00)*(255-blend))>>8)&0xff00)
|((((rgbs[i]&0xff0000)*blend+(rgbs[i - 1]&0xff0000)*(255-blend))>>8)&0xff0000);
}
rgbs[low] = ((((rgbs[low]&0xff)*blend+(tmp&0xff)*(255-blend))>>8)&0xff)
|((((rgbs[low]&0xff00)*blend+(tmp&0xff00)*(255-blend))>>8)&0xff00)
|((((rgbs[low]&0xff0000)*blend+(tmp&0xff0000)*(255-blend))>>8)&0xff0000);;
}
if (isEHB) {
// TO DO
}
}
}
}
public void doHardCycle(int[] rgbs, long time) {
if (isActive) {
int shift = (int) ((time * rate / timeScale / 1000) % (high - low + 1));
if (isReverse) {
for (int j = 0; j < shift; j++) {
int tmp = rgbs[low];
for (int i = low; i < high; i++) {
rgbs[i] = rgbs[i + 1];
}
rgbs[high] = tmp;
}
if (isEHB) {
for (int j = 0; j < shift; j++) {
int tmp = rgbs[low + 32];
for (int i = low + 32; i < high + 32; i++) {
rgbs[i] = rgbs[i + 1];
}
rgbs[high + 32] = tmp;
}
}
} else {
for (int j = 0; j < shift; j++) {
int tmp = rgbs[high];
for (int i = high; i > low; i--) {
rgbs[i] = rgbs[i - 1];
}
rgbs[low] = tmp;
}
if (isEHB) {
for (int j = 0; j < shift; j++) {
int tmp = rgbs[high + 32];
for (int i = high + 32; i > low + 32; i--) {
rgbs[i] = rgbs[i - 1];
}
rgbs[low + 32] = tmp;
}
}
}
}
}
}