Added GUI render and support for faces without textures
- Added FlatRenderProgram to render 2D graphics - Can be used as-is - Supports rectangular coordinate-aligned nested masks - Added AssembledFlatLayer to cache 2D graphics - Use RenderTarget for add elements during reassembly - ShapeRenderProgram now allows null textures (defaults to white BG) - Sprite now deduces size based on primitive's content size - unless given size explicitly - ShapeRenderHelper.*WorldTransform methods renamed to .*Transform
This commit is contained in:
parent
47ea102ed7
commit
1ed8f93af4
@ -21,6 +21,8 @@ import ru.windcorp.optica.Proxy;
|
||||
import ru.windcorp.optica.client.graphics.GUI;
|
||||
import ru.windcorp.optica.client.graphics.backend.GraphicsBackend;
|
||||
import ru.windcorp.optica.client.graphics.backend.RenderTaskQueue;
|
||||
import ru.windcorp.optica.client.graphics.flat.FlatRenderProgram;
|
||||
import ru.windcorp.optica.client.graphics.flat.LayerTestUI;
|
||||
import ru.windcorp.optica.client.graphics.world.LayerWorld;
|
||||
import ru.windcorp.optica.client.graphics.world.WorldRenderProgram;
|
||||
|
||||
@ -30,6 +32,7 @@ public class ClientProxy implements Proxy {
|
||||
public void initialize() {
|
||||
GraphicsBackend.initialize();
|
||||
try {
|
||||
RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init);
|
||||
RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
@ -37,6 +40,7 @@ public class ClientProxy implements Proxy {
|
||||
}
|
||||
|
||||
GUI.addBottomLayer(new LayerWorld());
|
||||
GUI.addTopLayer(new LayerTestUI());
|
||||
}
|
||||
|
||||
}
|
||||
|
21
src/main/java/ru/windcorp/optica/client/graphics/Colors.java
Normal file
21
src/main/java/ru/windcorp/optica/client/graphics/Colors.java
Normal file
@ -0,0 +1,21 @@
|
||||
package ru.windcorp.optica.client.graphics;
|
||||
|
||||
public class Colors {
|
||||
|
||||
public static final int
|
||||
WHITE = 0xFFFFFF,
|
||||
BLACK = 0x000000,
|
||||
|
||||
GRAY_4 = 0x444444,
|
||||
GRAY = 0x888888,
|
||||
GRAY_A = 0xAAAAAA,
|
||||
|
||||
DEBUG_RED = 0xFF0000,
|
||||
DEBUG_GREEN = 0x00FF00,
|
||||
DEBUG_BLUE = 0x0000FF,
|
||||
|
||||
DEBUG_CYAN = 0x00FFFF,
|
||||
DEBUG_MAGENTA = 0xFF00FF,
|
||||
DEBUG_YELLOW = 0x00FFFF;
|
||||
|
||||
}
|
@ -17,6 +17,8 @@
|
||||
*******************************************************************************/
|
||||
package ru.windcorp.optica.client.graphics;
|
||||
|
||||
import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
|
||||
|
||||
public abstract class Layer {
|
||||
|
||||
private final String name;
|
||||
@ -44,4 +46,12 @@ public abstract class Layer {
|
||||
|
||||
protected abstract void doRender();
|
||||
|
||||
protected float getWidth() {
|
||||
return GraphicsInterface.getFramebufferWidth();
|
||||
}
|
||||
|
||||
protected float getHeight() {
|
||||
return GraphicsInterface.getFramebufferHeight();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
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 RenderTarget target = new RenderTarget();
|
||||
|
||||
private boolean needsReassembly = true;
|
||||
private Clip[] clips = null;
|
||||
|
||||
public AssembledFlatLayer(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void markForReassembly() {
|
||||
needsReassembly = true;
|
||||
}
|
||||
|
||||
private void doReassemble() {
|
||||
assemble(target);
|
||||
clips = target.assemble();
|
||||
needsReassembly = false;
|
||||
}
|
||||
|
||||
protected abstract void assemble(RenderTarget target);
|
||||
|
||||
@Override
|
||||
protected void doRender() {
|
||||
if (needsReassembly) {
|
||||
doReassemble();
|
||||
}
|
||||
|
||||
for (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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package ru.windcorp.optica.client.graphics.flat;
|
||||
|
||||
public class FlatGraphics {
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package ru.windcorp.optica.client.graphics.flat;
|
||||
|
||||
import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
|
||||
import ru.windcorp.optica.client.graphics.model.ShapeRenderHelper;
|
||||
|
||||
public class FlatRenderHelper extends ShapeRenderHelper {
|
||||
|
||||
private final Mask mask = new Mask();
|
||||
|
||||
{
|
||||
setupScreenTransform();
|
||||
}
|
||||
|
||||
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() {
|
||||
float width = GraphicsInterface.getFramebufferWidth();
|
||||
float height = GraphicsInterface.getFramebufferHeight();
|
||||
|
||||
getTransform().translate(-1, +1, 0).scale(2 / width, -2 / height, 1);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package ru.windcorp.optica.client.graphics.flat;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
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.model.Shape;
|
||||
import ru.windcorp.optica.client.graphics.model.ShapeRenderHelper;
|
||||
import ru.windcorp.optica.client.graphics.model.ShapeRenderProgram;
|
||||
|
||||
public class FlatRenderProgram extends ShapeRenderProgram {
|
||||
|
||||
private static FlatRenderProgram def = null;
|
||||
|
||||
public static void init() {
|
||||
def = new FlatRenderProgram(
|
||||
new String[] {"FlatDefault.vertex.glsl"},
|
||||
new String[] {"FlatDefault.fragment.glsl"}
|
||||
);
|
||||
}
|
||||
|
||||
public static FlatRenderProgram getDefault() {
|
||||
return def;
|
||||
}
|
||||
|
||||
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";
|
||||
|
||||
private final Uniform2Int maskStartUniform;
|
||||
private final Uniform2Int maskEndUniform;
|
||||
|
||||
public FlatRenderProgram(
|
||||
String[] vertexShaderResources,
|
||||
String[] fragmentShaderResources
|
||||
) {
|
||||
super(
|
||||
attachVertexShader(vertexShaderResources),
|
||||
attachFragmentShader(fragmentShaderResources)
|
||||
);
|
||||
|
||||
this.maskStartUniform = getUniform(MASK_START_UNIFORM_NAME).as2Int();
|
||||
this.maskEndUniform = getUniform(MASK_END_UNIFORM_NAME).as2Int();
|
||||
}
|
||||
|
||||
private static String[] attachVertexShader(String[] others) {
|
||||
return ObjectArrays.concat(FLAT_VERTEX_SHADER_RESOURCE, others);
|
||||
}
|
||||
|
||||
private static String[] attachFragmentShader(String[] others) {
|
||||
return ObjectArrays.concat(FLAT_FRAGMENT_SHADER_RESOURCE, others);
|
||||
}
|
||||
|
||||
@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);
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(ShapeRenderHelper argHelper) {
|
||||
super.configure(argHelper);
|
||||
FlatRenderHelper helper = ((FlatRenderHelper) argHelper);
|
||||
|
||||
maskStartUniform.set(helper.getStartX(), helper.getStartY());
|
||||
maskEndUniform.set(helper.getEndX(), helper.getEndY());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package ru.windcorp.optica.client.graphics.flat;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
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.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;
|
||||
|
||||
public class LayerTestUI extends AssembledFlatLayer {
|
||||
|
||||
public LayerTestUI() {
|
||||
super("TestUI");
|
||||
|
||||
GraphicsInterface.subscribeToInputEvents(this);
|
||||
}
|
||||
|
||||
private boolean flag = false;
|
||||
|
||||
@Override
|
||||
protected void assemble(RenderTarget target) {
|
||||
final float width = 512 + 256;
|
||||
final float height = 64;
|
||||
final float border = 5;
|
||||
|
||||
final int boxColor = flag ? 0xEE8888 : 0xEEEE88;
|
||||
final int borderColor = flag ? 0xAA4444 : 0xAAAA44;
|
||||
final int boxShadowColor = flag ? 0x440000 : 0x444400;
|
||||
|
||||
float x = (getWidth() - width) / 2;
|
||||
float y = getHeight() - height;
|
||||
|
||||
y -= 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);
|
||||
|
||||
final float texShadow = 2;
|
||||
final float 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"));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onKeyEvent(KeyEvent event) {
|
||||
if (event.isRepeat() || event.getKey() != GLFW.GLFW_KEY_LEFT_CONTROL) {
|
||||
return;
|
||||
}
|
||||
|
||||
flag = event.isPress();
|
||||
markForReassembly();
|
||||
}
|
||||
|
||||
/*
|
||||
* TMP texture loader
|
||||
*/
|
||||
|
||||
private static final TextureSettings TEXTURE_SETTINGS =
|
||||
new TextureSettings(false);
|
||||
|
||||
private static Texture qtex(String name) {
|
||||
return new SimpleTexture(new Sprite(
|
||||
TextureManager.load(name, TEXTURE_SETTINGS)
|
||||
));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package ru.windcorp.optica.client.graphics.flat;
|
||||
|
||||
public class Mask {
|
||||
|
||||
private int startX;
|
||||
private int startY;
|
||||
private int endX;
|
||||
private int endY;
|
||||
|
||||
public Mask(int startX, int startY, int endX, int endY) {
|
||||
this.startX = startX;
|
||||
this.startY = startY;
|
||||
this.endX = endX;
|
||||
this.endY = endY;
|
||||
}
|
||||
|
||||
public Mask() {}
|
||||
|
||||
public int getStartX() {
|
||||
return startX;
|
||||
}
|
||||
|
||||
public void setStartX(int startX) {
|
||||
this.startX = startX;
|
||||
}
|
||||
|
||||
public int getStartY() {
|
||||
return startY;
|
||||
}
|
||||
|
||||
public void setStartY(int startY) {
|
||||
this.startY = startY;
|
||||
}
|
||||
|
||||
public int getEndX() {
|
||||
return endX;
|
||||
}
|
||||
|
||||
public void setEndX(int endX) {
|
||||
this.endX = endX;
|
||||
}
|
||||
|
||||
public int getEndY() {
|
||||
return endY;
|
||||
}
|
||||
|
||||
public void setEndY(int endY) {
|
||||
this.endY = endY;
|
||||
}
|
||||
|
||||
public void set(int startX, int startY, int endX, int endY) {
|
||||
this.startX = startX;
|
||||
this.startY = startY;
|
||||
this.endX = endX;
|
||||
this.endY = endY;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return startX >= endX || startY >= endY;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
package ru.windcorp.optica.client.graphics.flat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.optica.client.graphics.Colors;
|
||||
import ru.windcorp.optica.client.graphics.backend.Usage;
|
||||
import ru.windcorp.optica.client.graphics.model.Face;
|
||||
import ru.windcorp.optica.client.graphics.model.Faces;
|
||||
import ru.windcorp.optica.client.graphics.model.Shape;
|
||||
import ru.windcorp.optica.client.graphics.model.WorldRenderable;
|
||||
import ru.windcorp.optica.client.graphics.texture.Texture;
|
||||
|
||||
public class RenderTarget {
|
||||
|
||||
private static final int MAX_DEPTH = 1 << 16;
|
||||
|
||||
private final List<AssembledFlatLayer.Clip> assembled = new ArrayList<>();
|
||||
|
||||
private final Deque<Mask> maskStack = new LinkedList<>();
|
||||
|
||||
private final List<Face> currentClipFaces = new ArrayList<>();
|
||||
|
||||
private int depth = 0;
|
||||
|
||||
public RenderTarget() {
|
||||
reset();
|
||||
}
|
||||
|
||||
public void pushMaskStartEnd(int startX, int startY, int endX, int endY) {
|
||||
assembleCurrentClipFromFaces();
|
||||
maskStack.push(intersect(getMask(), startX, startY, endX, endY));
|
||||
}
|
||||
|
||||
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 void pushMask(Mask mask) {
|
||||
pushMaskStartEnd(
|
||||
mask.getStartX(), mask.getStartY(),
|
||||
mask.getEndX(), mask.getEndY()
|
||||
);
|
||||
}
|
||||
|
||||
public void pushMaskStartSize(int x, int y, int width, int height) {
|
||||
pushMaskStartEnd(x, y, x + width, y + height);
|
||||
}
|
||||
|
||||
public void popMask() {
|
||||
assembleCurrentClipFromFaces();
|
||||
maskStack.pop();
|
||||
}
|
||||
|
||||
public Mask 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() {
|
||||
assembleCurrentClipFromFaces();
|
||||
|
||||
AssembledFlatLayer.Clip[] result = assembled.toArray(
|
||||
new AssembledFlatLayer.Clip[assembled.size()]
|
||||
);
|
||||
|
||||
reset();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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 addCustomRenderer(WorldRenderable renderable) {
|
||||
assembleCurrentClipFromFaces();
|
||||
|
||||
Mask mask = getMask();
|
||||
if (mask.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assembled.add(new AssembledFlatLayer.Clip(mask, renderable));
|
||||
}
|
||||
|
||||
protected void addFaceToCurrentClip(Face face) {
|
||||
currentClipFaces.add(face);
|
||||
}
|
||||
|
||||
public void drawTexture(
|
||||
float x, float y, float width, float height,
|
||||
int color, Texture texture
|
||||
) {
|
||||
float depth = this.depth-- / (float) MAX_DEPTH;
|
||||
|
||||
addFaceToCurrentClip(Faces.createRectangle(
|
||||
FlatRenderProgram.getDefault(),
|
||||
texture,
|
||||
createVectorFromRGBInt(color),
|
||||
new Vec3(x, y + height, depth), // Flip
|
||||
new Vec3(width, 0, depth),
|
||||
new Vec3(0, -height, depth)
|
||||
));
|
||||
}
|
||||
|
||||
public void drawTexture(
|
||||
float x, float y, float width, float height,
|
||||
Texture texture
|
||||
) {
|
||||
drawTexture(x, y, width, height, Colors.WHITE, texture);
|
||||
}
|
||||
|
||||
public void fill(
|
||||
float x, float y, float width, float height,
|
||||
int color
|
||||
) {
|
||||
drawTexture(x, y, width, height, color, null);
|
||||
}
|
||||
|
||||
private static Vec3 createVectorFromRGBInt(int rgb) {
|
||||
int r = (rgb & 0xFF0000) >> 16;
|
||||
int g = (rgb & 0x00FF00) >> 8;
|
||||
int b = (rgb & 0x0000FF);
|
||||
|
||||
return new Vec3(r / 256f, g / 256f, b / 256f);
|
||||
}
|
||||
|
||||
}
|
@ -237,7 +237,7 @@ public class Face {
|
||||
}
|
||||
|
||||
public void setTexture(Texture texture) {
|
||||
this.texture = Objects.requireNonNull(texture, "texture");
|
||||
this.texture = texture;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,10 +36,10 @@ public abstract class Model implements WorldRenderable {
|
||||
Mat4 transform = getTransform(i);
|
||||
|
||||
try {
|
||||
helper.pushWorldTransform().mul(transform);
|
||||
helper.pushTransform().mul(transform);
|
||||
part.render(helper);
|
||||
} finally {
|
||||
helper.popWorldTransform();
|
||||
helper.popTransform();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,21 +32,21 @@ public class ShapeRenderHelper {
|
||||
transformStack.push().identity();
|
||||
}
|
||||
|
||||
public Mat4 pushWorldTransform() {
|
||||
public Mat4 pushTransform() {
|
||||
Mat4 previous = transformStack.getHead();
|
||||
return transformStack.push().set(previous);
|
||||
}
|
||||
|
||||
public void popWorldTransform() {
|
||||
public void popTransform() {
|
||||
transformStack.removeHead();
|
||||
}
|
||||
|
||||
public Mat4 getWorldTransform() {
|
||||
public Mat4 getTransform() {
|
||||
return transformStack.getHead();
|
||||
}
|
||||
|
||||
public Mat4 getFinalTransform() {
|
||||
return getWorldTransform();
|
||||
return getTransform();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
|
@ -35,6 +35,7 @@ import ru.windcorp.optica.client.graphics.backend.shaders.Program;
|
||||
import ru.windcorp.optica.client.graphics.backend.shaders.attributes.*;
|
||||
import ru.windcorp.optica.client.graphics.backend.shaders.uniforms.*;
|
||||
import ru.windcorp.optica.client.graphics.texture.Sprite;
|
||||
import ru.windcorp.optica.client.graphics.texture.Texture;
|
||||
|
||||
public class ShapeRenderProgram extends Program {
|
||||
|
||||
@ -53,6 +54,7 @@ public class ShapeRenderProgram extends Program {
|
||||
POSITIONS_ATTRIBUTE_NAME = "inputPositions",
|
||||
COLOR_MULTIPLER_ATTRIBUTE_NAME = "inputColorMultiplier",
|
||||
TEXTURE_COORDS_ATTRIBUTE_NAME = "inputTextureCoords",
|
||||
USE_TEXTURE_UNIFORM_NAME = "useTexture",
|
||||
TEXTURE_SLOT_UNIFORM_NAME = "textureSlot",
|
||||
TEXTURE_START_UNIFORM_NAME = "textureStart",
|
||||
TEXTURE_SIZE_UNIFORM_NAME = "textureSize";
|
||||
@ -61,6 +63,7 @@ public class ShapeRenderProgram extends Program {
|
||||
private final AttributeVertexArray positionsAttribute;
|
||||
private final AttributeVertexArray colorsAttribute;
|
||||
private final AttributeVertexArray textureCoordsAttribute;
|
||||
private final Uniform1Int useTextureUniform;
|
||||
private final Uniform1Int textureSlotUniform;
|
||||
private final Uniform2Float textureStartUniform;
|
||||
private final Uniform2Float textureSizeUniform;
|
||||
@ -90,6 +93,9 @@ public class ShapeRenderProgram extends Program {
|
||||
this.textureCoordsAttribute =
|
||||
getAttribute(TEXTURE_COORDS_ATTRIBUTE_NAME).asVertexArray();
|
||||
|
||||
this.useTextureUniform = getUniform(USE_TEXTURE_UNIFORM_NAME)
|
||||
.as1Int();
|
||||
|
||||
this.textureSlotUniform = getUniform(TEXTURE_SLOT_UNIFORM_NAME)
|
||||
.as1Int();
|
||||
|
||||
@ -174,13 +180,20 @@ public class ShapeRenderProgram extends Program {
|
||||
}
|
||||
|
||||
protected void renderFace(Face face) {
|
||||
Sprite sprite = face.getTexture().getSprite();
|
||||
Texture texture = face.getTexture();
|
||||
|
||||
sprite.getPrimitive().bind(0);
|
||||
textureSlotUniform.set(0);
|
||||
if (texture != null) {
|
||||
Sprite sprite = texture.getSprite();
|
||||
|
||||
textureStartUniform.set(sprite.getStart());
|
||||
textureSizeUniform.set(sprite.getSize());
|
||||
sprite.getPrimitive().bind(0);
|
||||
textureSlotUniform.set(0);
|
||||
useTextureUniform.set(1);
|
||||
|
||||
textureStartUniform.set(sprite.getStart());
|
||||
textureSizeUniform.set(sprite.getSize());
|
||||
} else {
|
||||
useTextureUniform.set(0);
|
||||
}
|
||||
|
||||
GL11.glDrawElements(
|
||||
GL11.GL_TRIANGLES,
|
||||
|
@ -24,7 +24,6 @@ import glm.vec._2.Vec2;
|
||||
public class Sprite {
|
||||
|
||||
private static final Vec2 ORIGIN = new Vec2(0, 0);
|
||||
private static final Vec2 FULL_PRIMITIVE = new Vec2(1, 1);
|
||||
|
||||
private final TexturePrimitive primitive;
|
||||
|
||||
@ -38,7 +37,10 @@ public class Sprite {
|
||||
}
|
||||
|
||||
public Sprite(TexturePrimitive primitive) {
|
||||
this(primitive, ORIGIN, FULL_PRIMITIVE);
|
||||
this(primitive, ORIGIN, new Vec2(
|
||||
primitive.getWidth() / (float) primitive.getBufferWidth(),
|
||||
primitive.getHeight() / (float) primitive.getBufferHeight()
|
||||
));
|
||||
}
|
||||
|
||||
public TexturePrimitive getPrimitive() {
|
||||
|
@ -48,7 +48,7 @@ public class WorldRenderHelper extends ShapeRenderHelper {
|
||||
|
||||
@Override
|
||||
public Mat4 getFinalTransform() {
|
||||
return finalTransform.set(getViewTransform()).mul(getWorldTransform());
|
||||
return finalTransform.set(getViewTransform()).mul(getTransform());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -96,7 +96,7 @@ public class WorldRenderProgram extends ShapeRenderProgram {
|
||||
@Override
|
||||
protected void configure(ShapeRenderHelper helper) {
|
||||
super.configure(helper);
|
||||
worldTransformUniform.set(helper.getWorldTransform());
|
||||
worldTransformUniform.set(helper.getTransform());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,7 +75,7 @@ public class ChunkRender {
|
||||
buildModel();
|
||||
}
|
||||
|
||||
renderer.pushWorldTransform().translate(
|
||||
renderer.pushTransform().translate(
|
||||
data.getX() * ChunkData.BLOCKS_PER_CHUNK,
|
||||
data.getY() * ChunkData.BLOCKS_PER_CHUNK,
|
||||
data.getZ() * ChunkData.BLOCKS_PER_CHUNK
|
||||
@ -83,7 +83,7 @@ public class ChunkRender {
|
||||
|
||||
model.render(renderer);
|
||||
|
||||
renderer.popWorldTransform();
|
||||
renderer.popTransform();
|
||||
}
|
||||
|
||||
private void buildModel() {
|
||||
|
@ -56,7 +56,7 @@ public class WorldRender {
|
||||
}
|
||||
|
||||
public void render(ShapeRenderHelper renderer) {
|
||||
renderer.pushWorldTransform().rotateX(-Math.PI / 2);
|
||||
renderer.pushTransform().rotateX(-Math.PI / 2);
|
||||
|
||||
for (ChunkRender chunk : getChunks()) {
|
||||
chunk.render(renderer);
|
||||
|
13
src/main/resources/assets/shaders/Flat.fragment.glsl
Normal file
13
src/main/resources/assets/shaders/Flat.fragment.glsl
Normal file
@ -0,0 +1,13 @@
|
||||
#version 120
|
||||
|
||||
uniform ivec2 maskStart;
|
||||
uniform ivec2 maskEnd;
|
||||
|
||||
void applyMask() {
|
||||
if (
|
||||
gl_FragCoord.x < maskStart.x || gl_FragCoord.x >= maskEnd.x ||
|
||||
gl_FragCoord.y < maskStart.y || gl_FragCoord.y >= maskEnd.y
|
||||
) {
|
||||
discard;
|
||||
}
|
||||
}
|
5
src/main/resources/assets/shaders/Flat.vertex.glsl
Normal file
5
src/main/resources/assets/shaders/Flat.vertex.glsl
Normal file
@ -0,0 +1,5 @@
|
||||
#version 120
|
||||
|
||||
void flatTransferToFragment() {
|
||||
shapeTransferToFragment();
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
#version 120
|
||||
|
||||
void main(void) {
|
||||
applyTexture();
|
||||
applyColorMultiplier();
|
||||
applyAlpha();
|
||||
applyMask();
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#version 120
|
||||
|
||||
void main(void) {
|
||||
gl_Position = applyFinalTransform(vec4(inputPositions, 1.0));
|
||||
flatTransferToFragment();
|
||||
}
|
@ -7,14 +7,20 @@ uniform sampler2D textureSlot;
|
||||
uniform vec2 textureStart;
|
||||
uniform vec2 textureSize;
|
||||
|
||||
uniform bool useTexture;
|
||||
|
||||
void applyTexture() {
|
||||
gl_FragColor = texture2D(
|
||||
textureSlot,
|
||||
vec2(
|
||||
varyingTextureCoords[0] * textureSize[0] + textureStart[0],
|
||||
varyingTextureCoords[1] * textureSize[1] + textureStart[1]
|
||||
)
|
||||
);
|
||||
if (!useTexture) {
|
||||
gl_FragColor = vec4(1, 1, 1, 1);
|
||||
} else {
|
||||
gl_FragColor = texture2D(
|
||||
textureSlot,
|
||||
vec2(
|
||||
varyingTextureCoords[0] * textureSize[0] + textureStart[0],
|
||||
varyingTextureCoords[1] * textureSize[1] + textureStart[1]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void multiply(inout vec4 vector, float scalar) {
|
||||
|
BIN
src/main/resources/assets/textures/windcorp.png
Normal file
BIN
src/main/resources/assets/textures/windcorp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Reference in New Issue
Block a user