/*
* This file is part of the Haven & Hearth game client.
* Copyright (C) 2009 Fredrik Tolf <fredrik@dolda2000.com>, and
* Björn Johannessen <johannessen.bjorn@gmail.com>
*
* Redistribution and/or modification of this file is subject to the
* terms of the GNU Lesser General Public License, version 3, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Other parts of this source tree adhere to other copying
* rights. Please see the file `COPYING' in the root directory of the
* source tree for details.
*
* A copy the GNU Lesser General Public License is distributed along
* with the source tree of which this file is a part in the file
* `doc/LPGL-3'. If it is missing for any reason, please see the Free
* Software Foundation's website at <http://www.fsf.org/>, or write
* to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package haven;
import java.util.*;
import java.awt.image.*;
public abstract class Mipmapper {
public abstract byte[] gen4(Coord dim, byte[] data, int fmt);
public static abstract class Mipmapper3 extends Mipmapper {
public abstract byte[] gen3(Coord dim, byte[] data, int fmt);
}
public static Coord nextsz(Coord dim) {
Coord ndim = dim.div(2);
ndim.x = Math.max(ndim.x, 1); ndim.y = Math.max(ndim.y, 1);
return(ndim);
}
public static final Mipmapper3 avg = new Mipmapper3() {
public byte[] gen4(Coord dim, byte[] data, int fmt) {
int dst = dim.x * 4;
dim = dim.div(2);
boolean lx = false, ly = false;
if(dim.x < 1) {dim.x = 1; lx = true;}
if(dim.y < 1) {dim.y = 1; ly = true;}
byte[] ndata = new byte[dim.x * dim.y * 4];
int[] r = new int[4], g = new int[4], b = new int[4], a = new int[4];
int na = 0, da = 0;
for(int y = 0; y < dim.y; y++) {
for(int x = 0; x < dim.x; x++) {
r[0] = ((int)data[da + 0]) & 0xff;
g[0] = ((int)data[da + 1]) & 0xff;
b[0] = ((int)data[da + 2]) & 0xff;
a[0] = ((int)data[da + 3]) & 0xff;
if(!lx) {
r[1] = ((int)data[da + 0 + 4]) & 0xff;
g[1] = ((int)data[da + 1 + 4]) & 0xff;
b[1] = ((int)data[da + 2 + 4]) & 0xff;
a[1] = ((int)data[da + 3 + 4]) & 0xff;
} else {
r[1] = r[0]; g[1] = g[0]; b[1] = b[0]; a[1] = a[0];
}
if(!ly) {
r[2] = ((int)data[da + 0 + dst]) & 0xff;
g[2] = ((int)data[da + 1 + dst]) & 0xff;
b[2] = ((int)data[da + 2 + dst]) & 0xff;
a[2] = ((int)data[da + 3 + dst]) & 0xff;
} else {
r[2] = r[0]; g[2] = g[0]; b[2] = b[0]; a[2] = a[0];
}
if(!lx && !ly) {
r[3] = ((int)data[da + 0 + dst + 4]) & 0xff;
g[3] = ((int)data[da + 1 + dst + 4]) & 0xff;
b[3] = ((int)data[da + 2 + dst + 4]) & 0xff;
a[3] = ((int)data[da + 3 + dst + 4]) & 0xff;
} else if(!ly) {
r[3] = r[2]; g[3] = g[2]; b[3] = b[2]; a[3] = a[2];
} else {
r[3] = r[1]; g[3] = g[1]; b[3] = b[1]; a[3] = a[1];
}
int n = 0, cr = 0, cg = 0, cb = 0;
for(int i = 0; i < 4; i++) {
if(a[i] < 128)
continue;
cr += r[i];
cg += g[i];
cb += b[i];
n++;
}
if(n <= 1) {
ndata[na + 3] = 0;
} else {
ndata[na + 0] = (byte)(cr / n);
ndata[na + 1] = (byte)(cg / n);
ndata[na + 2] = (byte)(cb / n);
ndata[na + 3] = (byte)255;
}
na += 4;
da += lx?4:8;
}
da += ly?0:dst;
}
return(ndata);
}
public byte[] gen3(Coord dim, byte[] data, int fmt) {
int dst = dim.x * 3;
dim = dim.div(2);
boolean lx = false, ly = false;
if(dim.x < 1) {dim.x = 1; lx = true;}
if(dim.y < 1) {dim.y = 1; ly = true;}
byte[] ndata = new byte[dim.x * dim.y * 3];
int[] r = new int[4], g = new int[4], b = new int[4];
int na = 0, da = 0;
for(int y = 0; y < dim.y; y++) {
for(int x = 0; x < dim.x; x++) {
r[0] = ((int)data[da + 0]) & 0xff;
g[0] = ((int)data[da + 1]) & 0xff;
b[0] = ((int)data[da + 2]) & 0xff;
if(!lx) {
r[1] = ((int)data[da + 0 + 3]) & 0xff;
g[1] = ((int)data[da + 1 + 3]) & 0xff;
b[1] = ((int)data[da + 2 + 3]) & 0xff;
} else {
r[1] = r[0]; g[1] = g[0]; b[1] = b[0];
}
if(!ly) {
r[2] = ((int)data[da + 0 + dst]) & 0xff;
g[2] = ((int)data[da + 1 + dst]) & 0xff;
b[2] = ((int)data[da + 2 + dst]) & 0xff;
} else {
r[2] = r[0]; g[2] = g[0]; b[2] = b[0];
}
if(!lx && !ly) {
r[3] = ((int)data[da + 0 + dst + 3]) & 0xff;
g[3] = ((int)data[da + 1 + dst + 3]) & 0xff;
b[3] = ((int)data[da + 2 + dst + 3]) & 0xff;
} else if(!ly) {
r[3] = r[2]; g[3] = g[2]; b[3] = b[2];
} else {
r[3] = r[1]; g[3] = g[1]; b[3] = b[1];
}
int cr = 0, cg = 0, cb = 0;
for(int i = 0; i < 4; i++) {
cr += r[i];
cg += g[i];
cb += b[i];
}
ndata[na + 0] = (byte)(cr / 4);
ndata[na + 1] = (byte)(cg / 4);
ndata[na + 2] = (byte)(cb / 4);
na += 3;
da += lx?3:6;
}
da += ly?0:dst;
}
return(ndata);
}
};
public static final Mipmapper rnd = new Mipmapper() {
public byte[] gen4(Coord dim, byte[] data, int fmt) {
Random rnd = new Random();
int dst = dim.x * 4;
dim = dim.div(2);
boolean lx = false, ly = false;
if(dim.x < 1) {dim.x = 1; lx = true;}
if(dim.y < 1) {dim.y = 1; ly = true;}
byte[] ndata = new byte[dim.x * dim.y * 4];
int[] o = new int[4];
o[0] = 0;
o[1] = lx?0:4;
o[2] = ly?0:dst;
o[3] = lx?dst:(ly?4:(dst + 4));
int na = 0, da = 0;
for(int y = 0; y < dim.y; y++) {
for(int x = 0; x < dim.x; x++) {
int so = da + o[rnd.nextInt(4)];
ndata[na + 0] = data[so + 0];
ndata[na + 1] = data[so + 1];
ndata[na + 2] = data[so + 2];
ndata[na + 3] = data[so + 3];
na += 4;
da += lx?4:8;
}
da += ly?0:dst;
}
return(ndata);
}
};
public static final Mipmapper cnt = new Mipmapper() {
public byte[] gen4(Coord dim, byte[] data, int fmt) {
int dst = dim.x * 4;
dim = dim.div(2);
boolean lx = false, ly = false;
if(dim.x < 1) {dim.x = 1; lx = true;}
if(dim.y < 1) {dim.y = 1; ly = true;}
byte[] ndata = new byte[dim.x * dim.y * 4];
int[] r = new int[4], g = new int[4], b = new int[4], a = new int[4];
int na = 0, da = 0;
for(int y = 0; y < dim.y; y++) {
for(int x = 0; x < dim.x; x++) {
r[0] = ((int)data[da + 0]) & 0xff;
g[0] = ((int)data[da + 1]) & 0xff;
b[0] = ((int)data[da + 2]) & 0xff;
a[0] = ((int)data[da + 3]) & 0xff;
if(!lx) {
r[1] = ((int)data[da + 0 + 4]) & 0xff;
g[1] = ((int)data[da + 1 + 4]) & 0xff;
b[1] = ((int)data[da + 2 + 4]) & 0xff;
a[1] = ((int)data[da + 3 + 4]) & 0xff;
} else {
r[1] = r[0]; g[1] = g[0]; b[1] = b[0]; a[1] = a[0];
}
if(!ly) {
r[2] = ((int)data[da + 0 + dst]) & 0xff;
g[2] = ((int)data[da + 1 + dst]) & 0xff;
b[2] = ((int)data[da + 2 + dst]) & 0xff;
a[2] = ((int)data[da + 3 + dst]) & 0xff;
} else {
r[2] = r[0]; g[2] = g[0]; b[2] = b[0]; a[2] = a[0];
}
if(!lx && !ly) {
r[3] = ((int)data[da + 0 + dst + 4]) & 0xff;
g[3] = ((int)data[da + 1 + dst + 4]) & 0xff;
b[3] = ((int)data[da + 2 + dst + 4]) & 0xff;
a[3] = ((int)data[da + 3 + dst + 4]) & 0xff;
} else if(!ly) {
r[3] = r[2]; g[3] = g[2]; b[3] = b[2]; a[3] = a[2];
} else {
r[3] = r[1]; g[3] = g[1]; b[3] = b[1]; a[3] = a[1];
}
int n = 0, cr = 0, cg = 0, cb = 0;
for(int i = 0; i < 4; i++) {
if(a[i] < 128)
continue;
cr += r[i];
cg += g[i];
cb += b[i];
n++;
}
if(n <= 1) {
ndata[na + 3] = 0;
} else {
cr /= n; cg /= n; cb /= n;
int md = -1, mi = -1;
for(int i = 0; i < 4; i++) {
if(a[i] < 128)
continue;
int d = Math.abs(r[i] - cr) + Math.abs(g[i] - cg) + Math.abs(b[i] - cb);
if((md == -1) || (d > md)) {
md = d;
mi = i;
}
}
ndata[na + 0] = (byte)r[mi];
ndata[na + 1] = (byte)g[mi];
ndata[na + 2] = (byte)b[mi];
ndata[na + 3] = (byte)255;
}
na += 4;
da += lx?4:8;
}
da += ly?0:dst;
}
return(ndata);
}
};
public static final Mipmapper dav = new Mipmapper() {
public byte[] gen4(Coord dim, byte[] data, int fmt) {
int dst = dim.x * 4;
dim = dim.div(2);
boolean lx = false, ly = false;
if(dim.x < 1) {dim.x = 1; lx = true;}
if(dim.y < 1) {dim.y = 1; ly = true;}
byte[] ndata = new byte[dim.x * dim.y * 4];
int[] r = new int[4], g = new int[4], b = new int[4], a = new int[4];
int na = 0, da = 0;
for(int y = 0; y < dim.y; y++) {
for(int x = 0; x < dim.x; x++) {
r[0] = ((int)data[da + 0]) & 0xff;
g[0] = ((int)data[da + 1]) & 0xff;
b[0] = ((int)data[da + 2]) & 0xff;
a[0] = ((int)data[da + 3]) & 0xff;
if(!lx) {
r[1] = ((int)data[da + 0 + 4]) & 0xff;
g[1] = ((int)data[da + 1 + 4]) & 0xff;
b[1] = ((int)data[da + 2 + 4]) & 0xff;
a[1] = ((int)data[da + 3 + 4]) & 0xff;
} else {
r[1] = r[0]; g[1] = g[0]; b[1] = b[0]; a[1] = a[0];
}
if(!ly) {
r[2] = ((int)data[da + 0 + dst]) & 0xff;
g[2] = ((int)data[da + 1 + dst]) & 0xff;
b[2] = ((int)data[da + 2 + dst]) & 0xff;
a[2] = ((int)data[da + 3 + dst]) & 0xff;
} else {
r[2] = r[0]; g[2] = g[0]; b[2] = b[0]; a[2] = a[0];
}
if(!lx && !ly) {
r[3] = ((int)data[da + 0 + dst + 4]) & 0xff;
g[3] = ((int)data[da + 1 + dst + 4]) & 0xff;
b[3] = ((int)data[da + 2 + dst + 4]) & 0xff;
a[3] = ((int)data[da + 3 + dst + 4]) & 0xff;
} else if(!ly) {
r[3] = r[2]; g[3] = g[2]; b[3] = b[2]; a[3] = a[2];
} else {
r[3] = r[1]; g[3] = g[1]; b[3] = b[1]; a[3] = a[1];
}
int n = 0, cr = 0, cg = 0, cb = 0;
for(int i = 0; i < 4; i++) {
if(a[i] < 128)
continue;
cr += r[i];
cg += g[i];
cb += b[i];
n++;
}
if(n <= 1) {
ndata[na + 3] = 0;
} else {
cr /= n; cg /= n; cb /= n;
int md = -1, mi = -1;
for(int i = 0; i < 4; i++) {
if(a[i] < 128)
continue;
int d = Math.abs(r[i] - cr) + Math.abs(g[i] - cg) + Math.abs(b[i] - cb);
if((md == -1) || (d < md)) {
md = d;
mi = i;
}
}
ndata[na + 0] = (byte)r[mi];
ndata[na + 1] = (byte)g[mi];
ndata[na + 2] = (byte)b[mi];
ndata[na + 3] = (byte)255;
}
na += 4;
da += lx?4:8;
}
da += ly?0:dst;
}
return(ndata);
}
};
public static final Mipmapper lanczos = new Mipmapper() {
final PUtils.Convolution filter = new PUtils.Lanczos(2);
public byte[] gen4(Coord dim, byte[] data, int fmt) {
BufferedImage img = PUtils.rasterimg(Raster.createInterleavedRaster(new DataBufferByte(data, data.length),
dim.x, dim.y, dim.x * 4, 4, new int[] {0, 1, 2, 3}, null));
dim = nextsz(dim);
BufferedImage sm = PUtils.convolvedown(img, dim, filter);
return(((DataBufferByte)sm.getRaster().getDataBuffer()).getData());
}
};
}