diff --git a/build.gradle b/build.gradle
index 1eff0a5..f442d6d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -18,10 +18,12 @@ dependencies {
implementation 'ru.windcorp.fork.io.github.java-graphics:glm:1.0.1'
// log4j
- compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.13.3'
- compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.13.3'
+ implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.13.3'
+ implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.13.3'
testImplementation 'junit:junit:4.12'
+
+ // See also LWJGL dependencies below
}
/*
@@ -77,3 +79,22 @@ dependencies {
}
// LWJGL END
+
+jar {
+ manifest {
+ attributes(
+ "Main-Class": "ru.windcorp.progressia.client.ProgressiaClientMain",
+ "Class-Path": configurations.runtimeClasspath.collect { "lib/" + it.getName() }.join(' ')
+ )
+ }
+}
+
+/*
+ * Copies runtime dependencies to a prespecified location so they can be packaged properly.
+ */
+task copyLibs(type: Copy) {
+ into "${libsDir}/lib"
+ from configurations.runtimeClasspath
+}
+
+build.dependsOn(copyLibs)
diff --git a/src/main/java/ru/windcorp/jputil/chars/StringUtil.java b/src/main/java/ru/windcorp/jputil/chars/StringUtil.java
index 9a8933b..8641ccf 100644
--- a/src/main/java/ru/windcorp/jputil/chars/StringUtil.java
+++ b/src/main/java/ru/windcorp/jputil/chars/StringUtil.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
+import java.util.Objects;
import java.util.function.IntFunction;
public class StringUtil {
@@ -775,4 +776,35 @@ public class StringUtil {
else return (char) ('A' - 0xA + value);
}
+ public static String replaceAll(String source, String substring, String replacement) {
+ Objects.requireNonNull(source, "source");
+ Objects.requireNonNull(substring, "substring");
+
+ if (substring.isEmpty()) {
+ throw new IllegalArgumentException("substring is empty");
+ }
+
+ if (!source.contains(substring)) { // also passes if source is empty
+ return source;
+ }
+
+ if (substring.equals(replacement)) { // null-safe
+ return source;
+ }
+
+ StringBuilder sb = new StringBuilder(2 * source.length());
+
+ for (int i = 0; i < source.length() - substring.length() + 1; ++i) {
+ if (source.startsWith(substring, i)) {
+ if (replacement != null) {
+ sb.append(replacement);
+ }
+ } else {
+ sb.append(source.charAt(i));
+ }
+ }
+
+ return sb.toString();
+ }
+
}
diff --git a/src/main/java/ru/windcorp/progressia/client/ClientState.java b/src/main/java/ru/windcorp/progressia/client/ClientState.java
index 84c26a2..b812907 100644
--- a/src/main/java/ru/windcorp/progressia/client/ClientState.java
+++ b/src/main/java/ru/windcorp/progressia/client/ClientState.java
@@ -3,10 +3,10 @@ package ru.windcorp.progressia.client;
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.flat.LayerTestUI;
-import ru.windcorp.progressia.client.graphics.gui.LayerTestGUI;
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.server.ServerState;
+import ru.windcorp.progressia.test.LayerTestGUI;
public class ClientState {
diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/LayerTestGUI.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/LayerTestGUI.java
deleted file mode 100755
index 6a74d96..0000000
--- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/LayerTestGUI.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*******************************************************************************
- * Progressia
- * 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.progressia.client.graphics.gui;
-
-import com.google.common.eventbus.Subscribe;
-import glm.vec._2.i.Vec2i;
-import org.lwjgl.glfw.GLFW;
-import ru.windcorp.progressia.client.graphics.Colors;
-import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
-import ru.windcorp.progressia.client.graphics.font.Font;
-import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent;
-import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
-import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
-import ru.windcorp.progressia.client.graphics.input.KeyEvent;
-import ru.windcorp.progressia.client.localization.Localizer;
-import ru.windcorp.progressia.client.localization.MutableString;
-import ru.windcorp.progressia.client.localization.MutableStringLocalized;
-
-public class LayerTestGUI extends GUILayer {
-
- private static class DebugComponent extends Component {
- private final int color;
-
- public DebugComponent(String name, Vec2i size, int color) {
- super(name);
- this.color = color;
-
- setPreferredSize(size);
-
- addListener(new Object() {
- @Subscribe
- public void onHoverChanged(HoverEvent e) {
- requestReassembly();
- }
- });
-
- addListener(KeyEvent.class, this::onClicked);
- }
-
- private boolean onClicked(KeyEvent event) {
- if (!event.isMouse()) {
- return false;
- } else if (event.isPress() && event.isLeftMouseButton()) {
- System.out.println("You pressed a Component!");
- }
- return true;
- }
-
- @Override
- protected void assembleSelf(RenderTarget target) {
- target.fill(getX(), getY(), getWidth(), getHeight(), Colors.BLACK);
-
- target.fill(
- getX() + 2, getY() + 2,
- getWidth() - 4, getHeight() - 4,
- isHovered() ? Colors.DEBUG_YELLOW : color
- );
- }
- }
-
- public LayerTestGUI() {
- super("LayerTestGui", new LayoutAlign(1, 0.75, 5));
-
- Panel panel = new Panel("Alex", new LayoutVertical(5));
-
- panel.addChild(new DebugComponent("Bravo", new Vec2i(200, 100), 0x44FF44));
-
- Component charlie = new DebugComponent("Charlie", null, 0x222222);
- charlie.setLayout(new LayoutVertical(5));
-
- //Debug
- Localizer.getInstance().setLanguage("ru-RU");
- MutableString epsilon = new MutableStringLocalized("Epsilon")
- .addListener(() -> ((Label)charlie.getChild(0)).update()).format(34, "thirty-four");
- // These two are swapped in code due to a bug in layouts, fixing ATM
- charlie.addChild(
- new Label(
- "Delta",
- new Font().withColor(0xCCBB44).deriveShadow().deriveBold(),
- "Пре-альфа!"
- )
- );
- charlie.addChild(
- new Label(
- "Epsilon",
- new Font().withColor(0x4444BB).deriveItalic(),
- () -> epsilon.get().concat("\u269b")
- )
- );
- panel.addChild(charlie);
-
-
- charlie.addListener(KeyEvent.class, e -> {
- if(e.isPress() && e.getKey() == GLFW.GLFW_KEY_L) {
- Localizer localizer = Localizer.getInstance();
- if (localizer.getLanguage().equals("ru-RU")) {
- localizer.setLanguage("en-US");
- } else {
- localizer.setLanguage("ru-RU");
- }
- return true;
- } return false;
- });
- charlie.setFocusable(true);
- charlie.takeFocus();
-
- getRoot().addChild(panel);
- }
-
-}
diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java
index c6799c5..00d47b1 100644
--- a/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java
+++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java
@@ -121,5 +121,14 @@ public class LambdaModel extends DynamicModel {
}
}
+
+ public static LambdaModel animate(Renderable model, TransformGetter transform) {
+ return new LambdaModel(
+ new Renderable[] { model },
+ new Mat4[] { new Mat4() },
+ new boolean[] { true },
+ new TransformGetter[] { transform }
+ );
+ }
}
diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java
index d8f4c18..8aaf4d4 100644
--- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java
+++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java
@@ -19,10 +19,10 @@ public class ComplexTexture {
this.primitive = primitive;
this.assumedWidth = abstractWidth
- * primitive.getWidth() / (float) primitive.getBufferWidth();
+ / (float) primitive.getWidth() * primitive.getBufferWidth();
this.assumedHeight = abstractHeight
- * primitive.getHeight() / (float) primitive.getBufferHeight();
+ / (float) primitive.getHeight() * primitive.getBufferHeight();
}
public Texture get(int x, int y, int width, int height) {
diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java
index ab99777..56748f9 100644
--- a/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java
+++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java
@@ -271,6 +271,10 @@ public class Camera {
currentModeIndex++;
}
}
+
+ public int getCurrentModeIndex() {
+ return currentModeIndex;
+ }
public float getLastAnchorYaw() {
return lastAnchorYaw;
diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java
index 114e1ed..fb7557e 100644
--- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java
+++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java
@@ -20,45 +20,27 @@ package ru.windcorp.progressia.client.graphics.world;
import java.util.ArrayList;
import java.util.List;
-import org.lwjgl.glfw.GLFW;
-
-import glm.Glm;
-import glm.mat._3.Mat3;
-import glm.vec._2.Vec2;
-import glm.vec._3.Vec3;
import ru.windcorp.progressia.client.Client;
+import ru.windcorp.progressia.client.ClientState;
import ru.windcorp.progressia.client.comms.controls.InputBasedControls;
import ru.windcorp.progressia.client.graphics.Layer;
import ru.windcorp.progressia.client.graphics.backend.FaceCulling;
-import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend;
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
-import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent;
-import ru.windcorp.progressia.client.graphics.input.InputEvent;
-import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
-import ru.windcorp.progressia.common.collision.AABB;
+import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.collision.Collideable;
-import ru.windcorp.progressia.common.collision.CollisionClock;
-import ru.windcorp.progressia.common.collision.CollisionModel;
-import ru.windcorp.progressia.common.collision.CompoundCollisionModel;
import ru.windcorp.progressia.common.collision.colliders.Collider;
-import ru.windcorp.progressia.common.util.FloatMathUtils;
-import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.entity.EntityData;
-import ru.windcorp.progressia.test.AABBRenderer;
+import ru.windcorp.progressia.test.CollisionModelRenderer;
+import ru.windcorp.progressia.test.TestPlayerControls;
public class LayerWorld extends Layer {
- private final Mat3 angMat = new Mat3();
-
- private int movementForward = 0;
- private int movementRight = 0;
- private int movementUp = 0;
-
private final WorldRenderHelper helper = new WorldRenderHelper();
private final Client client;
private final InputBasedControls inputBasedControls;
+ private final TestPlayerControls tmp_testControls = TestPlayerControls.getInstance();
public LayerWorld(Client client) {
super("World");
@@ -79,40 +61,12 @@ public class LayerWorld extends Layer {
@Override
protected void doRender() {
- if (client.getLocalPlayer() != null) {
- tmp_handleControls();
- }
-
Camera camera = client.getCamera();
if (camera.hasAnchor()) {
renderWorld();
}
}
- private void tmp_handleControls() {
- EntityData player = client.getLocalPlayer();
-
- angMat.identity().rotateZ(player.getYaw());
-
- Vec3 movement = Vectors.grab3();
-
- // Horizontal and vertical max control speed
- final float movementSpeed = 0.1f * 60.0f;
- // (0; 1], 1 is instant change, 0 is no control authority
- final float controlAuthority = 0.1f;
-
- movement.set(movementForward, -movementRight, 0);
- if (movementForward != 0 && movementRight != 0) movement.normalize();
- angMat.mul_(movement); // bug in jglm, .mul() and mul_() are swapped
- movement.z = movementUp;
- movement.mul(movementSpeed);
- movement.sub(player.getVelocity());
- movement.mul(controlAuthority);
- player.getVelocity().add(movement);
-
- Vectors.release(movement);
- }
-
private void renderWorld() {
client.getCamera().apply(helper);
FaceCulling.push(true);
@@ -128,150 +82,75 @@ public class LayerWorld extends Layer {
private final Collider.ColliderWorkspace tmp_colliderWorkspace = new Collider.ColliderWorkspace();
private final List tmp_collideableList = new ArrayList<>();
- private static final boolean RENDER_AABBS = true;
+ private static final boolean RENDER_COLLISION_MODELS = false;
private void tmp_doEveryFrame() {
+ float tickLength = (float) GraphicsInterface.getFrameLength();
+
try {
- if (RENDER_AABBS) {
- for (EntityData data : this.client.getWorld().getData().getEntities()) {
- CollisionModel model = data.getCollisionModel();
- if (model instanceof AABB) {
- AABBRenderer.renderAABB((AABB) model, helper);
- } else if (model instanceof CompoundCollisionModel) {
- AABBRenderer.renderAABBsInCompound((CompoundCollisionModel) model, helper);
- }
- }
- }
+ tmp_performCollisions(tickLength);
- tmp_collideableList.clear();
- tmp_collideableList.addAll(this.client.getWorld().getData().getEntities());
-
- Collider.performCollisions(
- tmp_collideableList,
- new CollisionClock() {
- private float t = 0;
- @Override
- public float getTime() {
- return t;
- }
-
- @Override
- public void advanceTime(float change) {
- t += change;
- }
- },
- (float) GraphicsInterface.getFrameLength(),
- tmp_colliderWorkspace
- );
-
- final float frictionCoeff = 1 - 1e-2f;
+ tmp_testControls.applyPlayerControls();
for (EntityData data : this.client.getWorld().getData().getEntities()) {
- data.getVelocity().mul(frictionCoeff);
+ tmp_applyFriction(data);
+ tmp_applyGravity(data, tickLength);
+ tmp_renderCollisionModel(data);
}
- } catch (Exception e) {
+ } catch (Throwable e) {
+ e.printStackTrace();
+ System.err.println("OLEGSHA is to blame. Tell him he vry stupiDD!!");
System.exit(31337);
}
}
+ private void tmp_renderCollisionModel(EntityData entity) {
+ if (RENDER_COLLISION_MODELS) {
+ CollisionModelRenderer.renderCollisionModel(entity.getCollisionModel(), helper);
+ }
+ }
+
+ private void tmp_performCollisions(float tickLength) {
+ tmp_collideableList.clear();
+ tmp_collideableList.addAll(this.client.getWorld().getData().getEntities());
+
+ Collider.performCollisions(
+ tmp_collideableList,
+ this.client.getWorld().getData(),
+ tickLength,
+ tmp_colliderWorkspace
+ );
+ }
+
+ private void tmp_applyFriction(EntityData entity) {
+ final float frictionCoeff = 1 - 1e-5f;
+ entity.getVelocity().mul(frictionCoeff);
+ }
+
+ private void tmp_applyGravity(EntityData entity, float tickLength) {
+ if (ClientState.getInstance().getLocalPlayer() == entity && tmp_testControls.isFlying()) {
+ return;
+ }
+
+ final float gravitationalAcceleration;
+
+ if (tmp_testControls.useMinecraftGravity()) {
+ gravitationalAcceleration = 32f * Units.METERS_PER_SECOND_SQUARED; // plz dont sue me M$
+ } else {
+ gravitationalAcceleration = 9.81f * Units.METERS_PER_SECOND_SQUARED;
+ }
+ entity.getVelocity().add(0, 0, -gravitationalAcceleration * tickLength);
+ }
+
@Override
protected void handleInput(Input input) {
if (input.isConsumed()) return;
- InputEvent event = input.getEvent();
-
- if (event instanceof KeyEvent) {
- if (onKeyEvent((KeyEvent) event)) {
- input.consume();
- }
- } else if (event instanceof CursorMoveEvent) {
- onMouseMoved((CursorMoveEvent) event);
- input.consume();
- }
+ tmp_testControls.handleInput(input);
if (!input.isConsumed()) {
inputBasedControls.handleInput(input);
}
}
-
- private boolean flag = true;
-
- private boolean onKeyEvent(KeyEvent event) {
- if (event.isRepeat()) return false;
-
- int multiplier = event.isPress() ? 1 : -1;
-
- switch (event.getKey()) {
- case GLFW.GLFW_KEY_W:
- movementForward += +1 * multiplier;
- break;
- case GLFW.GLFW_KEY_S:
- movementForward += -1 * multiplier;
- break;
- case GLFW.GLFW_KEY_A:
- movementRight += -1 * multiplier;
- break;
- case GLFW.GLFW_KEY_D:
- movementRight += +1 * multiplier;
- break;
- case GLFW.GLFW_KEY_SPACE:
- movementUp += +1 * multiplier;
- break;
- case GLFW.GLFW_KEY_LEFT_SHIFT:
- movementUp += -1 * multiplier;
- break;
-
- case GLFW.GLFW_KEY_ESCAPE:
- if (!event.isPress()) return false;
-
- 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;
-
- case GLFW.GLFW_KEY_F5:
- if (!event.isPress()) return false;
-
- if (client.getCamera().hasAnchor()) {
- client.getCamera().selectNextMode();
- }
- break;
-
- default:
- return false;
- }
-
- return true;
- }
-
- private void onMouseMoved(CursorMoveEvent event) {
- if (!flag) return;
-
- final float yawScale = -0.002f;
- final float pitchScale = yawScale;
-
- EntityData player = client.getLocalPlayer();
-
- if (player != null) {
- normalizeAngles(player.getDirection().add(
- (float) (event.getChangeX() * yawScale),
- (float) (event.getChangeY() * pitchScale)
- ));
- }
- }
-
- private void normalizeAngles(Vec2 dir) {
- // Normalize yaw
- dir.x = FloatMathUtils.normalizeAngle(dir.x);
-
- // Clamp pitch
- dir.y = Glm.clamp(
- dir.y, -FloatMathUtils.PI_F/2, +FloatMathUtils.PI_F/2
- );
- }
}
diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java
new file mode 100644
index 0000000..45817db
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java
@@ -0,0 +1,116 @@
+package ru.windcorp.progressia.client.world.entity;
+
+import static java.lang.Math.*;
+import static ru.windcorp.progressia.common.util.FloatMathUtils.*;
+
+import glm.mat._4.Mat4;
+import glm.vec._3.Vec3;
+import ru.windcorp.progressia.client.graphics.model.Renderable;
+import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
+import ru.windcorp.progressia.common.world.entity.EntityData;
+
+public class HumanoidModel extends NPedModel {
+
+ protected static abstract class Limb extends BodyPart {
+ private final float animationOffset;
+
+ public Limb(
+ Renderable renderable, Vec3 joint,
+ float animationOffset
+ ) {
+ super(renderable, joint);
+ this.animationOffset = animationOffset;
+ }
+
+ @Override
+ protected void applyTransform(Mat4 mat, NPedModel model) {
+ float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset;
+ float value = sin(phase);
+ float amplitude = getSwingAmplitude((HumanoidModel) model) * model.getVelocityParameter();
+ mat.rotateY(value * amplitude);
+ }
+
+ protected abstract float getSwingAmplitude(HumanoidModel model);
+
+ }
+
+ public static class Leg extends Limb {
+ public Leg(
+ Renderable renderable, Vec3 joint,
+ float animationOffset
+ ) {
+ super(renderable, joint, animationOffset);
+ }
+
+ @Override
+ protected float getSwingAmplitude(HumanoidModel model) {
+ return model.walkingLegSwing;
+ }
+ }
+
+ public static class Arm extends Limb {
+ public Arm(
+ Renderable renderable, Vec3 joint,
+ float animationOffset
+ ) {
+ super(renderable, joint, animationOffset);
+ }
+
+ @Override
+ protected float getSwingAmplitude(HumanoidModel model) {
+ return model.walkingArmSwing;
+ }
+ }
+
+ private final Arm leftArm;
+ private final Arm rightArm;
+ private final Leg leftLeg;
+ private final Leg rightLeg;
+
+ private float walkingLegSwing;
+ private float walkingArmSwing;
+
+ public HumanoidModel(
+ EntityData entity,
+
+ Body body, Head head,
+ Arm leftArm, Arm rightArm,
+ Leg leftLeg, Leg rightLeg,
+
+ float scale
+ ) {
+ super(entity, body, head, scale);
+ this.leftArm = leftArm;
+ this.rightArm = rightArm;
+ this.leftLeg = leftLeg;
+ this.rightLeg = rightLeg;
+ }
+
+ @Override
+ protected void renderBodyParts(ShapeRenderHelper renderer) {
+ super.renderBodyParts(renderer);
+ leftArm.render(renderer, this);
+ rightArm.render(renderer, this);
+ leftLeg.render(renderer, this);
+ rightLeg.render(renderer, this);
+ }
+
+ public float getWalkingArmSwing() {
+ return walkingArmSwing;
+ }
+
+ public float getWalkingLegSwing() {
+ return walkingLegSwing;
+ }
+
+ public HumanoidModel setWalkingLegSwing(float walkingLegSwing) {
+ this.walkingLegSwing = walkingLegSwing;
+ return this;
+ }
+
+ public HumanoidModel setWalkingArmSwing(float walkingArmSwing) {
+ this.walkingArmSwing = walkingArmSwing;
+ return this;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java
new file mode 100644
index 0000000..441ff6e
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java
@@ -0,0 +1,284 @@
+package ru.windcorp.progressia.client.world.entity;
+
+import static java.lang.Math.atan2;
+import static java.lang.Math.min;
+import static java.lang.Math.pow;
+import static java.lang.Math.toRadians;
+import static ru.windcorp.progressia.common.util.FloatMathUtils.normalizeAngle;
+
+import glm.Glm;
+import glm.mat._4.Mat4;
+import glm.vec._3.Vec3;
+import glm.vec._4.Vec4;
+import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
+import ru.windcorp.progressia.client.graphics.model.Renderable;
+import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
+import ru.windcorp.progressia.common.Units;
+import ru.windcorp.progressia.common.util.Matrices;
+import ru.windcorp.progressia.common.util.Vectors;
+import ru.windcorp.progressia.common.world.entity.EntityData;
+
+public abstract class NPedModel extends EntityRenderable {
+
+ protected static abstract class BodyPart {
+ private final Renderable renderable;
+ private final Vec3 translation = new Vec3();
+
+ public BodyPart(Renderable renderable, Vec3 joint) {
+ this.renderable = renderable;
+ if (joint != null) {
+ this.translation.set(joint);
+ }
+ }
+
+
+ protected void render(
+ ShapeRenderHelper renderer, NPedModel model
+ ) {
+ renderer.pushTransform().translate(translation);
+ applyTransform(renderer.pushTransform(), model);
+ renderable.render(renderer);
+ renderer.popTransform();
+ renderer.popTransform();
+ }
+
+ protected abstract void applyTransform(Mat4 mat, NPedModel model);
+
+ public Vec3 getTranslation() {
+ return translation;
+ }
+ }
+
+ public static class Body extends BodyPart {
+ public Body(Renderable renderable) {
+ super(renderable, null);
+ }
+
+ @Override
+ protected void applyTransform(Mat4 mat, NPedModel model) {
+ // Do nothing
+ }
+ }
+
+ public static class Head extends BodyPart {
+ private final float maxYaw;
+ private final float maxPitch;
+
+ private final Vec3 viewPoint;
+
+ public Head(
+ Renderable renderable, Vec3 joint,
+ double maxYawDegrees, double maxPitchDegrees,
+ Vec3 viewPoint
+ ) {
+ super(renderable, joint);
+ this.maxYaw = (float) toRadians(maxYawDegrees);
+ this.maxPitch = (float) toRadians(maxPitchDegrees);
+ this.viewPoint = viewPoint;
+ }
+
+ @Override
+ protected void applyTransform(Mat4 mat, NPedModel model) {
+ mat.rotateZ(model.getHeadYaw()).rotateY(model.getHeadPitch());
+ }
+
+ public Vec3 getViewPoint() {
+ return viewPoint;
+ }
+ }
+
+ protected final Body body;
+ protected final Head head;
+
+ private float walkingParameter = 0;
+ private float velocityParameter = 0;
+ private float velocity = 0;
+
+ /**
+ * If {@link #velocity} is greater than this value, {@link #velocityParameter} is 1.0.
+ */
+ private float maxEffectiveVelocity = 5 * Units.METERS_PER_SECOND;
+
+ /**
+ * If {@link #velocity} is less than {@link #maxEffectiveVelocity}, then
+ * {@code velocityCoeff = exp(velocity / maxEffectiveVelocity, velocityCoeffPower)}.
+ */
+ private float velocityCoeffPower = 1;
+
+ private final float scale;
+
+ private float walkingFrequency;
+
+ private float bodyYaw = Float.NaN;
+ private float headYaw;
+ private float headPitch;
+
+ public NPedModel(EntityData data, Body body, Head head, float scale) {
+ super(data);
+ this.body = body;
+ this.head = head;
+ this.scale = scale;
+ }
+
+ @Override
+ public void render(ShapeRenderHelper renderer) {
+ renderer.pushTransform().scale(scale).rotateZ(bodyYaw);
+ renderBodyParts(renderer);
+ renderer.popTransform();
+
+ accountForVelocity();
+ evaluateAngles();
+ }
+
+ protected void renderBodyParts(ShapeRenderHelper renderer) {
+ body.render(renderer, this);
+ head.render(renderer, this);
+ }
+
+ private void evaluateAngles() {
+ float globalYaw = normalizeAngle(getData().getYaw());
+
+ if (Float.isNaN(bodyYaw)) {
+ bodyYaw = globalYaw;
+ headYaw = 0;
+ } else {
+ headYaw = normalizeAngle(globalYaw - bodyYaw);
+
+ if (headYaw > +head.maxYaw) {
+ bodyYaw += headYaw - +head.maxYaw;
+ headYaw = +head.maxYaw;
+ } else if (headYaw < -head.maxYaw) {
+ bodyYaw += headYaw - -head.maxYaw;
+ headYaw = -head.maxYaw;
+ }
+ }
+
+ bodyYaw = normalizeAngle(bodyYaw);
+
+ headPitch = Glm.clamp(
+ getData().getPitch(),
+ -head.maxPitch, head.maxPitch
+ );
+ }
+
+ private void accountForVelocity() {
+ Vec3 horizontal = Vectors.grab3();
+ horizontal.set(getData().getVelocity());
+ horizontal.z = 0;
+
+ velocity = horizontal.length();
+
+ evaluateVelocityCoeff();
+
+ // TODO switch to world time
+ walkingParameter += velocity * GraphicsInterface.getFrameLength() * 1000;
+
+ bodyYaw += velocityParameter * normalizeAngle(
+ (float) (atan2(horizontal.y, horizontal.x) - bodyYaw)
+ ) * min(1, GraphicsInterface.getFrameLength() * 10);
+ Vectors.release(horizontal);
+ }
+
+ private void evaluateVelocityCoeff() {
+ if (velocity > maxEffectiveVelocity) {
+ velocityParameter = 1;
+ } else {
+ velocityParameter = (float) pow(velocity / maxEffectiveVelocity, velocityCoeffPower);
+ }
+ }
+
+ @Override
+ public void getViewPoint(Vec3 output) {
+ Mat4 m = Matrices.grab4();
+ Vec4 v = Vectors.grab4();
+
+ m.identity()
+ .scale(scale)
+ .rotateZ(bodyYaw)
+ .translate(head.getTranslation())
+ .rotateZ(headYaw)
+ .rotateY(headPitch);
+
+ v.set(head.getViewPoint(), 1);
+ m.mul(v);
+
+ output.set(v.x, v.y, v.z);
+
+ Vectors.release(v);
+ Matrices.release(m);
+ }
+
+ public Body getBody() {
+ return body;
+ }
+
+ public Head getHead() {
+ return head;
+ }
+
+ public float getBodyYaw() {
+ return bodyYaw;
+ }
+
+ public float getHeadYaw() {
+ return headYaw;
+ }
+
+ public float getHeadPitch() {
+ return headPitch;
+ }
+
+ /**
+ * Returns a number in the range [0; 1] that can be used to scale animation effects that depend on speed.
+ * This parameter is 0 when the entity is not moving and 1 when it's moving "fast".
+ * @return velocity parameter
+ */
+ protected float getVelocityParameter() {
+ return velocityParameter;
+ }
+
+ /**
+ * Returns a number that can be used to parameterize animation effects that depend on walking.
+ * This parameter increases when the entity moves (e.g. this can be total traveled distance).
+ * @return walking parameter
+ */
+ protected float getWalkingParameter() {
+ return walkingParameter;
+ }
+
+ protected float getVelocity() {
+ return velocity;
+ }
+
+ public float getScale() {
+ return scale;
+ }
+
+ protected float getWalkingFrequency() {
+ return walkingFrequency;
+ }
+
+ public NPedModel setWalkingFrequency(float walkingFrequency) {
+ this.walkingFrequency = walkingFrequency;
+ return this;
+ }
+
+ public float getMaxEffectiveVelocity() {
+ return maxEffectiveVelocity;
+ }
+
+ public float getVelocityCoeffPower() {
+ return velocityCoeffPower;
+ }
+
+ public NPedModel setMaxEffectiveVelocity(float maxEffectiveVelocity) {
+ this.maxEffectiveVelocity = maxEffectiveVelocity;
+ return this;
+ }
+
+ public NPedModel setVelocityCoeffPower(float velocityCoeffPower) {
+ this.velocityCoeffPower = velocityCoeffPower;
+ return this;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java
index c19a3b0..00311d4 100644
--- a/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java
+++ b/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java
@@ -2,86 +2,15 @@ package ru.windcorp.progressia.client.world.entity;
import static java.lang.Math.*;
import static ru.windcorp.progressia.common.util.FloatMathUtils.*;
+import static ru.windcorp.progressia.common.util.FloatMathUtils.sin;
-import glm.Glm;
import glm.mat._4.Mat4;
import glm.vec._3.Vec3;
-import glm.vec._4.Vec4;
-import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
import ru.windcorp.progressia.client.graphics.model.Renderable;
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
-import ru.windcorp.progressia.common.util.Matrices;
-import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.entity.EntityData;
-public class QuadripedModel extends EntityRenderable {
-
- private static abstract class BodyPart {
- private final Renderable renderable;
- private final Vec3 translation = new Vec3();
-
- public BodyPart(Renderable renderable, Vec3 joint) {
- this.renderable = renderable;
- if (joint != null) {
- this.translation.set(joint);
- }
- }
-
-
- protected void render(
- ShapeRenderHelper renderer, QuadripedModel model
- ) {
- renderer.pushTransform().translate(translation);
- applyTransform(renderer.pushTransform(), model);
- renderable.render(renderer);
- renderer.popTransform();
- renderer.popTransform();
- }
-
- protected abstract void applyTransform(Mat4 mat, QuadripedModel model);
-
- public Vec3 getTranslation() {
- return translation;
- }
- }
-
- public static class Body extends BodyPart {
- public Body(Renderable renderable) {
- super(renderable, null);
- }
-
- @Override
- protected void applyTransform(Mat4 mat, QuadripedModel model) {
- // Do nothing
- }
- }
-
- public static class Head extends BodyPart {
- private final float maxYaw;
- private final float maxPitch;
-
- private final Vec3 viewPoint;
-
- public Head(
- Renderable renderable, Vec3 joint,
- double maxYawDegrees, double maxPitchDegrees,
- Vec3 viewPoint
- ) {
- super(renderable, joint);
- this.maxYaw = (float) toRadians(maxYawDegrees);
- this.maxPitch = (float) toRadians(maxPitchDegrees);
- this.viewPoint = viewPoint;
- }
-
- @Override
- protected void applyTransform(Mat4 mat, QuadripedModel model) {
- mat.rotateZ(model.headYaw).rotateY(model.headPitch);
- }
-
- public Vec3 getViewPoint() {
- return viewPoint;
- }
- }
+public class QuadripedModel extends NPedModel {
public static class Leg extends BodyPart {
private final float animationOffset;
@@ -95,33 +24,19 @@ public class QuadripedModel extends EntityRenderable {
}
@Override
- protected void applyTransform(Mat4 mat, QuadripedModel model) {
- mat.rotateY(sin(model.walkingFrequency * model.walkingAnimationParameter + animationOffset) * model.walkingSwing * model.velocityCoeff);
+ protected void applyTransform(Mat4 mat, NPedModel model) {
+ float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset;
+ float value = sin(phase);
+ float amplitude = ((QuadripedModel) model).getWalkingSwing() * model.getVelocityParameter();
+ mat.rotateY(value * amplitude);
}
+
}
- private final Body body;
- private final Head head;
private final Leg leftForeLeg, rightForeLeg;
private final Leg leftHindLeg, rightHindLeg;
- private final float scale;
-
- private float walkingAnimationParameter = 0;
- private float velocityCoeff = 0;
- private float velocity = 0;
-
- /**
- * Controls how quickly velocityCoeff approaches 1
- */
- private float velocityCutoff = 10;
-
- private float walkingFrequency = 0.15f / 60.0f;
private float walkingSwing = (float) toRadians(30);
-
- private float bodyYaw = Float.NaN;
- private float headYaw;
- private float headPitch;
public QuadripedModel(
EntityData entity,
@@ -132,105 +47,30 @@ public class QuadripedModel extends EntityRenderable {
float scale
) {
- super(entity);
+ super(entity, body, head, scale);
- this.body = body;
- this.head = head;
this.leftForeLeg = leftForeLeg;
this.rightForeLeg = rightForeLeg;
this.leftHindLeg = leftHindLeg;
this.rightHindLeg = rightHindLeg;
-
- this.scale = scale;
}
@Override
- public void render(ShapeRenderHelper renderer) {
- renderer.pushTransform().scale(scale).rotateZ(bodyYaw);
- body.render(renderer, this);
- head.render(renderer, this);
- leftForeLeg.render(renderer, this);
- rightForeLeg.render(renderer, this);
- leftHindLeg.render(renderer, this);
- rightHindLeg.render(renderer, this);
- renderer.popTransform();
-
- accountForVelocity();
- evaluateAngles();
- }
-
- private void evaluateAngles() {
- float globalYaw = normalizeAngle(getData().getYaw());
-
- if (Float.isNaN(bodyYaw)) {
- bodyYaw = globalYaw;
- headYaw = 0;
- } else {
- headYaw = normalizeAngle(globalYaw - bodyYaw);
-
- if (headYaw > +head.maxYaw) {
- bodyYaw += headYaw - +head.maxYaw;
- headYaw = +head.maxYaw;
- } else if (headYaw < -head.maxYaw) {
- bodyYaw += headYaw - -head.maxYaw;
- headYaw = -head.maxYaw;
- }
- }
-
- bodyYaw = normalizeAngle(bodyYaw);
-
- headPitch = Glm.clamp(
- getData().getPitch(),
- -head.maxPitch, head.maxPitch
- );
- }
-
- private void accountForVelocity() {
- Vec3 horizontal = Vectors.grab3();
- horizontal.set(getData().getVelocity());
- horizontal.z = 0;
-
- velocity = horizontal.length();
-
- evaluateVelocityCoeff();
-
- // TODO switch to world time
- walkingAnimationParameter += velocity * GraphicsInterface.getFrameLength() * 1000;
-
- bodyYaw += velocityCoeff * normalizeAngle(
- (float) (atan2(horizontal.y, horizontal.x) - bodyYaw)
- ) * min(1, GraphicsInterface.getFrameLength() * 10);
- Vectors.release(horizontal);
+ protected void renderBodyParts(ShapeRenderHelper renderer) {
+ super.renderBodyParts(renderer);
+ this.leftForeLeg.render(renderer, this);
+ this.rightForeLeg.render(renderer, this);
+ this.leftHindLeg.render(renderer, this);
+ this.rightHindLeg.render(renderer, this);
}
- private void evaluateVelocityCoeff() {
- if (velocity * velocityCutoff > 1) {
- velocityCoeff = 1;
- } else {
- velocityCoeff = velocity * velocityCutoff;
- velocityCoeff *= velocityCoeff;
- }
+ public float getWalkingSwing() {
+ return walkingSwing;
}
- @Override
- public void getViewPoint(Vec3 output) {
- Mat4 m = Matrices.grab4();
- Vec4 v = Vectors.grab4();
-
- m.identity()
- .scale(scale)
- .rotateZ(bodyYaw)
- .translate(head.getTranslation())
- .rotateZ(headYaw)
- .rotateY(headPitch);
-
- v.set(head.getViewPoint(), 1);
- m.mul(v);
-
- output.set(v.x, v.y, v.z);
-
- Vectors.release(v);
- Matrices.release(m);
+ public QuadripedModel setWalkingSwing(float walkingSwing) {
+ this.walkingSwing = walkingSwing;
+ return this;
}
}
diff --git a/src/main/java/ru/windcorp/progressia/common/Units.java b/src/main/java/ru/windcorp/progressia/common/Units.java
new file mode 100644
index 0000000..0c8348a
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/Units.java
@@ -0,0 +1,56 @@
+package ru.windcorp.progressia.common;
+
+public class Units {
+
+ // Base units
+ // We're SI.
+ public static final float METERS = 1;
+ public static final float KILOGRAMS = 1;
+ public static final float SECONDS = 1;
+
+ // Length
+ public static final float CENTIMETERS = METERS / 100;
+ public static final float MILLIMETERS = METERS / 1000;
+ public static final float KILOMETERS = METERS * 1000;
+
+ // Surface
+ public static final float SQUARE_CENTIMETERS = CENTIMETERS * CENTIMETERS;
+ public static final float SQUARE_METERS = METERS * METERS;
+ public static final float SQUARE_MILLIMETERS = MILLIMETERS * MILLIMETERS;
+ public static final float SQUARE_KILOMETERS = KILOMETERS * KILOMETERS;
+
+ // Volume
+ public static final float CUBIC_CENTIMETERS = CENTIMETERS * CENTIMETERS * CENTIMETERS;
+ public static final float CUBIC_METERS = METERS * METERS * METERS;
+ public static final float CUBIC_MILLIMETERS = MILLIMETERS * MILLIMETERS * MILLIMETERS;
+ public static final float CUBIC_KILOMETERS = KILOMETERS * KILOMETERS * KILOMETERS;
+
+ // Mass
+ public static final float GRAMS = KILOGRAMS / 1000;
+ public static final float TONNES = KILOGRAMS * 1000;
+
+ // Density
+ public static final float KILOGRAMS_PER_CUBIC_METER = KILOGRAMS / CUBIC_METERS;
+ public static final float GRAMS_PER_CUBIC_CENTIMETER = GRAMS / CUBIC_CENTIMETERS;
+
+ // Time
+ public static final float MILLISECONDS = SECONDS / 1000;
+ public static final float MINUTES = SECONDS * 60;
+ public static final float HOURS = MINUTES * 60;
+ public static final float DAYS = HOURS * 24;
+
+ // Frequency
+ public static final float HERTZ = 1 / SECONDS;
+ public static final float KILOHERTZ = HERTZ * 1000;
+
+ // Velocity
+ public static final float METERS_PER_SECOND = METERS / SECONDS;
+ public static final float KILOMETERS_PER_HOUR = KILOMETERS / HOURS;
+
+ // Acceleration
+ public static final float METERS_PER_SECOND_SQUARED = METERS_PER_SECOND / SECONDS;
+
+ // Force
+ public static final float NEWTONS = METERS_PER_SECOND_SQUARED * KILOGRAMS;
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/collision/AABB.java b/src/main/java/ru/windcorp/progressia/common/collision/AABB.java
index 7188e33..e141673 100644
--- a/src/main/java/ru/windcorp/progressia/common/collision/AABB.java
+++ b/src/main/java/ru/windcorp/progressia/common/collision/AABB.java
@@ -1,93 +1,113 @@
package ru.windcorp.progressia.common.collision;
-import java.util.Collection;
-import java.util.Map;
-
import glm.vec._3.Vec3;
-import ru.windcorp.progressia.common.world.block.BlockFace;
-public class AABB implements CollisionModel {
+/**
+ * An implementation of an
+ * Axis-Aligned Bounding Box.
+ * @author javapony
+ */
+public class AABB implements AABBoid {
+
+ private class AABBWallImpl implements Wall {
+
+ private final Vec3 originOffset = new Vec3();
+ private final Vec3 widthSelector = new Vec3();
+ private final Vec3 heightSelector = new Vec3();
- private final Map faces = BlockFace.mapToFaces(
- new CollisionWall(-0.5f, -0.5f, -0.5f, +1, 0, 0, 0, 0, +1),
- new CollisionWall(+0.5f, -0.5f, -0.5f, 0, +1, 0, 0, 0, +1),
- new CollisionWall(+0.5f, +0.5f, -0.5f, -1, 0, 0, 0, 0, +1),
- new CollisionWall(-0.5f, +0.5f, -0.5f, 0, -1, 0, 0, 0, +1),
-
- new CollisionWall(-0.5f, -0.5f, +0.5f, +1, 0, 0, 0, +1, 0),
- new CollisionWall(-0.5f, -0.5f, -0.5f, 0, +1, 0, +1, 0, 0)
- );
+ public AABBWallImpl(
+ float ox, float oy, float oz,
+ float wx, float wy, float wz,
+ float hx, float hy, float hz
+ ) {
+ this.originOffset.set(ox, oy, oz);
+ this.widthSelector.set(wx, wy, wz);
+ this.heightSelector.set(hx, hy, hz);
+ }
+
+ @Override
+ public void getOrigin(Vec3 output) {
+ output.set(originOffset).mul(AABB.this.getSize()).add(AABB.this.getOrigin());
+ }
+
+ @Override
+ public void getWidth(Vec3 output) {
+ output.set(AABB.this.getSize()).mul(widthSelector);
+ }
+
+ @Override
+ public void getHeight(Vec3 output) {
+ output.set(AABB.this.getSize()).mul(heightSelector);
+ }
+
+ }
+
+ public static final AABB UNIT_CUBE = new AABB(0, 0, 0, 1, 1, 1);
+
+ private final Wall[] walls = new Wall[] {
+ new AABBWallImpl(-0.5f, -0.5f, +0.5f, +1, 0, 0, 0, +1, 0), // Top
+ new AABBWallImpl(-0.5f, -0.5f, -0.5f, 0, +1, 0, +1, 0, 0), // Bottom
+ new AABBWallImpl(+0.5f, -0.5f, -0.5f, 0, +1, 0, 0, 0, +1), // North
+ new AABBWallImpl(-0.5f, +0.5f, -0.5f, 0, -1, 0, 0, 0, +1), // South
+ new AABBWallImpl(+0.5f, +0.5f, -0.5f, -1, 0, 0, 0, 0, +1), // West
+ new AABBWallImpl(-0.5f, -0.5f, -0.5f, +1, 0, 0, 0, 0, +1) // East
+ };
private final Vec3 origin = new Vec3();
private final Vec3 size = new Vec3();
public AABB(Vec3 origin, Vec3 size) {
- this.origin.set(origin);
- this.size.set(size);
-
- for (CollisionWall wall : getFaces()) {
- wall.moveOrigin(origin);
- wall.getWidth().mul(size);
- wall.getHeight().mul(size);
- }
+ this(origin.x, origin.y, origin.z, size.x, size.y, size.z);
}
public AABB(
- float ox, float oy, float oz,
+ float ox, float oy, float oz,
float xSize, float ySize, float zSize
) {
this.origin.set(ox, oy, oz);
this.size.set(xSize, ySize, zSize);
-
- for (CollisionWall wall : getFaces()) {
- wall.moveOrigin(ox, oy, oz);
- wall.getWidth().mul(xSize, ySize, zSize);
- wall.getHeight().mul(xSize, ySize, zSize);
- }
- }
-
- public Collection getFaces() {
- return faces.values();
}
public Vec3 getOrigin() {
return origin;
}
+
+ @Override
+ public void getOrigin(Vec3 output) {
+ output.set(origin);
+ }
@Override
public void setOrigin(Vec3 origin) {
- for (CollisionWall wall : getFaces()) {
- wall.getOrigin().sub(this.origin).add(origin);
- }
-
this.origin.set(origin);
}
@Override
public void moveOrigin(Vec3 displacement) {
- for (CollisionWall wall : getFaces()) {
- wall.getOrigin().add(displacement);
- }
-
this.origin.add(displacement);
}
public Vec3 getSize() {
return size;
}
+
+ @Override
+ public void getSize(Vec3 output) {
+ output.set(size);
+ }
public void setSize(Vec3 size) {
setSize(size.x, size.y, size.z);
}
public void setSize(float xSize, float ySize, float zSize) {
- for (CollisionWall wall : getFaces()) {
- wall.getWidth().div(this.size).mul(xSize, ySize, zSize);
- wall.getHeight().div(this.size).mul(xSize, ySize, zSize);
- wall.getOrigin().sub(getOrigin()).div(this.size).mul(xSize, ySize, zSize).add(getOrigin());
- }
-
this.size.set(xSize, ySize, zSize);
}
+
+ @Override
+ public Wall getWall(int faceId) {
+ // No, we don't support Apple.
+ return walls[faceId];
+ }
}
diff --git a/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java b/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java
new file mode 100644
index 0000000..6e1d384
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java
@@ -0,0 +1,17 @@
+package ru.windcorp.progressia.common.collision;
+
+import glm.vec._3.Vec3;
+import ru.windcorp.progressia.common.world.block.BlockFace;
+
+public interface AABBoid extends CollisionModel {
+
+ void getOrigin(Vec3 output);
+ void getSize(Vec3 output);
+
+ default Wall getWall(BlockFace face) {
+ return getWall(face.getId());
+ }
+
+ Wall getWall(int faceId);
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/collision/CollisionClock.java b/src/main/java/ru/windcorp/progressia/common/collision/CollisionClock.java
deleted file mode 100644
index cf42614..0000000
--- a/src/main/java/ru/windcorp/progressia/common/collision/CollisionClock.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package ru.windcorp.progressia.common.collision;
-
-public interface CollisionClock {
-
- float getTime();
- void advanceTime(float change);
-
-}
diff --git a/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java b/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java
new file mode 100644
index 0000000..eda8e47
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java
@@ -0,0 +1,79 @@
+package ru.windcorp.progressia.common.collision;
+
+import java.util.function.Consumer;
+
+import glm.vec._3.Vec3;
+import glm.vec._3.i.Vec3i;
+import ru.windcorp.progressia.common.util.Vectors;
+
+import static java.lang.Math.*;
+
+public class CollisionPathComputer {
+
+ public static void forEveryBlockInCollisionPath(
+ Collideable coll,
+ float maxTime,
+ Consumer action
+ ) {
+ Vec3 displacement = Vectors.grab3();
+ coll.getCollideableVelocity(displacement);
+ displacement.mul(maxTime);
+
+ handleModel(coll.getCollisionModel(), displacement, action);
+
+ Vectors.release(displacement);
+ }
+
+ private static void handleModel(
+ CollisionModel model,
+ Vec3 displacement,
+ Consumer action
+ ) {
+ if (model instanceof CompoundCollisionModel) {
+ for (CollisionModel subModel : ((CompoundCollisionModel) model).getModels()) {
+ handleModel(subModel, displacement, action);
+ }
+ } else if (model instanceof AABBoid) {
+ handleAABBoid((AABBoid) model, displacement, action);
+ } else {
+ throw new RuntimeException("not supported");
+ }
+ }
+
+ private static void handleAABBoid(AABBoid model, Vec3 displacement, Consumer action) {
+ Vec3 size = Vectors.grab3();
+ Vec3 origin = Vectors.grab3();
+
+ model.getOrigin(origin);
+ model.getSize(size);
+
+ origin.mul(2).sub(size).div(2); // Subtract 0.5*size
+
+ Vec3i pos = Vectors.grab3i();
+
+ for (
+ pos.x = (int) floor(origin.x + min(0, size.x) + min(0, displacement.x));
+ pos.x <= (int) ceil(origin.x + max(0, size.x) + max(0, displacement.x));
+ pos.x += 1
+ ) {
+ for (
+ pos.y = (int) floor(origin.y + min(0, size.y) + min(0, displacement.y));
+ pos.y <= (int) ceil(origin.y + max(0, size.y) + max(0, displacement.y));
+ pos.y += 1
+ ) {
+ for (
+ pos.z = (int) floor(origin.z + min(0, size.z) + min(0, displacement.z));
+ pos.z <= (int) ceil(origin.z + max(0, size.z) + max(0, displacement.z));
+ pos.z += 1
+ ) {
+ action.accept(pos);
+ }
+ }
+ }
+
+ Vectors.release(origin);
+ Vectors.release(size);
+ Vectors.release(pos);
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/collision/CollisionWall.java b/src/main/java/ru/windcorp/progressia/common/collision/CollisionWall.java
deleted file mode 100644
index 8963ffd..0000000
--- a/src/main/java/ru/windcorp/progressia/common/collision/CollisionWall.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package ru.windcorp.progressia.common.collision;
-
-import glm.vec._3.Vec3;
-
-public class CollisionWall {
-
- private final Vec3 origin = new Vec3();
- private final Vec3 width = new Vec3();
- private final Vec3 height = new Vec3();
-
- public CollisionWall(Vec3 origin, Vec3 width, Vec3 height) {
- this.origin.set(origin);
- this.width.set(width);
- this.height.set(height);
- }
-
- public CollisionWall(
- float ox, float oy, float oz,
- float wx, float wy, float wz,
- float hx, float hy, float hz
- ) {
- this.origin.set(ox, oy, oz);
- this.width.set(wx, wy, wz);
- this.height.set(hx, hy, hz);
- }
-
- public Vec3 getOrigin() {
- return origin;
- }
-
- public Vec3 getWidth() {
- return width;
- }
-
- public Vec3 getHeight() {
- return height;
- }
-
- public void setOrigin(Vec3 origin) {
- setOrigin(origin.x, origin.y, origin.z);
- }
-
- public void setOrigin(float x, float y, float z) {
- this.origin.set(x, y, z);
- }
-
- public void moveOrigin(Vec3 displacement) {
- moveOrigin(displacement.x, displacement.y, displacement.z);
- }
-
- public void moveOrigin(float dx, float dy, float dz) {
- this.origin.add(dx, dy, dz);
- }
-
-}
diff --git a/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java b/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java
index 2cf4572..ab5e766 100644
--- a/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java
+++ b/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java
@@ -8,9 +8,9 @@ import glm.vec._3.Vec3;
public class CompoundCollisionModel implements CollisionModel {
- private final Collection models;
+ private final Collection extends CollisionModel> models;
- public CompoundCollisionModel(Collection models) {
+ public CompoundCollisionModel(Collection extends CollisionModel> models) {
this.models = models;
}
@@ -18,7 +18,7 @@ public class CompoundCollisionModel implements CollisionModel {
this(ImmutableList.copyOf(models));
}
- public Collection getModels() {
+ public Collection extends CollisionModel> getModels() {
return models;
}
diff --git a/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java b/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java
new file mode 100644
index 0000000..a22c330
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java
@@ -0,0 +1,105 @@
+package ru.windcorp.progressia.common.collision;
+
+import glm.vec._3.Vec3;
+import ru.windcorp.progressia.common.util.Vectors;
+import ru.windcorp.progressia.common.world.block.BlockFace;
+
+public class TranslatedAABB implements AABBoid {
+
+ private class TranslatedAABBWall implements Wall {
+ private final int id;
+
+ public TranslatedAABBWall(int id) {
+ this.id = id;
+ }
+
+ @Override
+ public void getOrigin(Vec3 output) {
+ parent.getWall(id).getOrigin(output);
+ output.add(translation);
+ }
+
+ @Override
+ public void getWidth(Vec3 output) {
+ parent.getWall(id).getWidth(output);
+ }
+
+ @Override
+ public void getHeight(Vec3 output) {
+ parent.getWall(id).getHeight(output);
+ }
+ }
+
+ private AABBoid parent;
+ private final Vec3 translation = new Vec3();
+
+ private final TranslatedAABBWall[] walls = new TranslatedAABBWall[BlockFace.BLOCK_FACE_COUNT];
+
+ {
+ for (int id = 0; id < walls.length; ++id) {
+ walls[id] = new TranslatedAABBWall(id);
+ }
+ }
+
+ public TranslatedAABB(AABBoid parent, float tx, float ty, float tz) {
+ setParent(parent);
+ setTranslation(tx, ty, tz);
+ }
+
+ public TranslatedAABB(AABBoid parent, Vec3 translation) {
+ this(parent, translation.x, translation.y, translation.z);
+ }
+
+ public TranslatedAABB() {
+ this(null, 0, 0, 0);
+ }
+
+ @Override
+ public void setOrigin(Vec3 origin) {
+ Vec3 v = Vectors.grab3().set(origin).sub(translation);
+ parent.setOrigin(v);
+ Vectors.release(v);
+ }
+
+ @Override
+ public void moveOrigin(Vec3 displacement) {
+ parent.moveOrigin(displacement);
+ }
+
+ @Override
+ public void getOrigin(Vec3 output) {
+ parent.getOrigin(output);
+ output.add(translation);
+ }
+
+ @Override
+ public void getSize(Vec3 output) {
+ parent.getSize(output);
+ }
+
+ @Override
+ public Wall getWall(int faceId) {
+ return walls[faceId];
+ }
+
+ public AABBoid getParent() {
+ return parent;
+ }
+
+ public void setParent(AABBoid parent) {
+ this.parent = parent;
+ }
+
+ public Vec3 getTranslation() {
+ return translation;
+ }
+
+ public void setTranslation(Vec3 translation) {
+ setTranslation(translation.x, translation.y, translation.z);
+ }
+
+ public void setTranslation(float tx, float ty, float tz) {
+ this.translation.set(tx, ty, tz);
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/collision/Wall.java b/src/main/java/ru/windcorp/progressia/common/collision/Wall.java
new file mode 100644
index 0000000..9549f04
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/collision/Wall.java
@@ -0,0 +1,12 @@
+package ru.windcorp.progressia.common.collision;
+
+import glm.vec._3.Vec3;
+
+public interface Wall {
+
+ void getOrigin(Vec3 output);
+
+ void getWidth(Vec3 output);
+ void getHeight(Vec3 output);
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java b/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java
new file mode 100644
index 0000000..ebf2c0b
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java
@@ -0,0 +1,94 @@
+package ru.windcorp.progressia.common.collision;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import glm.vec._3.Vec3;
+import glm.vec._3.i.Vec3i;
+import ru.windcorp.progressia.common.util.LowOverheadCache;
+import ru.windcorp.progressia.common.world.WorldData;
+
+public class WorldCollisionHelper {
+
+ private final Collideable collideable = new Collideable() {
+ @Override
+ public boolean onCollision(Collideable other) {
+ return false;
+ }
+
+ @Override
+ public void moveAsCollideable(Vec3 displacement) {
+ // Ignore
+ assert displacement.length() < 1e-3f;
+ }
+
+ @Override
+ public CollisionModel getCollisionModel() {
+ return WorldCollisionHelper.this.model;
+ }
+
+ @Override
+ public float getCollisionMass() {
+ return Float.POSITIVE_INFINITY;
+ }
+
+ @Override
+ public void getCollideableVelocity(Vec3 output) {
+ output.set(0);
+ }
+
+ @Override
+ public void changeVelocityOnCollision(Vec3 velocityChange) {
+ // Ignore
+ assert velocityChange.length() < 1e-3f;
+ }
+ };
+
+ private final Collection activeBlockModels = new ArrayList<>();
+ private final CollisionModel model = new CompoundCollisionModel(activeBlockModels);
+ private final LowOverheadCache blockModelCache = new LowOverheadCache<>(TranslatedAABB::new);
+
+ /**
+ * Changes the state of this helper's {@link #getCollideable()} so it is ready to adequately handle
+ * collisions with the {@code collideable} that might happen in the next {@code maxTime} seconds.
+ * This helper is only valid for checking collisions with the given Collideable and only within
+ * the given time limit.
+ * @param collideable the {@link Collideable} that collisions will be checked against
+ * @param maxTime maximum collision time
+ */
+ public void tuneToCollideable(WorldData world, Collideable collideable, float maxTime) {
+ activeBlockModels.forEach(blockModelCache::release);
+ activeBlockModels.clear();
+ CollisionPathComputer.forEveryBlockInCollisionPath(
+ collideable,
+ maxTime,
+ v -> addModel(world.getCollisionModelOfBlock(v), v)
+ );
+ }
+
+ private void addModel(CollisionModel model, Vec3i pos) {
+ if (model == null) {
+ // Ignore
+ } else if (model instanceof AABBoid) {
+ addAABBoidModel((AABBoid) model, pos);
+ } else if (model instanceof CompoundCollisionModel) {
+ for (CollisionModel subModel : ((CompoundCollisionModel) model).getModels()) {
+ addModel(subModel, pos);
+ }
+ } else {
+ throw new RuntimeException("not supported");
+ }
+ }
+
+ private void addAABBoidModel(AABBoid model, Vec3i pos) {
+ TranslatedAABB translator = blockModelCache.grab();
+ translator.setParent(model);
+ translator.setTranslation(pos.x, pos.y, pos.z);
+ activeBlockModels.add(translator);
+ }
+
+ public Collideable getCollideable() {
+ return collideable;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBWithAABBCollider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java
similarity index 78%
rename from src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBWithAABBCollider.java
rename to src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java
index 7b961e1..f440761 100644
--- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBWithAABBCollider.java
+++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java
@@ -2,26 +2,25 @@ package ru.windcorp.progressia.common.collision.colliders;
import glm.mat._3.Mat3;
import glm.vec._3.Vec3;
-import ru.windcorp.progressia.common.collision.AABB;
-import ru.windcorp.progressia.common.collision.Collideable;
-import ru.windcorp.progressia.common.collision.CollisionWall;
+import ru.windcorp.progressia.common.collision.*;
import ru.windcorp.progressia.common.collision.colliders.Collider.ColliderWorkspace;
import ru.windcorp.progressia.common.collision.colliders.Collider.Collision;
import ru.windcorp.progressia.common.util.Matrices;
import ru.windcorp.progressia.common.util.Vectors;
+import ru.windcorp.progressia.common.world.block.BlockFace;
-class AABBWithAABBCollider {
+class AABBoidCollider {
static Collider.Collision computeModelCollision(
Collideable aBody, Collideable bBody,
- AABB aModel, AABB bModel,
+ AABBoid aModel, AABBoid bModel,
float tickLength,
ColliderWorkspace workspace
) {
Collideable obstacleBody = bBody;
Collideable colliderBody = aBody;
- AABB obstacleModel = bModel;
- AABB colliderModel = aModel;
+ AABBoid obstacleModel = bModel;
+ AABBoid colliderModel = aModel;
Collision result = null;
@@ -32,7 +31,8 @@ class AABBWithAABBCollider {
computeCollisionVelocity(collisionVelocity, obstacleBody, colliderBody);
// For every wall of collision space
- for (CollisionWall wall : originCollisionSpace.getFaces()) {
+ for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) {
+ Wall wall = originCollisionSpace.getWall(i);
Collision collision = computeWallCollision(
wall, colliderModel,
@@ -80,12 +80,21 @@ class AABBWithAABBCollider {
Vectors.release(colliderVelocity);
}
- private static AABB createOriginCollisionSpace(AABB obstacle, AABB collider, AABB output) {
- output.setOrigin(obstacle.getOrigin());
+ private static AABB createOriginCollisionSpace(AABBoid obstacle, AABBoid collider, AABB output) {
+ Vec3 obstacleOrigin = Vectors.grab3();
+ Vec3 obstacleSize = Vectors.grab3();
+ Vec3 colliderSize = Vectors.grab3();
- Vec3 size = Vectors.grab3().set(obstacle.getSize()).add(collider.getSize());
- output.setSize(size);
- Vectors.release(size);
+ obstacle.getOrigin(obstacleOrigin);
+ output.setOrigin(obstacleOrigin);
+
+ obstacle.getSize(obstacleSize);
+ collider.getSize(colliderSize);
+ output.setSize(obstacleSize.add(colliderSize));
+
+ Vectors.release(obstacleOrigin);
+ Vectors.release(obstacleSize);
+ Vectors.release(colliderSize);
return output;
}
@@ -134,27 +143,34 @@ class AABBWithAABBCollider {
* If all conditions are satisfied, then the moment of impact is t0 + t.
*/
private static Collision computeWallCollision(
- CollisionWall obstacleWall,
- AABB colliderModel,
+ Wall obstacleWall,
+ AABBoid colliderModel,
Vec3 collisionVelocity,
float tickLength, ColliderWorkspace workspace,
Collideable aBody, Collideable bBody
) {
- Vec3 w = obstacleWall.getWidth();
- Vec3 h = obstacleWall.getHeight();
+ Vec3 w = Vectors.grab3();
+ Vec3 h = Vectors.grab3();
Vec3 v = Vectors.grab3();
Mat3 m = Matrices.grab3(); // The matrix [w h -v]
Vec3 r = Vectors.grab3();
+ Vec3 r_line = Vectors.grab3();
+ Vec3 r_wall = Vectors.grab3();
Vec3 xyt = Vectors.grab3();
try {
+ obstacleWall.getWidth(w);
+ obstacleWall.getHeight(h);
+
v.set(collisionVelocity);
if (isExiting(v, w, h)) {
return null;
}
- r.set(colliderModel.getOrigin()).sub(obstacleWall.getOrigin());
+ obstacleWall.getOrigin(r_wall);
+ colliderModel.getOrigin(r_line);
+ r.set(r_line).sub(r_wall);
m.c0(w).c1(h).c2(v.negate());
if (Math.abs(m.det()) < 1e-6) {
@@ -179,9 +195,13 @@ class AABBWithAABBCollider {
return workspace.grab().set(aBody, bBody, obstacleWall, t);
} finally {
+ Vectors.release(w);
+ Vectors.release(h);
Vectors.release(v);
- Vectors.release(r);
Matrices.release(m);
+ Vectors.release(r);
+ Vectors.release(r_line);
+ Vectors.release(r_wall);
Vectors.release(xyt);
}
}
@@ -193,6 +213,6 @@ class AABBWithAABBCollider {
return result;
}
- private AABBWithAABBCollider() {}
+ private AABBoidCollider() {}
}
diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java
index 74bcc2c..8fdbc90 100644
--- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java
+++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java
@@ -6,14 +6,10 @@ import java.util.List;
import org.apache.logging.log4j.LogManager;
import glm.vec._3.Vec3;
-import ru.windcorp.progressia.common.collision.AABB;
-import ru.windcorp.progressia.common.collision.Collideable;
-import ru.windcorp.progressia.common.collision.CollisionClock;
-import ru.windcorp.progressia.common.collision.CollisionModel;
-import ru.windcorp.progressia.common.collision.CollisionWall;
-import ru.windcorp.progressia.common.collision.CompoundCollisionModel;
+import ru.windcorp.progressia.common.collision.*;
import ru.windcorp.progressia.common.util.LowOverheadCache;
import ru.windcorp.progressia.common.util.Vectors;
+import ru.windcorp.progressia.common.world.WorldData;
public class Collider {
@@ -21,7 +17,7 @@ public class Collider {
public static void performCollisions(
List extends Collideable> colls,
- CollisionClock clock,
+ WorldData world,
float tickLength,
ColliderWorkspace workspace
) {
@@ -37,12 +33,12 @@ public class Collider {
return;
}
- Collision firstCollision = getFirstCollision(colls, tickLength, workspace);
+ Collision firstCollision = getFirstCollision(colls, tickLength, world, workspace);
if (firstCollision == null) {
break;
} else {
- collide(firstCollision, colls, clock, tickLength, workspace);
+ collide(firstCollision, colls, world, tickLength, workspace);
workspace.release(firstCollision);
collisionCount++;
@@ -50,45 +46,49 @@ public class Collider {
}
}
- advanceTime(colls, clock, tickLength);
+ advanceTime(colls, world, tickLength);
}
private static Collision getFirstCollision(
List extends Collideable> colls,
float tickLength,
+ WorldData world,
ColliderWorkspace workspace
) {
Collision result = null;
+ Collideable worldColl = workspace.worldCollisionHelper.getCollideable();
// For every pair of colls
for (int i = 0; i < colls.size(); ++i) {
Collideable a = colls.get(i);
+ tuneWorldCollisionHelper(a, tickLength, world, workspace);
+
+ result = workspace.updateLatestCollision(
+ result,
+ getCollision(a, worldColl, tickLength, workspace)
+ );
+
for (int j = i + 1; j < colls.size(); ++j) {
Collideable b = colls.get(j);
-
Collision collision = getCollision(a, b, tickLength, workspace);
-
- // Update result
- if (collision != null) {
- Collision second;
-
- if (result == null || collision.time < result.time) {
- second = result;
- result = collision;
- } else {
- second = collision;
- }
-
- // Release Collision that is no longer used
- if (second != null) workspace.release(second);
- }
+ result = workspace.updateLatestCollision(result, collision);
}
}
return result;
}
+ private static void tuneWorldCollisionHelper(
+ Collideable coll,
+ float tickLength,
+ WorldData world,
+ ColliderWorkspace workspace
+ ) {
+ WorldCollisionHelper wch = workspace.worldCollisionHelper;
+ wch.tuneToCollideable(world, coll, tickLength);
+ }
+
static Collision getCollision(
Collideable a,
Collideable b,
@@ -108,10 +108,10 @@ public class Collider {
float tickLength,
ColliderWorkspace workspace
) {
- if (aModel instanceof AABB && bModel instanceof AABB) {
- return AABBWithAABBCollider.computeModelCollision(
+ if (aModel instanceof AABBoid && bModel instanceof AABBoid) {
+ return AABBoidCollider.computeModelCollision(
aBody, bBody,
- (AABB) aModel, (AABB) bModel,
+ (AABBoid) aModel, (AABBoid) bModel,
tickLength,
workspace
);
@@ -144,11 +144,11 @@ public class Collider {
Collision collision,
Collection extends Collideable> colls,
- CollisionClock clock,
+ WorldData world,
float tickLength,
ColliderWorkspace workspace
) {
- advanceTime(colls, clock, collision.time);
+ advanceTime(colls, world, collision.time);
boolean doNotHandle = false;
@@ -237,7 +237,7 @@ public class Collider {
Vec3 du_a = Vectors.grab3();
Vec3 du_b = Vectors.grab3();
- n.set(collision.wall.getWidth()).cross(collision.wall.getHeight()).normalize();
+ n.set(collision.wallWidth).cross(collision.wallHeight).normalize();
collision.a.getCollideableVelocity(v_a);
collision.b.getCollideableVelocity(v_b);
@@ -306,10 +306,10 @@ public class Collider {
private static void advanceTime(
Collection extends Collideable> colls,
- CollisionClock clock,
+ WorldData world,
float step
) {
- clock.advanceTime(step);
+ world.advanceTime(step);
Vec3 tmp = Vectors.grab3();
@@ -328,6 +328,8 @@ public class Collider {
new LowOverheadCache<>(Collision::new);
AABB dummyAABB = new AABB(0, 0, 0, 1, 1, 1);
+
+ WorldCollisionHelper worldCollisionHelper = new WorldCollisionHelper();
Collision grab() {
return collisionCache.grab();
@@ -337,12 +339,35 @@ public class Collider {
collisionCache.release(object);
}
+ Collision updateLatestCollision(Collision a, Collision b) {
+ if (a == null) {
+ return b; // may be null
+ } else if (b == null) {
+ return a;
+ }
+
+ Collision first, second;
+
+ if (a.time > b.time) {
+ first = b;
+ second = a;
+ } else {
+ first = a;
+ second = b;
+ }
+
+ release(second);
+ return first;
+ }
+
}
static class Collision {
public Collideable a;
public Collideable b;
- public final CollisionWall wall = new CollisionWall(0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ public final Vec3 wallWidth = new Vec3();
+ public final Vec3 wallHeight = new Vec3();
/**
* Time offset from the start of the tick.
@@ -350,12 +375,15 @@ public class Collider {
*/
public float time;
- public Collision set(Collideable a, Collideable b, CollisionWall wall, float time) {
+ public Collision set(
+ Collideable a, Collideable b,
+ Wall wall,
+ float time
+ ) {
this.a = a;
this.b = b;
- this.wall.getOrigin().set(wall.getOrigin());
- this.wall.getWidth().set(wall.getWidth());
- this.wall.getHeight().set(wall.getHeight());
+ wall.getWidth(wallWidth);
+ wall.getHeight(wallHeight);
this.time = time;
return this;
diff --git a/src/main/java/ru/windcorp/progressia/common/util/Vectors.java b/src/main/java/ru/windcorp/progressia/common/util/Vectors.java
index 489bf13..7cc3623 100644
--- a/src/main/java/ru/windcorp/progressia/common/util/Vectors.java
+++ b/src/main/java/ru/windcorp/progressia/common/util/Vectors.java
@@ -30,6 +30,19 @@ import glm.vec._4.i.Vec4i;
*/
public class Vectors {
+ public static final Vec2 ZERO_2 = new Vec2 (0, 0);
+ public static final Vec2i ZERO_2i = new Vec2i(0, 0);
+ public static final Vec3 ZERO_3 = new Vec3 (0, 0, 0);
+ public static final Vec3i ZERO_3i = new Vec3i(0, 0, 0);
+ public static final Vec4 ZERO_4 = new Vec4 (0, 0, 0, 0);
+ public static final Vec4i ZERO_4i = new Vec4i(0, 0, 0, 0);
+ public static final Vec2 UNIT_2 = new Vec2 (1, 1);
+ public static final Vec2i UNIT_2i = new Vec2i(1, 1);
+ public static final Vec3 UNIT_3 = new Vec3 (1, 1, 1);
+ public static final Vec3i UNIT_3i = new Vec3i(1, 1, 1);
+ public static final Vec4 UNIT_4 = new Vec4 (1, 1, 1, 1);
+ public static final Vec4i UNIT_4i = new Vec4i(1, 1, 1, 1);
+
private static final LowOverheadCache VEC3IS =
new LowOverheadCache<>(Vec3i::new);
diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java
index 18d44b0..f25ac0a 100644
--- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java
+++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java
@@ -80,7 +80,7 @@ public class ChunkData {
TileData flowers = TileDataRegistry.getInstance().get("Test:YellowFlowers");
TileData sand = TileDataRegistry.getInstance().get("Test:Sand");
- Vec3i aPoint = new Vec3i(5, 0, BLOCKS_PER_CHUNK + BLOCKS_PER_CHUNK/2);
+ Vec3i aPoint = new Vec3i(5, 0, BLOCKS_PER_CHUNK + BLOCKS_PER_CHUNK/2).sub(getPosition());
Vec3i pos = new Vec3i();
for (int x = 0; x < BLOCKS_PER_CHUNK; ++x) {
@@ -132,18 +132,28 @@ public class ChunkData {
}
}
- EntityData javapony = EntityDataRegistry.getInstance().create("Test:Javapony");
- javapony.setEntityId(0x42);
- javapony.setPosition(new Vec3(-6, -6, 20));
- javapony.setDirection(new Vec2(
- (float) Math.toRadians(40), (float) Math.toRadians(45)
- ));
- getEntities().add(javapony);
-
- EntityData statie = EntityDataRegistry.getInstance().create("Test:Statie");
- statie.setEntityId(0xDEADBEEF);
- statie.setPosition(new Vec3(0, 15, 16));
- getEntities().add(statie);
+ if (!getPosition().any()) {
+// EntityData javapony = EntityDataRegistry.getInstance().create("Test:Javapony");
+// javapony.setEntityId(0x42);
+// javapony.setPosition(new Vec3(-6, -6, 20));
+// javapony.setDirection(new Vec2(
+// (float) Math.toRadians(40), (float) Math.toRadians(45)
+// ));
+// getEntities().add(javapony);
+
+ EntityData player = EntityDataRegistry.getInstance().create("Test:Player");
+ player.setEntityId(0x42);
+ player.setPosition(new Vec3(-6, -6, 20));
+ player.setDirection(new Vec2(
+ (float) Math.toRadians(40), (float) Math.toRadians(45)
+ ));
+ getEntities().add(player);
+
+ EntityData statie = EntityDataRegistry.getInstance().create("Test:Statie");
+ statie.setEntityId(0xDEADBEEF);
+ statie.setPosition(new Vec3(0, 15, 16));
+ getEntities().add(statie);
+ }
}
public BlockData getBlock(Vec3i posInChunk) {
diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java
index 6440709..6584884 100644
--- a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java
+++ b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java
@@ -24,8 +24,10 @@ import glm.vec._3.i.Vec3i;
import gnu.trove.impl.sync.TSynchronizedLongObjectMap;
import gnu.trove.map.TLongObjectMap;
import gnu.trove.map.hash.TLongObjectHashMap;
+import ru.windcorp.progressia.common.collision.CollisionModel;
import ru.windcorp.progressia.common.util.CoordinatePacker;
import ru.windcorp.progressia.common.util.Vectors;
+import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.entity.EntityData;
public class WorldData {
@@ -42,6 +44,8 @@ public class WorldData {
private final Collection entities =
Collections.unmodifiableCollection(entitiesById.valueCollection());
+ private float time = 0;
+
public WorldData() {
final int size = 1;
@@ -96,4 +100,25 @@ public class WorldData {
return entities;
}
+ public float getTime() {
+ return time;
+ }
+
+ public void advanceTime(float change) {
+ this.time += change;
+ }
+
+ public CollisionModel getCollisionModelOfBlock(Vec3i blockInWorld) {
+ ChunkData chunk = getChunkByBlock(blockInWorld);
+ if (chunk == null) return null;
+
+ Vec3i blockInChunk = Vectors.grab3i();
+ Coordinates.convertInWorldToInChunk(blockInWorld, blockInChunk);
+ BlockData block = chunk.getBlock(blockInChunk);
+ Vectors.release(blockInChunk);
+
+ if (block == null) return null;
+ return block.getCollisionModel();
+ }
+
}
diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java b/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java
index 5bcbd50..e1ea62d 100644
--- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java
+++ b/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java
@@ -17,6 +17,8 @@
*******************************************************************************/
package ru.windcorp.progressia.common.world.block;
+import ru.windcorp.progressia.common.collision.AABB;
+import ru.windcorp.progressia.common.collision.CollisionModel;
import ru.windcorp.progressia.common.util.Namespaced;
public class BlockData extends Namespaced {
@@ -24,5 +26,9 @@ public class BlockData extends Namespaced {
public BlockData(String namespace, String name) {
super(namespace, name);
}
+
+ public CollisionModel getCollisionModel() {
+ return AABB.UNIT_CUBE;
+ }
}
diff --git a/src/main/java/ru/windcorp/progressia/test/AABBRenderer.java b/src/main/java/ru/windcorp/progressia/test/AABBRenderer.java
deleted file mode 100644
index e9a6b7b..0000000
--- a/src/main/java/ru/windcorp/progressia/test/AABBRenderer.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package ru.windcorp.progressia.test;
-
-import ru.windcorp.progressia.client.graphics.model.Shape;
-import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
-import ru.windcorp.progressia.client.graphics.model.Shapes;
-import ru.windcorp.progressia.client.graphics.texture.Texture;
-import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
-import ru.windcorp.progressia.common.collision.AABB;
-import ru.windcorp.progressia.common.collision.CollisionModel;
-import ru.windcorp.progressia.common.collision.CompoundCollisionModel;
-
-public class AABBRenderer {
-
- private static final Shape CUBE = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null).setColorMultiplier(1.0f, 0.7f, 0.2f).create();
-
- public static void renderAABB(AABB aabb, ShapeRenderHelper helper) {
- helper.pushTransform().translate(aabb.getOrigin()).scale(aabb.getSize());
- CUBE.render(helper);
- helper.popTransform();
- }
-
- public static void renderAABBsInCompound(
- CompoundCollisionModel model,
- ShapeRenderHelper helper
- ) {
- for (CollisionModel part : model.getModels()) {
- if (part instanceof CompoundCollisionModel) {
- renderAABBsInCompound((CompoundCollisionModel) part, helper);
- } else if (part instanceof AABB) {
- renderAABB((AABB) part, helper);
- }
- }
- }
-
-}
diff --git a/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java b/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java
new file mode 100644
index 0000000..15463d4
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java
@@ -0,0 +1,61 @@
+package ru.windcorp.progressia.test;
+
+import glm.mat._4.Mat4;
+import glm.vec._3.Vec3;
+import glm.vec._3.i.Vec3i;
+import ru.windcorp.progressia.client.graphics.model.Shape;
+import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
+import ru.windcorp.progressia.client.graphics.model.Shapes;
+import ru.windcorp.progressia.client.graphics.texture.Texture;
+import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
+import ru.windcorp.progressia.common.collision.AABBoid;
+import ru.windcorp.progressia.common.collision.CollisionModel;
+import ru.windcorp.progressia.common.collision.CompoundCollisionModel;
+import ru.windcorp.progressia.common.util.Vectors;
+
+public class CollisionModelRenderer {
+
+ private static final Shape CUBE = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null).setColorMultiplier(1.0f, 0.7f, 0.2f).create();
+ private static final Shape CUBE_GRAY = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null).setColorMultiplier(0.5f, 0.5f, 0.5f).create();
+
+ public static void renderCollisionModel(CollisionModel model, ShapeRenderHelper helper) {
+ if (model instanceof AABBoid) {
+ renderAABBoid((AABBoid) model, helper);
+ } else if (model instanceof CompoundCollisionModel) {
+ renderCompound((CompoundCollisionModel) model, helper);
+ } else {
+ // Ignore silently
+ }
+ }
+
+ private static void renderAABBoid(AABBoid aabb, ShapeRenderHelper helper) {
+ Mat4 mat = helper.pushTransform();
+ Vec3 tmp = Vectors.grab3();
+
+ aabb.getOrigin(tmp);
+ mat.translate(tmp);
+ aabb.getSize(tmp);
+ mat.scale(tmp);
+
+ Vectors.release(tmp);
+
+ CUBE.render(helper);
+ helper.popTransform();
+ }
+
+ private static void renderCompound(
+ CompoundCollisionModel model,
+ ShapeRenderHelper helper
+ ) {
+ for (CollisionModel part : model.getModels()) {
+ renderCollisionModel(part, helper);
+ }
+ }
+
+ public static void renderBlock(Vec3i coords, ShapeRenderHelper helper) {
+ helper.pushTransform().translate(coords.x, coords.y, coords.z);
+ CUBE_GRAY.render(helper);
+ helper.popTransform();
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java
new file mode 100755
index 0000000..2ae9828
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Progressia
+ * 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.progressia.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import ru.windcorp.progressia.client.ClientState;
+import ru.windcorp.progressia.client.graphics.font.Font;
+import ru.windcorp.progressia.client.graphics.gui.GUILayer;
+import ru.windcorp.progressia.client.graphics.gui.Label;
+import ru.windcorp.progressia.client.graphics.gui.Panel;
+import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
+import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
+
+public class LayerTestGUI extends GUILayer {
+
+ public LayerTestGUI() {
+ super("LayerTestGui", new LayoutAlign(0, 1, 5));
+
+ Panel panel = new Panel("ControlDisplays", new LayoutVertical(5));
+
+ Collection