diff --git a/src/main/java/ru/windcorp/optica/client/TestLayer.java b/src/main/java/ru/windcorp/optica/client/TestLayer.java
deleted file mode 100644
index 69e3a57..0000000
--- a/src/main/java/ru/windcorp/optica/client/TestLayer.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*******************************************************************************
- * Optica
- * Copyright (C) 2020 Wind Corporation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *******************************************************************************/
-package ru.windcorp.optica.client;
-
-import org.lwjgl.glfw.GLFW;
-
-import com.google.common.eventbus.Subscribe;
-
-import glm.mat._3.Mat3;
-import glm.mat._4.Mat4;
-import glm.vec._3.Vec3;
-import ru.windcorp.optica.client.graphics.Layer;
-import ru.windcorp.optica.client.graphics.backend.GraphicsBackend;
-import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
-import ru.windcorp.optica.client.graphics.input.KeyEvent;
-import ru.windcorp.optica.client.graphics.input.CursorMoveEvent;
-import ru.windcorp.optica.client.graphics.model.Model;
-import ru.windcorp.optica.client.graphics.model.DynamicModel;
-import ru.windcorp.optica.client.graphics.model.Shapes;
-import ru.windcorp.optica.client.graphics.texture.SimpleTexture;
-import ru.windcorp.optica.client.graphics.texture.Sprite;
-import ru.windcorp.optica.client.graphics.texture.Texture;
-import ru.windcorp.optica.client.graphics.texture.TextureManager;
-import ru.windcorp.optica.client.graphics.world.Camera;
-import ru.windcorp.optica.client.graphics.world.WorldRenderer;
-
-public class TestLayer extends Layer {
-
- private final Model model;
-
- private final Camera camera = new Camera(
- new Vec3(),
- 0, (float) Math.PI,
- (float) Math.toRadians(70)
- );
-
- private final Vec3 velocity = new Vec3();
- private final Vec3 tmp = new Vec3();
-
- private final Mat3 angMat = new Mat3();
-
- private int movementX = 0;
- private int movementY = 0;
- private int movementZ = 0;
-
- public TestLayer() {
- super("Test");
-
- Texture top = qtex("grass_top");
- Texture side = qtex("grass_side");
- Texture bottom = qtex("grass_bottom");
-
- model = new DynamicModel(DynamicModel.builder()
- .addDynamicPart(
- new Shapes.PppBuilder(top, bottom, side, side, side, side)
- .create()
- )
- ) {
- @Override
- protected void getDynamicTransform(int shapeIndex, Mat4 result) {
- result.translate(0, 0, +5);
- }
- };
- }
-
- private Texture qtex(String name) {
- return new SimpleTexture(new Sprite(TextureManager.load(name, false)));
- }
-
- @Override
- protected void initialize() {
- GraphicsInterface.subscribeToInputEvents(this);
- }
-
- private final WorldRenderer renderer = new WorldRenderer();
-
- @Override
- protected void doRender() {
- camera.apply(renderer);
-
- angMat.set().rotateY(-camera.getYaw());
-
- tmp.set(movementX, 0, movementZ);
- angMat.mul_(tmp); // bug in jglm
- tmp.y = movementY;
- tmp.mul(0.1f);
- tmp.sub(velocity);
- tmp.mul(0.1f);
- velocity.add(tmp);
- camera.move(velocity);
-
- model.render(renderer);
-
- renderer.reset();
- }
-
- private boolean flag = true;
-
- @Subscribe
- public void onKeyEvent(KeyEvent event) {
- if (event.isRepeat()) return;
-
- int multiplier = event.isPress() ? 1 : -1;
-
- switch (event.getKey()) {
- case GLFW.GLFW_KEY_W:
- movementZ += -1 * multiplier;
- break;
- case GLFW.GLFW_KEY_S:
- movementZ += +1 * multiplier;
- break;
- case GLFW.GLFW_KEY_A:
- movementX += -1 * multiplier;
- break;
- case GLFW.GLFW_KEY_D:
- movementX += +1 * multiplier;
- break;
- case GLFW.GLFW_KEY_SPACE:
- movementY += +1 * multiplier;
- break;
- case GLFW.GLFW_KEY_LEFT_SHIFT:
- movementY += -1 * multiplier;
- break;
-
- case GLFW.GLFW_KEY_ESCAPE:
- if (!event.isPress()) return;
-
- if (flag) {
- GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL);
- } else {
- GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED);
- }
-
- flag = !flag;
- break;
- }
- }
-
- @Subscribe
- public void onMouseMoved(CursorMoveEvent event) {
- if (!flag) return;
-
- final float yawScale = 0.002f;
- final float pitchScale = yawScale;
-
- camera.turn(
- (float) (event.getChangeY() * pitchScale),
- (float) (event.getChangeX() * yawScale)
- );
- }
-
-}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/texture/Pixels.java b/src/main/java/ru/windcorp/optica/client/graphics/texture/Pixels.java
index 2971afc..9ff3b2f 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/texture/Pixels.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/texture/Pixels.java
@@ -29,24 +29,30 @@ class Pixels {
private final int bufferWidth;
private final int bufferHeight;
- private final boolean filtered;
+ private final TextureSettings settings;
+
+ private final int width;
+ private final int height;
public Pixels(
ByteBuffer data,
int bufferWidth, int bufferHeight,
- boolean filtered
+ int width, int height,
+ TextureSettings settings
) {
this.data = data;
+ this.width = width;
+ this.height = height;
this.bufferWidth = bufferWidth;
this.bufferHeight = bufferHeight;
- this.filtered = filtered;
+ this.settings = settings;
}
public int load() {
int handle = glGenTextures();
glBindTexture(GL_TEXTURE_2D, handle);
- if (filtered) {
+ if (settings.isFiltered()) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
@@ -74,4 +80,28 @@ class Pixels {
return handle;
}
+ public ByteBuffer getData() {
+ return data;
+ }
+
+ public int getBufferWidth() {
+ return bufferWidth;
+ }
+
+ public int getBufferHeight() {
+ return bufferHeight;
+ }
+
+ public int getContentWidth() {
+ return width;
+ }
+
+ public int getContentHeight() {
+ return height;
+ }
+
+ public TextureSettings getSettings() {
+ return settings;
+ }
+
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/texture/PngLoader.java b/src/main/java/ru/windcorp/optica/client/graphics/texture/PngLoader.java
new file mode 100644
index 0000000..0f18d77
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/client/graphics/texture/PngLoader.java
@@ -0,0 +1,109 @@
+package ru.windcorp.optica.client.graphics.texture;
+
+import java.awt.Graphics2D;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Hashtable;
+import javax.imageio.ImageIO;
+import org.lwjgl.BufferUtils;
+
+import ru.windcorp.optica.common.util.BinUtil;
+
+class PngLoader {
+
+ private static final ColorModel COLOR_MODEL = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB), // Use RGB
+ new int[] {8, 8, 8, 8}, // Use every bit
+ true, // Has alpha
+ false, // Not premultiplied
+ ComponentColorModel.TRANSLUCENT, // Can have any alpha
+ DataBuffer.TYPE_BYTE // Alpha is one byte
+ );
+
+ private static final Hashtable, ?> CANVAS_PROPERTIES = new Hashtable<>();
+
+ private static final java.awt.Color CANVAS_BACKGROUND = new java.awt.Color(0, 0, 0, 0);
+
+ public static Pixels loadPngImage(
+ InputStream pngStream,
+ TextureSettings settings
+ ) throws IOException {
+
+ BufferedImage readResult = ImageIO.read(pngStream);
+
+ int width = readResult.getWidth();
+ int height = readResult.getHeight();
+
+ int bufferWidth = BinUtil.roundToGreaterPowerOf2(width);
+ int bufferHeight = BinUtil.roundToGreaterPowerOf2(height);
+
+ WritableRaster raster = createRaster(bufferWidth, bufferHeight);
+
+ BufferedImage canvas = createCanvas(raster);
+
+ Graphics2D g = canvas.createGraphics();
+ try {
+ g.setColor(CANVAS_BACKGROUND);
+ g.fillRect(0, 0, width, height);
+ g.drawImage(
+ readResult,
+ 0, 0, width, height,
+ 0, height, width, 0, // Flip the image
+ null
+ );
+ } finally {
+ g.dispose();
+ }
+
+ return new Pixels(
+ extractBytes(raster),
+ width, height,
+ bufferWidth, bufferHeight,
+ settings
+ );
+ }
+
+ private static WritableRaster createRaster(
+ int bufferWidth,
+ int bufferHeight
+ ) {
+ return Raster.createInterleavedRaster(
+ DataBuffer.TYPE_BYTE, // Storage model
+ bufferWidth, // Buffer width
+ bufferHeight, // Buffer height
+ 4, // RGBA
+ null // Location (here (0; 0))
+ );
+ }
+
+ private static BufferedImage createCanvas(WritableRaster raster) {
+ return new BufferedImage(
+ COLOR_MODEL, // Color model
+ raster, // Backing raster
+ false, // Raster is not premultipied
+ CANVAS_PROPERTIES // Properties
+ );
+ }
+
+ private static ByteBuffer extractBytes(WritableRaster raster) {
+ byte[] data = (
+ (DataBufferByte) raster.getDataBuffer()
+ ).getData();
+
+ ByteBuffer buffer = BufferUtils.createByteBuffer(data.length);
+ buffer.put(data);
+ buffer.flip();
+
+ return buffer;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/texture/TextureManager.java b/src/main/java/ru/windcorp/optica/client/graphics/texture/TextureManager.java
index 419b8e8..e5f7145 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/texture/TextureManager.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/texture/TextureManager.java
@@ -17,128 +17,202 @@
*******************************************************************************/
package ru.windcorp.optica.client.graphics.texture;
-import java.awt.Graphics;
-import java.awt.color.ColorSpace;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.ComponentColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferByte;
-import java.awt.image.Raster;
-import java.awt.image.WritableRaster;
+import java.io.IOException;
+import java.io.InputStream;
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Hashtable;
-import javax.imageio.ImageIO;
+import java.util.HashMap;
+import java.util.Map;
import ru.windcorp.optica.client.graphics.backend.RenderTaskQueue;
import ru.windcorp.optica.common.resource.Resource;
import ru.windcorp.optica.common.resource.ResourceManager;
+import ru.windcorp.optica.common.util.ByteBufferInputStream;
public class TextureManager {
- private static final ColorModel COLOR_MODEL = new ComponentColorModel(
- ColorSpace.getInstance(ColorSpace.CS_sRGB), // Use RGB
- new int[] {8, 8, 8, 8}, // Use every bit
- true, // Has alpha
- false, // Not premultiplied
- ComponentColorModel.TRANSLUCENT, // Can have any alpha
- DataBuffer.TYPE_BYTE // Alpha is one byte
- );
-
- private static final Hashtable, ?> CANVAS_PROPERTIES = new Hashtable<>();
- private static final java.awt.Color CANVAS_BACKGROUND =
- new java.awt.Color(0, 0, 0, 0);
-
private static final String TEXTURE_ASSETS_PREFIX = "assets/textures/";
+ private static final Map LOADED_PIXELS =
+ new HashMap<>();
+
+ private static final Map LOADED_PRIMITIVES =
+ new HashMap<>();
+
+ private static Pixels getCachedPixels(String name) {
+ return LOADED_PIXELS.get(name);
+ }
+
+ private static Pixels getCachedPixels(Resource resource) {
+ return getCachedPixels(resource.getName());
+ }
+
+ private static Pixels cachePixels(Pixels pixels, String name) {
+ LOADED_PIXELS.put(name, pixels);
+ return pixels;
+ }
+
+ private static Pixels cachePixels(Pixels pixels, Resource resource) {
+ return cachePixels(pixels, resource.getName());
+ }
+
+ private static TexturePrimitive getCachedPrimitive(String name) {
+ return LOADED_PRIMITIVES.get(name);
+ }
+
+ private static TexturePrimitive getCachedPrimitive(Resource resource) {
+ return getCachedPrimitive(resource.getName());
+ }
+
+ private static TexturePrimitive cachePrimitive(
+ TexturePrimitive primitive,
+ String name
+ ) {
+ LOADED_PRIMITIVES.put(name, primitive);
+ return primitive;
+ }
+
+ private static TexturePrimitive cachePrimitive(
+ TexturePrimitive primitive,
+ Resource resource
+ ) {
+ return cachePrimitive(primitive, resource.getName());
+ }
+
private static Resource getResource(String textureName) {
return ResourceManager.getResource(
TEXTURE_ASSETS_PREFIX + textureName + ".png"
);
}
- public static TexturePrimitive load(String textureName, boolean filtered) {
- TexturePrimitive result = loadToByteBuffer(textureName, filtered);
- RenderTaskQueue.invokeLater(result::load);
- return result;
- }
-
- public static TexturePrimitive loadToByteBuffer(
- String textureName, boolean filter
+ public static Pixels createOpenGLBuffer(
+ InputStream stream,
+ TextureSettings settings
) {
- Resource resource = getResource(textureName);
-
- BufferedImage source = readImage(resource);
-
- int bufferWidth = toPowerOf2(source.getWidth()),
- bufferHeight = toPowerOf2(source.getHeight());
-
- WritableRaster raster = Raster.createInterleavedRaster(
- DataBuffer.TYPE_BYTE, // Storage model
- bufferWidth, // Buffer width
- bufferHeight, // Buffer height
- 4, // RGBA
- null // Location (here (0; 0))
- );
-
- BufferedImage canvas = new BufferedImage(
- COLOR_MODEL, // Color model
- raster, // Backing raster
- false, // Raster is not premultipied
- CANVAS_PROPERTIES // Properties
- );
-
- Graphics g = canvas.createGraphics();
- g.setColor(CANVAS_BACKGROUND);
- g.fillRect(0, 0, source.getWidth(), source.getHeight());
- g.drawImage(
- source,
- 0, 0, source.getWidth(), source.getHeight(),
- 0, source.getHeight(), source.getWidth(), 0, // Flip the image
- null
- );
- g.dispose();
-
- byte[] data = (
- (DataBufferByte) canvas.getRaster().getDataBuffer()
- ).getData();
-
- ByteBuffer buffer = ByteBuffer.allocateDirect(data.length);
- buffer.order(ByteOrder.nativeOrder());
- buffer.put(data);
- buffer.flip();
-
- Pixels pixels = new Pixels(buffer, bufferWidth, bufferHeight, filter);
-
- TexturePrimitive result = new TexturePrimitive(
- pixels,
- source.getWidth(),
- source.getHeight(),
- bufferWidth,
- bufferHeight
- );
-
- return result;
- }
-
- private static BufferedImage readImage(Resource resource) {
try {
- return ImageIO.read(resource.getInputStream());
- } catch (Exception e) {
- throw new RuntimeException("too bad. refresh project u stupid. must be " + resource.getName(), e);
+ return PngLoader.loadPngImage(stream, settings);
+ } catch (IOException e) {
+ throw new RuntimeException("u stupid. refresh ur project");
}
}
- private static int toPowerOf2(int i) {
-
- // TODO optimize
-
- int result = 1;
- do {
- result *= 2;
- } while (result < i);
+ public static Pixels createOpenGLBuffer(
+ Resource resource,
+ TextureSettings settings
+ ) {
+ Pixels cache = getCachedPixels(resource);
+ if (cache != null) return cache;
+ return cachePixels(
+ createOpenGLBuffer(resource.getInputStream(), settings),
+ resource
+ );
+ }
+
+ public static Pixels createOpenGLBuffer(
+ String textureName,
+ TextureSettings settings
+ ) {
+ Pixels cache = getCachedPixels(textureName);
+ if (cache != null) return cache;
+ return cachePixels(
+ createOpenGLBuffer(getResource(textureName), settings),
+ textureName
+ );
+ }
+
+ public static Pixels createOpenGLBuffer(
+ ByteBuffer bytes,
+ TextureSettings settings
+ ) {
+ bytes.mark();
+ try {
+ return createOpenGLBuffer(
+ new ByteBufferInputStream(bytes), settings
+ );
+ } finally {
+ bytes.reset();
+ }
+ }
+
+ public static TexturePrimitive createTexturePrimitive(
+ InputStream stream,
+ TextureSettings settings
+ ) {
+ Pixels pixels = createOpenGLBuffer(stream, settings);
+ TexturePrimitive result = new TexturePrimitive(pixels);
+ return result;
+ }
+
+ public static TexturePrimitive createTexturePrimitive(
+ Resource resource,
+ TextureSettings settings
+ ) {
+ TexturePrimitive primitive = getCachedPrimitive(resource);
+ if (primitive != null) return primitive;
+ return cachePrimitive(
+ createTexturePrimitive(resource.getInputStream(), settings),
+ resource
+ );
+ }
+
+ public static TexturePrimitive createTexturePrimitive(
+ String textureName,
+ TextureSettings settings
+ ) {
+ TexturePrimitive primitive = getCachedPrimitive(textureName);
+ if (primitive != null) return primitive;
+ return cachePrimitive(
+ createTexturePrimitive(getResource(textureName), settings),
+ textureName
+ );
+ }
+
+ public static TexturePrimitive createTexturePrimitive(
+ ByteBuffer bytes,
+ TextureSettings settings
+ ) {
+ bytes.mark();
+ try {
+ return createTexturePrimitive(
+ new ByteBufferInputStream(bytes), settings
+ );
+ } finally {
+ bytes.reset();
+ }
+ }
+
+ public static TexturePrimitive load(
+ InputStream stream,
+ TextureSettings settings
+ ) {
+ TexturePrimitive result = createTexturePrimitive(stream, settings);
+ if (!result.isLoaded()) RenderTaskQueue.invokeLater(result::load);
return result;
}
+ public static TexturePrimitive load(
+ Resource resource,
+ TextureSettings settings
+ ) {
+ return load(resource.getInputStream(), settings);
+ }
+
+ public static TexturePrimitive load(
+ String textureName,
+ TextureSettings settings
+ ) {
+ return load(getResource(textureName), settings);
+ }
+
+ public static TexturePrimitive load(
+ ByteBuffer bytes,
+ TextureSettings settings
+ ) {
+ bytes.mark();
+ try {
+ return load(new ByteBufferInputStream(bytes), settings);
+ } finally {
+ bytes.reset();
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/texture/TexturePrimitive.java b/src/main/java/ru/windcorp/optica/client/graphics/texture/TexturePrimitive.java
index a2833a4..40c8916 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/texture/TexturePrimitive.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/texture/TexturePrimitive.java
@@ -28,43 +28,28 @@ public class TexturePrimitive implements OpenGLDeletable {
private static final int NOT_LOADED = -1;
private int handle = NOT_LOADED;
- private Pixels pixelsToLoad;
+ private Pixels pixels;
+
+ public TexturePrimitive(Pixels pixels) {
+ this.pixels = pixels;
+ }
- private final int width;
- private final int height;
- private final int bufferWidth;
- private final int bufferHeight;
-
- protected TexturePrimitive(
- Pixels pixels,
- int width, int height,
- int bufferWidth, int bufferHeight
- ) {
- this.pixelsToLoad = pixels;
- this.width = width;
- this.height = height;
- this.bufferWidth = bufferWidth;
- this.bufferHeight = bufferHeight;
-
- OpenGLObjectTracker.register(this);
- }
-
- public int getWidth() {
- return width;
- }
-
- public int getHeight() {
- return height;
- }
-
public int getBufferWidth() {
- return bufferWidth;
+ return pixels.getBufferWidth();
}
public int getBufferHeight() {
- return bufferHeight;
+ return pixels.getBufferHeight();
}
-
+
+ public int getWidth() {
+ return pixels.getContentWidth();
+ }
+
+ public int getHeight() {
+ return pixels.getContentHeight();
+ }
+
public boolean isLoaded() {
return handle != NOT_LOADED;
}
@@ -83,13 +68,12 @@ public class TexturePrimitive implements OpenGLDeletable {
protected void load() {
if (isLoaded()) return;
- handle = pixelsToLoad.load();
+ handle = pixels.load();
+ OpenGLObjectTracker.register(this);
if (handle < 0) {
throw new RuntimeException("oops");
}
-
- pixelsToLoad = null;
}
@Override
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/texture/TextureSettings.java b/src/main/java/ru/windcorp/optica/client/graphics/texture/TextureSettings.java
new file mode 100644
index 0000000..3613cac
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/client/graphics/texture/TextureSettings.java
@@ -0,0 +1,15 @@
+package ru.windcorp.optica.client.graphics.texture;
+
+public class TextureSettings {
+
+ private final boolean isFiltered;
+
+ public TextureSettings(boolean isFiltered) {
+ this.isFiltered = isFiltered;
+ }
+
+ public boolean isFiltered() {
+ return isFiltered;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/optica/client/world/renders/BlockRenders.java b/src/main/java/ru/windcorp/optica/client/world/renders/BlockRenders.java
index d8d58fe..7c1bbca 100644
--- a/src/main/java/ru/windcorp/optica/client/world/renders/BlockRenders.java
+++ b/src/main/java/ru/windcorp/optica/client/world/renders/BlockRenders.java
@@ -24,18 +24,22 @@ import ru.windcorp.optica.client.graphics.texture.SimpleTexture;
import ru.windcorp.optica.client.graphics.texture.Sprite;
import ru.windcorp.optica.client.graphics.texture.Texture;
import ru.windcorp.optica.client.graphics.texture.TextureManager;
+import ru.windcorp.optica.client.graphics.texture.TextureSettings;
import ru.windcorp.optica.client.world.renders.bro.BlockRenderOpaqueCube;
public class BlockRenders {
+ private static final Map BLOCK_RENDERS =
+ new HashMap<>();
+
+ private static final TextureSettings TEXTURE_SETTINGS =
+ new TextureSettings(false);
+
private static Texture grassTop = qtex("grass_top");
private static Texture grassSide = qtex("grass_side");
private static Texture dirtT = qtex("grass_bottom");
private static Texture stoneT = qtex("stone");
private static Texture glassT = qtex("glass_clear");
-
- private static final Map BLOCK_RENDERS =
- new HashMap<>();
private BlockRenders() {}
@@ -59,7 +63,9 @@ public class BlockRenders {
}
private static Texture qtex(String name) {
- return new SimpleTexture(new Sprite(TextureManager.load(name, false)));
+ return new SimpleTexture(new Sprite(
+ TextureManager.load(name, TEXTURE_SETTINGS)
+ ));
}
}
diff --git a/src/main/java/ru/windcorp/optica/common/util/BinUtil.java b/src/main/java/ru/windcorp/optica/common/util/BinUtil.java
new file mode 100644
index 0000000..9c09d89
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/common/util/BinUtil.java
@@ -0,0 +1,18 @@
+package ru.windcorp.optica.common.util;
+
+public class BinUtil {
+
+ public static int closestGreaterPowerOf2(int x) {
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ return x + 1;
+ }
+
+ public static int roundToGreaterPowerOf2(int x) {
+ return closestGreaterPowerOf2(x - 1);
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/optica/common/util/ByteBufferInputStream.java b/src/main/java/ru/windcorp/optica/common/util/ByteBufferInputStream.java
new file mode 100644
index 0000000..42e3c8b
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/common/util/ByteBufferInputStream.java
@@ -0,0 +1,35 @@
+package ru.windcorp.optica.common.util;
+
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * @author Mike
+ * Houston, adapted by Javapony
+ */
+public class ByteBufferInputStream extends InputStream {
+
+ private final ByteBuffer buffer;
+
+ public ByteBufferInputStream(ByteBuffer buffer) {
+ this.buffer = buffer;
+ }
+
+ public int read() {
+ if (!buffer.hasRemaining()) {
+ return -1;
+ }
+ return buffer.get() & 0xFF;
+ }
+
+ public int read(byte[] bytes, int off, int len) {
+ if (!buffer.hasRemaining()) {
+ return -1;
+ }
+
+ len = Math.min(len, buffer.remaining());
+ buffer.get(bytes, off, len);
+ return len;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/ru/windcorp/optica/common/util/ByteBufferOutputStream.java b/src/main/java/ru/windcorp/optica/common/util/ByteBufferOutputStream.java
new file mode 100644
index 0000000..c2237a6
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/common/util/ByteBufferOutputStream.java
@@ -0,0 +1,32 @@
+package ru.windcorp.optica.common.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+public class ByteBufferOutputStream extends OutputStream {
+
+ private final ByteBuffer buffer;
+
+ public ByteBufferOutputStream(ByteBuffer buffer) {
+ this.buffer = buffer;
+ }
+
+ public void write(int b) throws IOException {
+ try {
+ buffer.put((byte) b);
+ } catch (BufferOverflowException e) {
+ throw new IOException(e);
+ }
+ }
+
+ public void write(byte[] bytes, int off, int len) throws IOException {
+ try {
+ buffer.put(bytes, off, len);
+ } catch (BufferOverflowException e) {
+ throw new IOException(e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/ru/windcorp/optica/util/BinUtilTest.java b/src/test/java/ru/windcorp/optica/util/BinUtilTest.java
new file mode 100644
index 0000000..6f648e0
--- /dev/null
+++ b/src/test/java/ru/windcorp/optica/util/BinUtilTest.java
@@ -0,0 +1,58 @@
+package ru.windcorp.optica.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Random;
+
+import org.junit.Test;
+
+import ru.windcorp.optica.common.util.BinUtil;
+
+public class BinUtilTest {
+
+ @Test
+ public void cornerCases() {
+ test(1);
+ test(2);
+ test(3);
+ test(4);
+ test(7);
+ test(8);
+ test(9);
+
+ test(1023);
+ test(1024);
+ test(1025);
+
+ test((1 << 16) - 1);
+ test(1 << 16);
+ test((1 << 16) + 1);
+ }
+
+ @Test
+ public void random() {
+ Random random = new Random(0);
+
+ for (int i = 0; i < 10000; ++i) {
+ test(random.nextInt((1 << 30) - 2) + 1);
+ }
+ }
+
+ void test(int x) {
+ assertEquals("Round, x = " + x, referenceRound(x), BinUtil.roundToGreaterPowerOf2(x));
+ assertEquals("Greater, x = " + x, referenceGreater(x), BinUtil.closestGreaterPowerOf2(x));
+ }
+
+ int referenceGreater(int x) {
+ int p;
+ for (p = 1; p <= x; p *= 2);
+ return p;
+ }
+
+ int referenceRound(int x) {
+ int p;
+ for (p = 1; p < x; p *= 2);
+ return p;
+ }
+
+}