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 models; - public CompoundCollisionModel(Collection models) { + public CompoundCollisionModel(Collection models) { this.models = models; } @@ -18,7 +18,7 @@ public class CompoundCollisionModel implements CollisionModel { this(ImmutableList.copyOf(models)); } - public Collection getModels() { + public Collection 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 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 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 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 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