diff --git a/src/main/java/ru/windcorp/optica/client/graphics/Colors.java b/src/main/java/ru/windcorp/optica/client/graphics/Colors.java
index f0927a5..369c7a3 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/Colors.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/Colors.java
@@ -33,6 +33,6 @@ public class Colors {
DEBUG_CYAN = 0x00FFFF,
DEBUG_MAGENTA = 0xFF00FF,
- DEBUG_YELLOW = 0x00FFFF;
+ DEBUG_YELLOW = 0xFFFF00;
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/backend/InputHandler.java b/src/main/java/ru/windcorp/optica/client/graphics/backend/InputHandler.java
index 38e835a..e040df3 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/backend/InputHandler.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/backend/InputHandler.java
@@ -26,18 +26,19 @@ public class InputHandler {
private static final EventBus INPUT_EVENT_BUS = new EventBus("Input");
- // ScrollEvent Start
+ // ScrollEvent
private static class ModifiableWheelScrollEvent extends WheelScrollEvent {
public void initialize(double xoffset, double yoffset) {
- this.xoffset = xoffset;
- this.yoffset = yoffset;
+ this.xOffset = xoffset;
+ this.yOffset = yoffset;
}
}
- private static final ModifiableWheelScrollEvent THE_SCROLL_EVENT = new ModifiableWheelScrollEvent();
+ private static final ModifiableWheelScrollEvent THE_SCROLL_EVENT =
+ new ModifiableWheelScrollEvent();
static void handleMouseWheel(
long window,
@@ -49,7 +50,7 @@ public class InputHandler {
dispatch(THE_SCROLL_EVENT);
}
- // KeyEvent Start
+ // KeyEvent
private static class ModifiableKeyEvent extends KeyEvent {
@@ -62,7 +63,8 @@ public class InputHandler {
}
- private static final ModifiableKeyEvent THE_KEY_EVENT = new ModifiableKeyEvent();
+ private static final ModifiableKeyEvent THE_KEY_EVENT =
+ new ModifiableKeyEvent();
static void handleKeyInput(
long window,
@@ -76,7 +78,7 @@ public class InputHandler {
dispatch(THE_KEY_EVENT);
}
- // CursorEvent Start
+ // CursorMoveEvent
private static class ModifiableCursorMoveEvent extends CursorMoveEvent {
@@ -111,6 +113,8 @@ public class InputHandler {
CURSOR_POSITION.set(x, y);
}
+ // Misc
+
public static double getCursorX() {
return CURSOR_POSITION.x;
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/backend/shaders/CombinedShader.java b/src/main/java/ru/windcorp/optica/client/graphics/backend/shaders/CombinedShader.java
index dcd9571..61ccfb8 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/backend/shaders/CombinedShader.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/backend/shaders/CombinedShader.java
@@ -44,7 +44,7 @@ public class CombinedShader extends Shader {
}
private static String combine(String[] resources) {
- StringBuilder accumulator = new StringBuilder("#version 120\n");
+ StringBuilder accumulator = new StringBuilder("#version 140\n");
for (String resourceName : resources) {
Resource resource = getShaderResource(resourceName);
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/flat/AssembledFlatLayer.java b/src/main/java/ru/windcorp/optica/client/graphics/flat/AssembledFlatLayer.java
index 8085306..f246ee7 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/flat/AssembledFlatLayer.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/flat/AssembledFlatLayer.java
@@ -18,16 +18,16 @@
package ru.windcorp.optica.client.graphics.flat;
import ru.windcorp.optica.client.graphics.Layer;
-import ru.windcorp.optica.client.graphics.model.WorldRenderable;
public abstract class AssembledFlatLayer extends Layer {
- private final FlatRenderHelper helper = new FlatRenderHelper();
+ private final AssembledFlatRenderHelper helper =
+ new AssembledFlatRenderHelper();
private final RenderTarget target = new RenderTarget();
private boolean needsReassembly = true;
- private Clip[] clips = null;
+ private RenderTarget.Clip[] clips = null;
public AssembledFlatLayer(String name) {
super(name);
@@ -57,64 +57,11 @@ public abstract class AssembledFlatLayer extends Layer {
doReassemble();
}
- for (Clip clip : clips) {
+ for (RenderTarget.Clip clip : clips) {
clip.render(helper);
}
helper.reset();
}
- public static class Clip {
-
- private final Mask mask = new Mask();
- private final WorldRenderable renderable;
-
- public Clip(
- int startX, int startY,
- int endX, int endY,
- WorldRenderable renderable
- ) {
- mask.set(startX, startY, endX, endY);
- this.renderable = renderable;
- }
-
- public Clip(
- Mask mask,
- WorldRenderable renderable
- ) {
- this(
- mask.getStartX(), mask.getStartY(),
- mask.getEndX(), mask.getEndY(),
- renderable
- );
- }
-
- public int getStartX() {
- return mask.getStartX();
- }
-
- public int getStartY() {
- return mask.getStartY();
- }
-
- public int getEndX() {
- return mask.getEndX();
- }
-
- public int getEndY() {
- return mask.getEndY();
- }
-
- public WorldRenderable getRenderable() {
- return renderable;
- }
-
- public void render(FlatRenderHelper helper) {
- helper.pushMask(getStartX(), getStartY(), getEndX(), getEndY());
- renderable.render(helper);
- helper.popTransform();
- }
-
- }
-
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/flat/AssembledFlatRenderHelper.java b/src/main/java/ru/windcorp/optica/client/graphics/flat/AssembledFlatRenderHelper.java
new file mode 100644
index 0000000..9763644
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/client/graphics/flat/AssembledFlatRenderHelper.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * 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.graphics.flat;
+
+import java.nio.FloatBuffer;
+
+public class AssembledFlatRenderHelper extends FlatRenderHelper {
+
+ private FloatBuffer masks;
+
+ @Override
+ protected FloatBuffer getMasks() {
+ return masks;
+ }
+
+ public void setMasks(FloatBuffer masks) {
+ this.masks = masks;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/flat/DefaultFlatRenderHelper.java b/src/main/java/ru/windcorp/optica/client/graphics/flat/DefaultFlatRenderHelper.java
new file mode 100644
index 0000000..4749b77
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/client/graphics/flat/DefaultFlatRenderHelper.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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.graphics.flat;
+
+import java.nio.FloatBuffer;
+
+import glm.mat._4.Mat4;
+
+public class DefaultFlatRenderHelper extends FlatRenderHelper {
+
+ private final TransformedMask transformer = new TransformedMask();
+
+ protected final MaskStack maskStack = new MaskStack();
+
+ protected final boolean[] hasMask = new boolean[TRANSFORM_STACK_SIZE];
+
+ public void pushMask(Mask mask, Mat4 transform) {
+ pushMask(transformer.set(mask, transform), transform);
+ }
+
+ public void pushMask(TransformedMask mask, Mat4 transform) {
+ hasMask[transformStack.getSize()] = true;
+ pushTransform().mul(transform);
+ maskStack.pushMask(mask);
+ }
+
+ @Override
+ public Mat4 pushTransform() {
+ hasMask[transformStack.getSize()] = false;
+ return super.pushTransform();
+ }
+
+ @Override
+ public void popTransform() {
+ super.popTransform();
+
+ if (hasMask[transformStack.getSize()]) {
+ maskStack.popMask();
+ }
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ maskStack.clear();
+ }
+
+ @Override
+ protected FloatBuffer getMasks() {
+ return maskStack.getBuffer();
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/flat/FlatRenderHelper.java b/src/main/java/ru/windcorp/optica/client/graphics/flat/FlatRenderHelper.java
index aa2aae0..45f9cc5 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/flat/FlatRenderHelper.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/flat/FlatRenderHelper.java
@@ -17,69 +17,28 @@
*******************************************************************************/
package ru.windcorp.optica.client.graphics.flat;
+import java.nio.FloatBuffer;
+
+import glm.mat._4.Mat4;
import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
import ru.windcorp.optica.client.graphics.model.ShapeRenderHelper;
-public class FlatRenderHelper extends ShapeRenderHelper {
+public abstract class FlatRenderHelper extends ShapeRenderHelper {
- private static final float MAX_DEPTH = 1 << 16;
+ protected static final float MAX_DEPTH = 1 << 16;
- private final Mask mask = new Mask();
+ protected final Mat4 finalTransform = new Mat4();
- {
- setupScreenTransform();
- }
+ protected abstract FloatBuffer getMasks();
- public FlatRenderHelper pushMask(
- int startX, int startY,
- int endX, int endY
- ) {
- mask.set(startX, startY, endX, endY);
- pushTransform().translate(startX, startY, 0);
- return this;
- }
-
- public FlatRenderHelper pushMask(Mask mask) {
- return pushMask(
- mask.getStartX(), mask.getStartY(),
- mask.getEndX(), mask.getEndY()
- );
- }
-
- public int getStartX() {
- return mask.getStartX();
- }
-
- public int getStartY() {
- return mask.getStartY();
- }
-
- public int getEndX() {
- return mask.getEndX();
- }
-
- public int getEndY() {
- return mask.getEndY();
- }
-
- public boolean isRenderable() {
- return !mask.isEmpty();
- }
-
@Override
- public void reset() {
- super.reset();
-
- setupScreenTransform();
- mask.set(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
- }
-
- private void setupScreenTransform() {
+ public Mat4 getFinalTransform() {
float width = GraphicsInterface.getFramebufferWidth();
float height = GraphicsInterface.getFramebufferHeight();
-
- getTransform().translate(-1, +1, 0)
- .scale(2 / width, -2 / height, 1 / MAX_DEPTH);
+
+ return finalTransform.identity().translate(-1, +1, 0)
+ .scale(2 / width, -2 / height, 1 / MAX_DEPTH)
+ .mul(getTransform());
}
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/flat/FlatRenderProgram.java b/src/main/java/ru/windcorp/optica/client/graphics/flat/FlatRenderProgram.java
index 6fdd152..4a41b67 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/flat/FlatRenderProgram.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/flat/FlatRenderProgram.java
@@ -19,10 +19,12 @@ package ru.windcorp.optica.client.graphics.flat;
import static org.lwjgl.opengl.GL11.*;
+import java.nio.FloatBuffer;
+
import com.google.common.collect.ObjectArrays;
-import ru.windcorp.optica.client.graphics.backend.shaders.uniforms.Uniform2Int;
-import ru.windcorp.optica.client.graphics.model.Face;
+import ru.windcorp.optica.client.graphics.backend.shaders.uniforms.Uniform1Int;
+import ru.windcorp.optica.client.graphics.backend.shaders.uniforms.Uniform2Float;
import ru.windcorp.optica.client.graphics.model.Shape;
import ru.windcorp.optica.client.graphics.model.ShapeRenderHelper;
import ru.windcorp.optica.client.graphics.model.ShapeRenderProgram;
@@ -42,17 +44,19 @@ public class FlatRenderProgram extends ShapeRenderProgram {
return def;
}
+ public static final int MASK_STACK_SIZE = 16; // As in Flat.fragment.glsl
+
private static final String FLAT_VERTEX_SHADER_RESOURCE =
"Flat.vertex.glsl";
private static final String FLAT_FRAGMENT_SHADER_RESOURCE =
"Flat.fragment.glsl";
private static final String
- MASK_START_UNIFORM_NAME = "maskStart",
- MASK_END_UNIFORM_NAME = "maskEnd";
+ MASK_COUNT_UNIFORM_NAME = "maskCount",
+ MASKS_UNIFORM_NAME = "masks";
- private final Uniform2Int maskStartUniform;
- private final Uniform2Int maskEndUniform;
+ private final Uniform1Int maskCountUniform;
+ private final Uniform2Float masksUniform;
public FlatRenderProgram(
String[] vertexShaderResources,
@@ -63,8 +67,8 @@ public class FlatRenderProgram extends ShapeRenderProgram {
attachFragmentShader(fragmentShaderResources)
);
- this.maskStartUniform = getUniform(MASK_START_UNIFORM_NAME).as2Int();
- this.maskEndUniform = getUniform(MASK_END_UNIFORM_NAME).as2Int();
+ this.maskCountUniform = getUniform(MASK_COUNT_UNIFORM_NAME).as1Int();
+ this.masksUniform = getUniform(MASKS_UNIFORM_NAME).as2Float();
}
private static String[] attachVertexShader(String[] others) {
@@ -77,15 +81,8 @@ public class FlatRenderProgram extends ShapeRenderProgram {
@Override
public void render(ShapeRenderHelper helper, Shape shape) {
- if (((FlatRenderHelper) helper).isRenderable()) {
- super.render(helper, shape);
- }
- }
-
- @Override
- protected void renderFace(Face face) {
glDisable(GL_CULL_FACE);
- super.renderFace(face);
+ super.render(helper, shape);
glEnable(GL_CULL_FACE);
}
@@ -94,8 +91,29 @@ public class FlatRenderProgram extends ShapeRenderProgram {
super.configure(argHelper);
FlatRenderHelper helper = ((FlatRenderHelper) argHelper);
- maskStartUniform.set(helper.getStartX(), helper.getStartY());
- maskEndUniform.set(helper.getEndX(), helper.getEndY());
+ configureMasks(helper.getMasks());
+ }
+
+ private void configureMasks(FloatBuffer masks) {
+ int pos = masks.position();
+ int limit = masks.limit();
+ int size = pos / TransformedMask.SIZE_IN_FLOATS;
+
+ maskCountUniform.set(size);
+
+ masks.flip();
+ masksUniform.set(masks);
+
+// for (int i = 0; i < pos; ++i) {
+// if (i % TransformedMask.SIZE_IN_FLOATS == 0) {
+// System.out.print(" | ");
+// }
+// System.out.print(masks.get(i) + "; ");
+// }
+// System.out.println();
+
+ masks.limit(limit);
+ masks.position(pos);
}
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/flat/LayerTestUI.java b/src/main/java/ru/windcorp/optica/client/graphics/flat/LayerTestUI.java
index 1afc76e..16d73aa 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/flat/LayerTestUI.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/flat/LayerTestUI.java
@@ -21,14 +21,17 @@ import org.lwjgl.glfw.GLFW;
import com.google.common.eventbus.Subscribe;
+import glm.mat._4.Mat4;
import ru.windcorp.optica.client.graphics.Colors;
import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
import ru.windcorp.optica.client.graphics.input.KeyEvent;
+import ru.windcorp.optica.client.graphics.model.LambdaModel;
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.graphics.world.LayerWorld;
public class LayerTestUI extends AssembledFlatLayer {
@@ -40,37 +43,46 @@ public class LayerTestUI extends AssembledFlatLayer {
private boolean flag = false;
- private static int width = 512 + 256;
- private static final int height = 64;
- private static final int border = 5;
+ private static final int WIDTH = 512 + 256;
+ private static final int HEIGHT = 80;
+ private static final int BORDER = 5;
@Override
protected void assemble(RenderTarget target) {
-
-
final int boxColor = flag ? 0xEE8888 : 0xEEEE88;
final int borderColor = flag ? 0xAA4444 : 0xAAAA44;
final int boxShadowColor = flag ? 0x440000 : 0x444400;
- int x = (getWidth() - width) / 2;
- int y = getHeight() - height;
-
- y -= 2*border;
+ int x = (getWidth() - WIDTH) / 2;
+ int y = getHeight() - HEIGHT - 2*BORDER;
- target.fill(x + border, y + border, width, height, boxShadowColor);
- target.fill(x - 1, y - 1, width + 2, height + 2, boxShadowColor);
- target.fill(x, y, width, height, borderColor);
- target.fill(x + border, y + border, width - 2*border, height - 2*border, boxColor);
+ target.fill(x + BORDER, y + BORDER, WIDTH, HEIGHT, boxShadowColor);
+ target.fill(x - 1, y - 1, WIDTH + 2, HEIGHT + 2, boxShadowColor);
+ target.fill(x, y, WIDTH, HEIGHT, borderColor);
+ target.fill(x + BORDER, y + BORDER, WIDTH - 2*BORDER, HEIGHT - 2*BORDER, boxColor);
final int texShadow = 2;
- final int texSize = height - 4*border;
+ final int texSize = HEIGHT - 4*BORDER;
- target.fill(x + 2*border + texShadow, y + 2*border + texShadow, texSize, texSize, Colors.BLACK);
- target.drawTexture(x + 2*border, y + 2*border, texSize, texSize, qtex("compass"));
+ target.pushTransform(new Mat4().identity().translate(x + 2*BORDER, y + 2*BORDER, 0));
+
+ final Texture compassBg = qtex("compass_icon");
+ final Texture compassFg = qtex("compass_icon_arrow");
+
+ target.drawTexture(texShadow, texShadow, texSize, texSize, Colors.BLACK, compassBg);
+ target.drawTexture(0, 0, texSize, texSize, compassBg);
+
+ target.addCustomRenderer(new LambdaModel(LambdaModel.lambdaBuilder()
+ .addDynamicPart(
+ target.createRectagle(0, 0, texSize, texSize, 0xFFFFFF, compassFg),
+ mat -> mat.translate(texSize/2, texSize/2, 0).rotateZ(-LayerWorld.tmp_the_camera.getYaw()).translate(-texSize/2, -texSize/2, 0)
+ )
+ ));
+ target.popTransform();
drawCross(target);
}
-
+
private void drawCross(RenderTarget target) {
int cx = getWidth() / 2;
int cy = getHeight() / 2;
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/flat/Mask.java b/src/main/java/ru/windcorp/optica/client/graphics/flat/Mask.java
index c959b62..1295a4d 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/flat/Mask.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/flat/Mask.java
@@ -65,6 +65,14 @@ public class Mask {
this.endY = endY;
}
+ public int getWidth() {
+ return getEndX() - getStartX();
+ }
+
+ public int getHeight() {
+ return getEndY() - getStartY();
+ }
+
public void set(int startX, int startY, int endX, int endY) {
this.startX = startX;
this.startY = startY;
@@ -72,8 +80,14 @@ public class Mask {
this.endY = endY;
}
- public boolean isEmpty() {
- return startX >= endX || startY >= endY;
+ public void set(Mask copyFrom) {
+ set(copyFrom.startX, copyFrom.startY, copyFrom.endX, copyFrom.endY);
+ }
+
+ @Override
+ public String toString() {
+ return "(" + getStartX() + "; " + getStartY() +
+ ") -> (" + getEndX() + "; " + getEndY() + ")";
}
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/flat/MaskStack.java b/src/main/java/ru/windcorp/optica/client/graphics/flat/MaskStack.java
new file mode 100644
index 0000000..e0c9dcf
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/client/graphics/flat/MaskStack.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * 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.graphics.flat;
+
+import java.nio.FloatBuffer;
+
+import org.lwjgl.BufferUtils;
+
+public class MaskStack {
+
+ private final FloatBuffer buffer = BufferUtils.createFloatBuffer(
+ FlatRenderProgram.MASK_STACK_SIZE * TransformedMask.SIZE_IN_FLOATS
+ );
+
+ public void pushMask(TransformedMask mask) {
+ mask.writeToBuffer(buffer);
+ }
+
+ public void popMask() {
+ buffer.position(buffer.position() - TransformedMask.SIZE_IN_FLOATS);
+ }
+
+ public void clear() {
+ buffer.clear();
+ }
+
+ FloatBuffer getBuffer() {
+ return buffer;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/flat/RenderTarget.java b/src/main/java/ru/windcorp/optica/client/graphics/flat/RenderTarget.java
index fc55ca6..e087a18 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/flat/RenderTarget.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/flat/RenderTarget.java
@@ -21,7 +21,9 @@ import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
+import glm.mat._4.Mat4;
import glm.vec._3.Vec3;
import ru.windcorp.optica.client.graphics.Colors;
import ru.windcorp.optica.client.graphics.backend.Usage;
@@ -33,10 +35,53 @@ import ru.windcorp.optica.client.graphics.texture.Texture;
public class RenderTarget {
- private final List assembled = new ArrayList<>();
+ private static final Mat4 IDENTITY = new Mat4().identity();
- private final Deque maskStack = new LinkedList<>();
+ public static class Clip {
+
+ private final MaskStack masks = new MaskStack();
+ private final Mat4 transform;
+ private final WorldRenderable renderable;
+ public Clip(
+ Iterable masks,
+ Mat4 transform,
+ WorldRenderable renderable
+ ) {
+ for (TransformedMask mask : masks) {
+ this.masks.pushMask(mask);
+ }
+
+ this.transform = transform == null ? IDENTITY : transform;
+ this.renderable = Objects.requireNonNull(renderable, "renderable");
+ }
+
+ public Mat4 getTransform() {
+ return transform;
+ }
+
+ public WorldRenderable getRenderable() {
+ return renderable;
+ }
+
+ public void render(AssembledFlatRenderHelper helper) {
+ helper.setMasks(masks.getBuffer());
+ helper.pushTransform().mul(getTransform());
+
+ try {
+ getRenderable().render(helper);
+ } finally {
+ helper.popTransform();
+ helper.setMasks(null);
+ }
+ }
+
+ }
+
+ private final List assembled = new ArrayList<>();
+
+ private final Deque maskStack = new LinkedList<>();
+ private final Deque transformStack = new LinkedList<>();
private final List currentClipFaces = new ArrayList<>();
private int depth = 0;
@@ -45,20 +90,55 @@ public class RenderTarget {
reset();
}
- public void pushMaskStartEnd(int startX, int startY, int endX, int endY) {
- assembleCurrentClipFromFaces();
- maskStack.push(intersect(getMask(), startX, startY, endX, endY));
+ protected void assembleCurrentClipFromFaces() {
+ if (!currentClipFaces.isEmpty()) {
+ Face[] faces = currentClipFaces.toArray(
+ new Face[currentClipFaces.size()]
+ );
+ currentClipFaces.clear();
+
+ Shape shape = new Shape(
+ Usage.STATIC, FlatRenderProgram.getDefault(), faces
+ );
+
+ assembled.add(new Clip(
+ maskStack, getTransform(), shape
+ ));
+ }
}
- private Mask intersect(
- Mask current,
- int startX, int startY, int endX, int endY
- ) {
- return new Mask(
- Math.max(startX, current.getStartX()),
- Math.max(startY, current.getStartY()),
- Math.min(endX, current.getEndX()),
- Math.min(endY, current.getEndY())
+ public Clip[] assemble() {
+ assembleCurrentClipFromFaces();
+
+ Clip[] result = assembled.toArray(
+ new Clip[assembled.size()]
+ );
+
+ reset();
+
+ return result;
+ }
+
+ private void reset() {
+ maskStack.clear();
+ transformStack.clear();
+ currentClipFaces.clear();
+ assembled.clear();
+
+ transformStack.add(new Mat4().identity());
+ depth = 0;
+ }
+
+ public void pushMaskStartEnd(int startX, int startY, int endX, int endY) {
+ assembleCurrentClipFromFaces();
+
+ pushTransform(new Mat4().identity().translate(startX, startY, 0));
+
+ maskStack.push(
+ new TransformedMask(
+ new Mask(startX, startY, endX, endY),
+ getTransform()
+ )
);
}
@@ -76,64 +156,32 @@ public class RenderTarget {
public void popMask() {
assembleCurrentClipFromFaces();
maskStack.pop();
+ popTransform();
}
- public Mask getMask() {
+ public TransformedMask getMask() {
return maskStack.getFirst();
}
- protected void assembleCurrentClipFromFaces() {
- if (!currentClipFaces.isEmpty()) {
-
- Mask mask = getMask();
- if (mask.isEmpty()) {
- currentClipFaces.clear();
- return;
- }
-
- Face[] faces = currentClipFaces.toArray(
- new Face[currentClipFaces.size()]
- );
- currentClipFaces.clear();
-
- Shape shape = new Shape(
- Usage.STATIC, FlatRenderProgram.getDefault(), faces
- );
-
- assembled.add(new AssembledFlatLayer.Clip(mask, shape));
- }
- }
-
- public AssembledFlatLayer.Clip[] assemble() {
+ public void pushTransform(Mat4 transform) {
assembleCurrentClipFromFaces();
-
- AssembledFlatLayer.Clip[] result = assembled.toArray(
- new AssembledFlatLayer.Clip[assembled.size()]
- );
-
- reset();
-
- return result;
+ transformStack.push(getTransform().mul(transform, transform));
}
- private void reset() {
- maskStack.clear();
- currentClipFaces.clear();
- assembled.clear();
-
- maskStack.add(new Mask(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE));
- depth = 0;
+ public void popTransform() {
+ assembleCurrentClipFromFaces();
+ transformStack.pop();
+ }
+
+ public Mat4 getTransform() {
+ return transformStack.getFirst();
}
public void addCustomRenderer(WorldRenderable renderable) {
assembleCurrentClipFromFaces();
-
- Mask mask = getMask();
- if (mask.isEmpty()) {
- return;
- }
-
- assembled.add(new AssembledFlatLayer.Clip(mask, renderable));
+ assembled.add(new Clip(
+ maskStack, getTransform(), renderable
+ ));
}
protected void addFaceToCurrentClip(Face face) {
@@ -144,16 +192,9 @@ public class RenderTarget {
int x, int y, int width, int height,
int color, Texture texture
) {
- float depth = this.depth--;
-
- addFaceToCurrentClip(Faces.createRectangle(
- FlatRenderProgram.getDefault(),
- texture,
- createVectorFromRGBInt(color),
- new Vec3(x, y + height, depth), // Flip
- new Vec3(width, 0, 0),
- new Vec3(0, -height, 0)
- ));
+ addFaceToCurrentClip(
+ createRectagleFace(x, y, width, height, color, texture)
+ );
}
public void drawTexture(
@@ -170,6 +211,38 @@ public class RenderTarget {
drawTexture(x, y, width, height, color, null);
}
+ public void fill(int color) {
+ fill(
+ Integer.MIN_VALUE / 2, Integer.MIN_VALUE / 2,
+ Integer.MAX_VALUE, Integer.MAX_VALUE,
+ color
+ );
+ }
+
+ public Face createRectagleFace(
+ int x, int y, int width, int height, int color, Texture texture
+ ) {
+ float depth = this.depth--;
+
+ return Faces.createRectangle(
+ FlatRenderProgram.getDefault(),
+ texture,
+ createVectorFromRGBInt(color),
+ new Vec3(x, y + height, depth), // Flip
+ new Vec3(width, 0, 0),
+ new Vec3(0, -height, 0)
+ );
+ }
+
+ public Shape createRectagle(
+ int x, int y, int width, int height, int color, Texture texture
+ ) {
+ return new Shape(
+ Usage.STATIC, FlatRenderProgram.getDefault(),
+ createRectagleFace(x, y, width, height, color, texture)
+ );
+ }
+
private static Vec3 createVectorFromRGBInt(int rgb) {
int r = (rgb & 0xFF0000) >> 16;
int g = (rgb & 0x00FF00) >> 8;
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/flat/TransformedMask.java b/src/main/java/ru/windcorp/optica/client/graphics/flat/TransformedMask.java
new file mode 100644
index 0000000..829191b
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/client/graphics/flat/TransformedMask.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * 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.graphics.flat;
+
+import java.nio.FloatBuffer;
+
+import glm.mat._4.Mat4;
+import glm.vec._2.Vec2;
+import glm.vec._4.Vec4;
+import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
+
+public class TransformedMask {
+
+ public static final int SIZE_IN_FLOATS = 2 * 3 * 2;
+
+ private final Vec2 origin = new Vec2();
+ private final Vec2 width = new Vec2();
+ private final Vec2 height = new Vec2();
+
+ private final Vec2 counterOrigin = new Vec2();
+ private final Vec2 counterWidth = new Vec2();
+ private final Vec2 counterHeight = new Vec2();
+
+ // Temporary values, objects cached for efficiency
+ private Vec4 startXstartY = null;
+ private Vec4 startXendY = null;
+ private Vec4 endXstartY = null;
+ private Vec4 endXendY = null;
+
+ public TransformedMask(
+ Vec2 origin, Vec2 width, Vec2 height,
+ Vec2 counterOrigin, Vec2 counterWidth, Vec2 counterHeight
+ ) {
+ set(origin, width, height, counterOrigin, counterWidth, counterHeight);
+ }
+
+ public TransformedMask(Mask mask, Mat4 transform) {
+ set(mask, transform);
+ }
+
+ public TransformedMask() {
+ // Do nothing
+ }
+
+ public TransformedMask set(
+ Vec2 origin, Vec2 width, Vec2 height,
+ Vec2 counterOrigin, Vec2 counterWidth, Vec2 counterHeight
+ ) {
+ this.origin.set(origin.x, origin.y);
+ this.width.set(width.x, width.y);
+ this.height.set(height.x, height.y);
+ this.counterOrigin.set(counterOrigin.x, counterOrigin.y);
+ this.counterWidth.set(counterWidth.x, counterWidth.y);
+ this.counterHeight.set(counterHeight.x, counterHeight.y);
+
+ return this;
+ }
+
+ public TransformedMask set(Mask mask, Mat4 transform) {
+ applyTransform(mask, transform);
+ setFields();
+ return this;
+ }
+
+ private void applyTransform(Mask mask, Mat4 transform) {
+ ensureTemporaryVariablesExist();
+
+ int relX = mask.getWidth();
+ int relY = mask.getHeight();
+
+ startXstartY.set( 0, 0, 0, 1);
+ startXendY .set( 0, relY, 0, 1);
+ endXstartY .set(relX, 0, 0, 1);
+ endXendY .set(relX, relY, 0, 1);
+
+ transform.mul(startXstartY);
+ transform.mul(startXendY);
+ transform.mul(endXstartY);
+ transform.mul(endXendY);
+
+ flipY();
+ }
+
+ private void ensureTemporaryVariablesExist() {
+ if (startXstartY == null) {
+ startXstartY = new Vec4();
+ startXendY = new Vec4();
+ endXstartY = new Vec4();
+ endXendY = new Vec4();
+ }
+ }
+
+ private void flipY() {
+ float height = GraphicsInterface.getFramebufferHeight();
+
+ startXstartY.y = height - startXstartY.y;
+ startXendY.y = height - startXendY.y;
+ endXstartY.y = height - endXstartY.y;
+ endXendY.y = height - endXendY.y;
+ }
+
+ private void setFields() {
+ origin.set(
+ startXstartY.x,
+ startXstartY.y
+ );
+
+ width.set(
+ endXstartY.x - startXstartY.x,
+ endXstartY.y - startXstartY.y
+ );
+
+ height.set(
+ startXendY.x - startXstartY.x,
+ startXendY.y - startXstartY.y
+ );
+
+ counterOrigin.set(
+ endXendY.x,
+ endXendY.y
+ );
+
+ counterWidth.set(
+ startXendY.x - endXendY.x,
+ startXendY.y - endXendY.y
+ );
+
+ counterHeight.set(
+ endXstartY.x - endXendY.x,
+ endXstartY.y - endXendY.y
+ );
+ }
+
+ public void writeToBuffer(FloatBuffer output) {
+ output.put(origin.x).put(origin.y);
+ output.put(width.x).put(width.y);
+ output.put(height.x).put(height.y);
+ output.put(counterOrigin.x).put(counterOrigin.y);
+ output.put(counterWidth.x).put(counterWidth.y);
+ output.put(counterHeight.x).put(counterHeight.y);
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/input/WheelEvent.java b/src/main/java/ru/windcorp/optica/client/graphics/input/WheelEvent.java
index f21b088..41c1aae 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/input/WheelEvent.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/input/WheelEvent.java
@@ -1,7 +1,25 @@
+/*******************************************************************************
+ * 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.graphics.input;
public abstract class WheelEvent extends InputEvent {
@Override
public abstract WheelEvent snapshot();
+
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/input/WheelScrollEvent.java b/src/main/java/ru/windcorp/optica/client/graphics/input/WheelScrollEvent.java
index f8c36b9..2b0f1b8 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/input/WheelScrollEvent.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/input/WheelScrollEvent.java
@@ -1,51 +1,86 @@
+/*******************************************************************************
+ * 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.graphics.input;
-import glm.vec._2.d.Vec2d;
-
public class WheelScrollEvent extends WheelEvent {
- protected double xoffset;
- protected double yoffset;
+ protected double xOffset;
+ protected double yOffset;
- protected WheelScrollEvent(double xoffset, double yoffset) {
- this.xoffset = xoffset;
- this.yoffset = yoffset;
+ protected WheelScrollEvent(double xOffset, double yOffset) {
+ this.xOffset = xOffset;
+ this.yOffset = yOffset;
}
protected WheelScrollEvent() {}
- public boolean isUp() { return yoffset > 0; }
+ public boolean isUp() {
+ return yOffset > 0;
+ }
- public boolean isDown() { return yoffset < 0; }
+ public boolean isDown() {
+ return yOffset < 0;
+ }
- public boolean isRight() { return xoffset > 0; }
+ public boolean isRight() {
+ return xOffset > 0;
+ }
- public boolean isLeft() { return xoffset < 0; }
+ public boolean isLeft() {
+ return xOffset < 0;
+ }
- public boolean hasVerticalMovement() { return yoffset != 0; }
+ public boolean hasVerticalMovement() {
+ return yOffset != 0;
+ }
- public boolean hasHorizontalMovement() { return xoffset != 0; }
+ public boolean hasHorizontalMovement() {
+ return xOffset != 0;
+ }
- public double getX() { return xoffset; }
+ public double getX() {
+ return xOffset;
+ }
- public double getY() { return yoffset; }
+ public double getY() {
+ return yOffset;
+ }
@Override
public WheelEvent snapshot() {
- return new StaticWheelScrollEvent(xoffset, yoffset, getTime());
+ return new StaticWheelScrollEvent(xOffset, yOffset, getTime());
}
private class StaticWheelScrollEvent extends WheelScrollEvent {
private final double time;
- public StaticWheelScrollEvent(double xoffset, double yoffset, double time) {
- super(xoffset, yoffset);
+ public StaticWheelScrollEvent(
+ double xOffset, double yOffset, double time
+ ) {
+ super(xOffset, yOffset);
this.time = time;
}
@Override
- public double getTime() { return time; }
+ public double getTime() {
+ return time;
+ }
@Override
public WheelEvent snapshot() {
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/model/LambdaModel.java b/src/main/java/ru/windcorp/optica/client/graphics/model/LambdaModel.java
new file mode 100644
index 0000000..4c946dd
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/client/graphics/model/LambdaModel.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * 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.graphics.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import com.google.common.primitives.Booleans;
+
+import glm.mat._4.Mat4;
+
+public class LambdaModel extends DynamicModel {
+
+ private static final Mat4 IDENTITY = new Mat4();
+
+ @FunctionalInterface
+ public static interface TransformGetter {
+ void transform(Mat4 result);
+ }
+
+ private final TransformGetter[] getters;
+
+ public LambdaModel(
+ WorldRenderable[] parts,
+ Mat4[] transforms,
+ boolean[] dynamic,
+ TransformGetter[] getters
+ ) {
+ super(parts, transforms, dynamic);
+ this.getters = getters;
+ }
+
+ public LambdaModel(Builder builder) {
+ this(
+ builder.getParts(), builder.getTransforms(),
+ builder.getDynamics(), builder.getGetters()
+ );
+ }
+
+ @Override
+ protected void getDynamicTransform(int shapeIndex, Mat4 result) {
+ getters[shapeIndex].transform(result);
+ }
+
+ public static Builder lambdaBuilder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private final List parts = new ArrayList<>();
+ private final List transforms = new ArrayList<>();
+ private final List dynamics = new ArrayList<>();
+ private final List getters = new ArrayList<>();
+
+ protected Builder() {}
+
+ private Builder addPart(
+ WorldRenderable part,
+ Mat4 transform,
+ TransformGetter getter
+ ) {
+ parts.add(Objects.requireNonNull(part, "part"));
+ transforms.add(Objects.requireNonNull(transform, "transform"));
+ dynamics.add(getter != null);
+ getters.add(getter);
+
+ return this;
+ }
+
+ public Builder addStaticPart(
+ WorldRenderable part,
+ Mat4 transform
+ ) {
+ return addPart(part, new Mat4(transform), null);
+ }
+
+ public Builder addDynamicPart(
+ WorldRenderable part,
+ TransformGetter getter
+ ) {
+ return addPart(part, new Mat4(), getter);
+ }
+
+ public Builder addStaticPart(
+ WorldRenderable part
+ ) {
+ return addStaticPart(part, IDENTITY);
+ }
+
+ private WorldRenderable[] getParts() {
+ return parts.toArray(new WorldRenderable[parts.size()]);
+ }
+
+ private Mat4[] getTransforms() {
+ return transforms.toArray(new Mat4[transforms.size()]);
+ }
+
+ private boolean[] getDynamics() {
+ return Booleans.toArray(dynamics);
+ }
+
+ private TransformGetter[] getGetters() {
+ return getters.toArray(new TransformGetter[getters.size()]);
+ }
+
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/model/ShapeRenderHelper.java b/src/main/java/ru/windcorp/optica/client/graphics/model/ShapeRenderHelper.java
index b3b2641..8c691f3 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/model/ShapeRenderHelper.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/model/ShapeRenderHelper.java
@@ -24,7 +24,7 @@ public class ShapeRenderHelper {
protected static final int TRANSFORM_STACK_SIZE = 64;
- private final StashingStack transformStack = new StashingStack<>(
+ protected final StashingStack transformStack = new StashingStack<>(
TRANSFORM_STACK_SIZE, Mat4::new
);
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/world/LayerWorld.java b/src/main/java/ru/windcorp/optica/client/graphics/world/LayerWorld.java
index 59d5bad..7e42272 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/world/LayerWorld.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/world/LayerWorld.java
@@ -35,6 +35,8 @@ import ru.windcorp.optica.common.world.WorldData;
public class LayerWorld extends Layer {
+ public static Camera tmp_the_camera;
+
private final Camera camera = new Camera(
new Vec3(8, 8, 8),
0, 0,
@@ -59,6 +61,7 @@ public class LayerWorld extends Layer {
public LayerWorld() {
super("World");
+ tmp_the_camera = camera;
}
@Override
diff --git a/src/main/java/ru/windcorp/optica/common/util/StashingStack.java b/src/main/java/ru/windcorp/optica/common/util/StashingStack.java
index 27acbd6..e7d520e 100644
--- a/src/main/java/ru/windcorp/optica/common/util/StashingStack.java
+++ b/src/main/java/ru/windcorp/optica/common/util/StashingStack.java
@@ -208,6 +208,26 @@ public class StashingStack implements Iterable {
return newElement;
}
+ /**
+ * Returns the specified element from the stack. Indexing starts from the
+ * bottom of the stack. If the index is out of bounds, an
+ * {@link IndexOutOfBoundsException} is thrown.
+ * @param index index of the element to retrieve,
+ * [0; {@link #getSize()})
+ * @return the requested element
+ * @throws IndexOutOfBoundsException if the index is negative or greater
+ * than head
+ */
+ public T get(int index) {
+ if (index > head) {
+ throw new IndexOutOfBoundsException(
+ "Requested index " + index + " > head " + head
+ );
+ }
+
+ return (T) contents[index];
+ }
+
/**
* Removes all elements from the stack.
*/
diff --git a/src/main/resources/assets/shaders/Flat.fragment.glsl b/src/main/resources/assets/shaders/Flat.fragment.glsl
index be26587..15da58f 100644
--- a/src/main/resources/assets/shaders/Flat.fragment.glsl
+++ b/src/main/resources/assets/shaders/Flat.fragment.glsl
@@ -1,13 +1,26 @@
-#version 120
+#version 140
-uniform ivec2 maskStart;
-uniform ivec2 maskEnd;
+uniform int maskCount;
+
+uniform vec2 masks[3 * 2 * 16];
+
+bool isInMaskPrimitive(int primitive) {
+ vec2 origin = masks[3 * primitive + 0];
+ vec2 width = masks[3 * primitive + 1];
+ vec2 height = masks[3 * primitive + 2];
+
+ vec2 current = gl_FragCoord.xy - origin;
+
+ mat2 matrix = mat2(width, height);
+ vec2 relative = inverse(matrix) * current;
+
+ return relative.x >= 0 && relative.y >= 0 && relative.x + relative.y <= 1;
+}
void applyMask() {
- if (
- gl_FragCoord.x < maskStart.x || gl_FragCoord.x >= maskEnd.x ||
- gl_FragCoord.y < maskStart.y || gl_FragCoord.y >= maskEnd.y
- ) {
- discard;
+ for (int i = 0; i < maskCount; ++i) {
+ if (!(isInMaskPrimitive(2 * i + 0) || isInMaskPrimitive(2 * i + 1))) {
+ discard;
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/main/resources/assets/shaders/Flat.vertex.glsl b/src/main/resources/assets/shaders/Flat.vertex.glsl
index 7a531e1..9082679 100644
--- a/src/main/resources/assets/shaders/Flat.vertex.glsl
+++ b/src/main/resources/assets/shaders/Flat.vertex.glsl
@@ -1,4 +1,4 @@
-#version 120
+#version 140
void flatTransferToFragment() {
shapeTransferToFragment();
diff --git a/src/main/resources/assets/shaders/FlatDefault.fragment.glsl b/src/main/resources/assets/shaders/FlatDefault.fragment.glsl
index 507d434..267244c 100644
--- a/src/main/resources/assets/shaders/FlatDefault.fragment.glsl
+++ b/src/main/resources/assets/shaders/FlatDefault.fragment.glsl
@@ -1,4 +1,4 @@
-#version 120
+#version 140
void main(void) {
applyTexture();
diff --git a/src/main/resources/assets/shaders/FlatDefault.vertex.glsl b/src/main/resources/assets/shaders/FlatDefault.vertex.glsl
index 6ebcbfe..a317ef4 100644
--- a/src/main/resources/assets/shaders/FlatDefault.vertex.glsl
+++ b/src/main/resources/assets/shaders/FlatDefault.vertex.glsl
@@ -1,4 +1,4 @@
-#version 120
+#version 140
void main(void) {
gl_Position = applyFinalTransform(vec4(inputPositions, 1.0));
diff --git a/src/main/resources/assets/shaders/Shape.fragment.glsl b/src/main/resources/assets/shaders/Shape.fragment.glsl
index 4860b9f..d188922 100644
--- a/src/main/resources/assets/shaders/Shape.fragment.glsl
+++ b/src/main/resources/assets/shaders/Shape.fragment.glsl
@@ -1,4 +1,4 @@
-#version 120
+#version 140
varying vec3 varyingColorMultiplier;
varying vec2 varyingTextureCoords;
diff --git a/src/main/resources/assets/shaders/Shape.vertex.glsl b/src/main/resources/assets/shaders/Shape.vertex.glsl
index b5da67f..661252d 100644
--- a/src/main/resources/assets/shaders/Shape.vertex.glsl
+++ b/src/main/resources/assets/shaders/Shape.vertex.glsl
@@ -1,4 +1,4 @@
-#version 120
+#version 140
attribute vec3 inputPositions;
diff --git a/src/main/resources/assets/shaders/World.fragment.glsl b/src/main/resources/assets/shaders/World.fragment.glsl
index 7ec061b..691aadf 100644
--- a/src/main/resources/assets/shaders/World.fragment.glsl
+++ b/src/main/resources/assets/shaders/World.fragment.glsl
@@ -1,4 +1,4 @@
-#version 120
+#version 140
varying vec3 varyingNormals;
diff --git a/src/main/resources/assets/shaders/World.vertex.glsl b/src/main/resources/assets/shaders/World.vertex.glsl
index 229df49..435826d 100644
--- a/src/main/resources/assets/shaders/World.vertex.glsl
+++ b/src/main/resources/assets/shaders/World.vertex.glsl
@@ -1,4 +1,4 @@
-#version 120
+#version 140
attribute vec3 inputNormals;
varying vec3 varyingNormals;
diff --git a/src/main/resources/assets/shaders/WorldDefault.fragment.glsl b/src/main/resources/assets/shaders/WorldDefault.fragment.glsl
index 94be7fd..1e8b869 100644
--- a/src/main/resources/assets/shaders/WorldDefault.fragment.glsl
+++ b/src/main/resources/assets/shaders/WorldDefault.fragment.glsl
@@ -1,4 +1,4 @@
-#version 120
+#version 140
void main(void) {
applyTexture();
diff --git a/src/main/resources/assets/shaders/WorldDefault.vertex.glsl b/src/main/resources/assets/shaders/WorldDefault.vertex.glsl
index e9b6579..00a4097 100644
--- a/src/main/resources/assets/shaders/WorldDefault.vertex.glsl
+++ b/src/main/resources/assets/shaders/WorldDefault.vertex.glsl
@@ -1,4 +1,4 @@
-#version 120
+#version 140
void main(void) {
gl_Position = applyFinalTransform(vec4(inputPositions, 1.0));
diff --git a/src/main/resources/assets/textures/compass_icon.png b/src/main/resources/assets/textures/compass_icon.png
new file mode 100644
index 0000000..ef68813
Binary files /dev/null and b/src/main/resources/assets/textures/compass_icon.png differ
diff --git a/src/main/resources/assets/textures/compass_icon_arrow.png b/src/main/resources/assets/textures/compass_icon_arrow.png
new file mode 100644
index 0000000..01ff5d3
Binary files /dev/null and b/src/main/resources/assets/textures/compass_icon_arrow.png differ