2 * Sixth 3D engine. Author: Svjatoslav Agejenko.
3 * This project is released under Creative Commons Zero (CC0) license.
8 package eu.svjatoslav.sixth.e3d.renderer.raster.texture;
10 import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
13 import java.awt.image.BufferedImage;
14 import java.awt.image.DataBufferByte;
15 import java.awt.image.WritableRaster;
17 public class Texture {
19 public final TextureBitmap primaryBitmap;
20 public final java.awt.Graphics2D graphics;
21 TextureBitmap[] upSampled;
22 TextureBitmap[] downSampled = new TextureBitmap[8];
24 public Texture(final int width, final int height, final int maxUpscale) {
25 upSampled = new TextureBitmap[maxUpscale];
27 final BufferedImage bufferedImage = new BufferedImage(width, height,
28 RenderingContext.bufferedImageType);
30 final WritableRaster raster = bufferedImage.getRaster();
31 final DataBufferByte dbi = (DataBufferByte) raster.getDataBuffer();
32 graphics = (Graphics2D) bufferedImage.getGraphics();
34 graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
35 RenderingHints.VALUE_ANTIALIAS_ON);
37 graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
38 RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
40 primaryBitmap = new TextureBitmap(width, height, dbi.getData(), 1);
43 public int detectDownscaleFactorForZoom(final double zoom) {
45 for (int i = 0; i < downSampled.length; i++) {
51 return downSampled.length - 1;
54 public int detectUpscaleFactorForZoom(final double zoom) {
56 for (int i = 0; i < upSampled.length; i++) {
62 return upSampled.length - 1;
65 public TextureBitmap downscaleBitmap(final TextureBitmap originalBitmap) {
66 int newWidth = originalBitmap.width / 2;
67 int newHeight = originalBitmap.height / 2;
69 // Enforce minimum width and height
75 final TextureBitmap downScaled = new TextureBitmap(newWidth, newHeight,
76 originalBitmap.multiplicationFactor / 2d);
78 final ColorAccumulator accumulator = new ColorAccumulator();
80 for (int y = 0; y < newHeight; y++)
81 for (int x = 0; x < newWidth; x++) {
83 accumulator.accumulate(originalBitmap, x * 2, y * 2);
84 accumulator.accumulate(originalBitmap, (x * 2) + 1, y * 2);
85 accumulator.accumulate(originalBitmap, x * 2, (y * 2) + 1);
87 .accumulate(originalBitmap, (x * 2) + 1, (y * 2) + 1);
88 accumulator.storeResult(downScaled, x, y);
94 public TextureBitmap getDownscaledBitmap(final int scaleFactor) {
95 if (downSampled[scaleFactor] == null) {
97 TextureBitmap largerBitmap;
99 largerBitmap = primaryBitmap;
101 largerBitmap = getDownscaledBitmap(scaleFactor - 1);
103 downSampled[scaleFactor] = downscaleBitmap(largerBitmap);
106 return downSampled[scaleFactor];
109 public TextureBitmap getUpscaledBitmap(final int scaleFactor) {
110 if (upSampled[scaleFactor] == null) {
112 TextureBitmap smallerBitmap;
113 if (scaleFactor == 0)
114 smallerBitmap = primaryBitmap;
116 smallerBitmap = getUpscaledBitmap(scaleFactor - 1);
118 upSampled[scaleFactor] = upscaleBitmap(smallerBitmap);
121 return upSampled[scaleFactor];
124 public TextureBitmap getZoomedBitmap(final double zoomLevel) {
127 final int downscaleFactor = detectDownscaleFactorForZoom(zoomLevel);
128 return getDownscaledBitmap(downscaleFactor);
129 } else if (zoomLevel > 2) {
130 final int upscaleFactor = detectUpscaleFactorForZoom(zoomLevel);
132 if (upscaleFactor < 0)
133 return primaryBitmap;
135 return getUpscaledBitmap(upscaleFactor);
138 // System.out.println(zoomLevel);
139 return primaryBitmap;
142 public void resetResampledBitmapCache() {
143 for (int i = 0; i < upSampled.length; i++)
146 for (int i = 0; i < downSampled.length; i++)
147 downSampled[i] = null;
150 public TextureBitmap upscaleBitmap(final TextureBitmap originalBitmap) {
151 final int newWidth = originalBitmap.width * 2;
152 final int newHeight = originalBitmap.height * 2;
154 final TextureBitmap upScaled = new TextureBitmap(newWidth, newHeight,
155 originalBitmap.multiplicationFactor * 2d);
157 final ColorAccumulator accumulator = new ColorAccumulator();
159 for (int y = 0; y < originalBitmap.height; y++)
160 for (int x = 0; x < originalBitmap.width; x++) {
162 accumulator.accumulate(originalBitmap, x, y);
163 accumulator.storeResult(upScaled, x * 2, y * 2);
166 accumulator.accumulate(originalBitmap, x, y);
167 accumulator.accumulate(originalBitmap, x + 1, y);
168 accumulator.storeResult(upScaled, (x * 2) + 1, y * 2);
171 accumulator.accumulate(originalBitmap, x, y);
172 accumulator.accumulate(originalBitmap, x, y + 1);
173 accumulator.storeResult(upScaled, x * 2, (y * 2) + 1);
176 accumulator.accumulate(originalBitmap, x, y);
177 accumulator.accumulate(originalBitmap, x + 1, y);
178 accumulator.accumulate(originalBitmap, x, y + 1);
179 accumulator.accumulate(originalBitmap, x + 1, y + 1);
180 accumulator.storeResult(upScaled, (x * 2) + 1, (y * 2) + 1);
186 public class ColorAccumulator {
187 public int r, g, b, a;
188 public int pixelCount = 0;
190 public void accumulate(final TextureBitmap bitmap, final int x,
192 int address = bitmap.getAddress(x, y);
194 a += bitmap.bytes[address] & 0xff;
197 b += bitmap.bytes[address] & 0xff;
200 g += bitmap.bytes[address] & 0xff;
203 r += bitmap.bytes[address] & 0xff;
208 public void reset() {
216 public void storeResult(final TextureBitmap bitmap, final int x,
218 int address = bitmap.getAddress(x, y);
220 bitmap.bytes[address] = (byte) (a / pixelCount);
223 bitmap.bytes[address] = (byte) (b / pixelCount);
226 bitmap.bytes[address] = (byte) (g / pixelCount);
229 bitmap.bytes[address] = (byte) (r / pixelCount);