2 * Sixth 3D engine. Author: Svjatoslav Agejenko.
3 * This project is released under Creative Commons Zero (CC0) license.
5 package eu.svjatoslav.sixth.e3d.renderer.raster.texture;
7 import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
10 import java.awt.image.BufferedImage;
11 import java.awt.image.DataBufferByte;
12 import java.awt.image.WritableRaster;
14 public class Texture {
16 public final TextureBitmap primaryBitmap;
17 public final java.awt.Graphics2D graphics;
18 TextureBitmap[] upSampled;
19 TextureBitmap[] downSampled = new TextureBitmap[8];
21 public Texture(final int width, final int height, final int maxUpscale) {
22 upSampled = new TextureBitmap[maxUpscale];
24 final BufferedImage bufferedImage = new BufferedImage(width, height,
25 RenderingContext.bufferedImageType);
27 final WritableRaster raster = bufferedImage.getRaster();
28 final DataBufferByte dbi = (DataBufferByte) raster.getDataBuffer();
29 graphics = (Graphics2D) bufferedImage.getGraphics();
31 graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
32 RenderingHints.VALUE_ANTIALIAS_ON);
34 graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
35 RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
37 primaryBitmap = new TextureBitmap(width, height, dbi.getData(), 1);
40 public int detectDownscaleFactorForZoom(final double zoom) {
42 for (int i = 0; i < downSampled.length; i++) {
48 return downSampled.length - 1;
51 public int detectUpscaleFactorForZoom(final double zoom) {
53 for (int i = 0; i < upSampled.length; i++) {
59 return upSampled.length - 1;
62 public TextureBitmap downscaleBitmap(final TextureBitmap originalBitmap) {
63 int newWidth = originalBitmap.width / 2;
64 int newHeight = originalBitmap.height / 2;
66 // Enforce minimum width and height
72 final TextureBitmap downScaled = new TextureBitmap(newWidth, newHeight,
73 originalBitmap.multiplicationFactor / 2d);
75 final ColorAccumulator accumulator = new ColorAccumulator();
77 for (int y = 0; y < newHeight; y++)
78 for (int x = 0; x < newWidth; x++) {
80 accumulator.accumulate(originalBitmap, x * 2, y * 2);
81 accumulator.accumulate(originalBitmap, (x * 2) + 1, y * 2);
82 accumulator.accumulate(originalBitmap, x * 2, (y * 2) + 1);
84 .accumulate(originalBitmap, (x * 2) + 1, (y * 2) + 1);
85 accumulator.storeResult(downScaled, x, y);
91 public TextureBitmap getDownscaledBitmap(final int scaleFactor) {
92 if (downSampled[scaleFactor] == null) {
94 TextureBitmap largerBitmap;
96 largerBitmap = primaryBitmap;
98 largerBitmap = getDownscaledBitmap(scaleFactor - 1);
100 downSampled[scaleFactor] = downscaleBitmap(largerBitmap);
103 return downSampled[scaleFactor];
106 public TextureBitmap getUpscaledBitmap(final int scaleFactor) {
107 if (upSampled[scaleFactor] == null) {
109 TextureBitmap smallerBitmap;
110 if (scaleFactor == 0)
111 smallerBitmap = primaryBitmap;
113 smallerBitmap = getUpscaledBitmap(scaleFactor - 1);
115 upSampled[scaleFactor] = upscaleBitmap(smallerBitmap);
118 return upSampled[scaleFactor];
121 public TextureBitmap getZoomedBitmap(final double zoomLevel) {
124 final int downscaleFactor = detectDownscaleFactorForZoom(zoomLevel);
125 return getDownscaledBitmap(downscaleFactor);
126 } else if (zoomLevel > 2) {
127 final int upscaleFactor = detectUpscaleFactorForZoom(zoomLevel);
129 if (upscaleFactor < 0)
130 return primaryBitmap;
132 return getUpscaledBitmap(upscaleFactor);
135 // System.out.println(zoomLevel);
136 return primaryBitmap;
139 public void resetResampledBitmapCache() {
140 for (int i = 0; i < upSampled.length; i++)
143 for (int i = 0; i < downSampled.length; i++)
144 downSampled[i] = null;
147 public TextureBitmap upscaleBitmap(final TextureBitmap originalBitmap) {
148 final int newWidth = originalBitmap.width * 2;
149 final int newHeight = originalBitmap.height * 2;
151 final TextureBitmap upScaled = new TextureBitmap(newWidth, newHeight,
152 originalBitmap.multiplicationFactor * 2d);
154 final ColorAccumulator accumulator = new ColorAccumulator();
156 for (int y = 0; y < originalBitmap.height; y++)
157 for (int x = 0; x < originalBitmap.width; x++) {
159 accumulator.accumulate(originalBitmap, x, y);
160 accumulator.storeResult(upScaled, x * 2, y * 2);
163 accumulator.accumulate(originalBitmap, x, y);
164 accumulator.accumulate(originalBitmap, x + 1, y);
165 accumulator.storeResult(upScaled, (x * 2) + 1, y * 2);
168 accumulator.accumulate(originalBitmap, x, y);
169 accumulator.accumulate(originalBitmap, x, y + 1);
170 accumulator.storeResult(upScaled, x * 2, (y * 2) + 1);
173 accumulator.accumulate(originalBitmap, x, y);
174 accumulator.accumulate(originalBitmap, x + 1, y);
175 accumulator.accumulate(originalBitmap, x, y + 1);
176 accumulator.accumulate(originalBitmap, x + 1, y + 1);
177 accumulator.storeResult(upScaled, (x * 2) + 1, (y * 2) + 1);
183 public class ColorAccumulator {
184 public int r, g, b, a;
185 public int pixelCount = 0;
187 public void accumulate(final TextureBitmap bitmap, final int x,
189 int address = bitmap.getAddress(x, y);
191 a += bitmap.bytes[address] & 0xff;
194 b += bitmap.bytes[address] & 0xff;
197 g += bitmap.bytes[address] & 0xff;
200 r += bitmap.bytes[address] & 0xff;
205 public void reset() {
213 public void storeResult(final TextureBitmap bitmap, final int x,
215 int address = bitmap.getAddress(x, y);
217 bitmap.bytes[address] = (byte) (a / pixelCount);
220 bitmap.bytes[address] = (byte) (b / pixelCount);
223 bitmap.bytes[address] = (byte) (g / pixelCount);
226 bitmap.bytes[address] = (byte) (r / pixelCount);