From 4d6278d21fe5562390548d4c4928aa59137f1f76 Mon Sep 17 00:00:00 2001 From: austin Date: Mon, 28 Oct 2024 16:15:24 -0400 Subject: [PATCH] fix + docs + refactor mathutils --- assets/Config/settings.json | 8 +++---- buildNumber.properties | 4 ++-- .../architecture/generation/voxelgenideas.md | 11 ++++++++++ .../generation/worldgenerationindex.md | 3 ++- docs/src/progress/renderertodo.md | 8 +++++++ .../java/electrosphere/audio/AudioEngine.java | 6 +++--- .../electrosphere/audio/AudioListener.java | 4 ++-- .../entity/camera/CameraEntityUtils.java | 20 +++++++++--------- .../entity/debug/DebugVisualizerUtils.java | 4 ++-- .../electrosphere/controls/CameraHandler.java | 8 +++---- .../ClientParticleEmitterComponent.java | 8 +++---- .../state/hitbox/HitboxCollectionState.java | 4 ++-- .../editor/ClientEditorMovementTree.java | 8 +++---- .../editor/ServerEditorMovementTree.java | 8 +++---- .../groundmove/ClientGroundMovementTree.java | 4 ++-- .../groundmove/ServerGroundMovementTree.java | 4 ++-- .../upright/ServerAlwaysUprightTree.java | 4 ++-- .../types/common/CommonEntityUtils.java | 10 ++++----- .../types/projectile/ProjectileUtils.java | 10 ++++----- .../renderer/pipelines/ShadowMapPipeline.java | 4 ++-- .../electrosphere/script/ScriptEngine.java | 4 ++-- .../ai/nodes/actions/move/FaceTargetNode.java | 4 ++-- .../electrosphere/util/math/MathBones.java | 4 ++-- .../{MathUtils.java => SpatialMathUtils.java} | 4 ++-- .../renderer/ui/test_Screencapture_Match.png | Bin 28071 -> 31264 bytes 25 files changed, 88 insertions(+), 68 deletions(-) create mode 100644 docs/src/architecture/generation/voxelgenideas.md rename src/main/java/electrosphere/util/math/{MathUtils.java => SpatialMathUtils.java} (95%) diff --git a/assets/Config/settings.json b/assets/Config/settings.json index 68d178d7..74162155 100644 --- a/assets/Config/settings.json +++ b/assets/Config/settings.json @@ -2,8 +2,8 @@ "gameplayGenerateWorld" : false, "gameplayPhysicsCellRadius" : 2, - "displayWidth" : 2560, - "displayHeight" : 1600, + "displayWidth" : 1920, + "displayHeight" : 1080, "displayFullscreen" : false, "graphicsFOV" : 100.0, @@ -15,8 +15,8 @@ "graphicsPerformanceOIT" : true, "graphicsViewRange" : 20000.0, - "renderResolutionX": 2560, - "renderResolutionY": 1600, + "renderResolutionX": 1920, + "renderResolutionY": 1080, "graphicsDebugDrawCollisionSpheresClient" : false, "graphicsDebugDrawCollisionSpheresServer" : false, diff --git a/buildNumber.properties b/buildNumber.properties index 62d16ddf..eaad655c 100644 --- a/buildNumber.properties +++ b/buildNumber.properties @@ -1,3 +1,3 @@ #maven.buildNumber.plugin properties file -#Mon Oct 21 09:58:24 EDT 2024 -buildNumber=363 +#Mon Oct 28 16:07:42 EDT 2024 +buildNumber=364 diff --git a/docs/src/architecture/generation/voxelgenideas.md b/docs/src/architecture/generation/voxelgenideas.md new file mode 100644 index 00000000..476b878e --- /dev/null +++ b/docs/src/architecture/generation/voxelgenideas.md @@ -0,0 +1,11 @@ +@page voxelgenideas + +techniques to consider: + +adding different types of noise +gradients of different types of noise +fractal brownian noise +sines pulling from sines +noise functions pulling from sines +applying 2d values to the surface (top) of a 3d noise map +subtracting true 3d noise from a 2d heightmap to account for cave entrances diff --git a/docs/src/architecture/generation/worldgenerationindex.md b/docs/src/architecture/generation/worldgenerationindex.md index 4649da55..b816c16a 100644 --- a/docs/src/architecture/generation/worldgenerationindex.md +++ b/docs/src/architecture/generation/worldgenerationindex.md @@ -3,4 +3,5 @@ [TOC] - @subpage biomeselection - @subpage biomegenerationproblems -- @subpage terraingenerationprocess \ No newline at end of file +- @subpage terraingenerationprocess +- @subpage voxelgenideas \ No newline at end of file diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 9e70631a..a0a81df3 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -906,6 +906,14 @@ Chemistry system collision engine instance on server and client (10/24/2024) CraftingPanel implementation +(10/27/2024) +World gen docs + ideas +Update default resolution in config + +(10/28/2024) +Fix main menu ui test +Refactor math utils to spatial math utils to make room for more fundamental utils + # TODO diff --git a/src/main/java/electrosphere/audio/AudioEngine.java b/src/main/java/electrosphere/audio/AudioEngine.java index 7c9b247c..598187ec 100644 --- a/src/main/java/electrosphere/audio/AudioEngine.java +++ b/src/main/java/electrosphere/audio/AudioEngine.java @@ -3,7 +3,7 @@ package electrosphere.audio; import electrosphere.client.entity.camera.CameraEntityUtils; import electrosphere.engine.Globals; import electrosphere.logger.LoggerInterface; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; import java.nio.ByteBuffer; import java.nio.IntBuffer; @@ -197,8 +197,8 @@ public class AudioEngine { listener.setPosition(cameraPos); //orientation - Vector3d cameraEye = MathUtils.getOriginVector().rotate(CameraEntityUtils.getRotationQuat(Globals.playerCamera)).normalize(); - Vector3d cameraUp = MathUtils.getUpVector().rotate(CameraEntityUtils.getRotationQuat(Globals.playerCamera)).normalize(); + Vector3d cameraEye = SpatialMathUtils.getOriginVector().rotate(CameraEntityUtils.getRotationQuat(Globals.playerCamera)).normalize(); + Vector3d cameraUp = SpatialMathUtils.getUpVector().rotate(CameraEntityUtils.getRotationQuat(Globals.playerCamera)).normalize(); listener.setOrientation(new Vector3f((float)cameraEye.x,(float)cameraEye.y,(float)cameraEye.z), new Vector3f((float)cameraUp.x,(float)cameraUp.y,(float)cameraUp.z)); } } diff --git a/src/main/java/electrosphere/audio/AudioListener.java b/src/main/java/electrosphere/audio/AudioListener.java index 85f46ac8..16db4cb1 100644 --- a/src/main/java/electrosphere/audio/AudioListener.java +++ b/src/main/java/electrosphere/audio/AudioListener.java @@ -5,7 +5,7 @@ import org.joml.Vector3f; import org.lwjgl.openal.AL11; import electrosphere.engine.Globals; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; import static org.lwjgl.openal.AL10.*; @@ -18,7 +18,7 @@ public class AudioListener { Vector3d position = new Vector3d(); //eye vector for listener - Vector3f eye = MathUtils.getOriginVectorf(); + Vector3f eye = SpatialMathUtils.getOriginVectorf(); //up vector for listener Vector3f up = new Vector3f(0,1,0); diff --git a/src/main/java/electrosphere/client/entity/camera/CameraEntityUtils.java b/src/main/java/electrosphere/client/entity/camera/CameraEntityUtils.java index 7c91b047..437acafd 100644 --- a/src/main/java/electrosphere/client/entity/camera/CameraEntityUtils.java +++ b/src/main/java/electrosphere/client/entity/camera/CameraEntityUtils.java @@ -8,7 +8,7 @@ import electrosphere.entity.EntityUtils; import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.types.common.CommonEntityUtils; import electrosphere.game.data.common.CommonEntityType; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; import org.joml.Matrix4d; import org.joml.Matrix4f; @@ -70,7 +70,7 @@ public class CameraEntityUtils { */ public static Entity spawnPlayerEntityTrackingCameraEntity(){ Vector3f center = new Vector3f(0,0,0); - Vector3f eye = MathUtils.getOriginVectorf(); + Vector3f eye = SpatialMathUtils.getOriginVectorf(); Entity rVal = EntityCreationUtils.createClientSpatialEntity(); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_TYPE, EntityDataStrings.DATA_STRING_CAMERA_TYPE_ORBIT); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_CENTER, center); @@ -125,7 +125,7 @@ public class CameraEntityUtils { if(Globals.controlHandler.cameraIsThirdPerson()){ Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraEntity(); } else { - Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraFirstPersonEntity(new Vector3f(0,0,0), MathUtils.getOriginVectorf()); + Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraFirstPersonEntity(new Vector3f(0,0,0), SpatialMathUtils.getOriginVectorf()); } } @@ -196,7 +196,7 @@ public class CameraEntityUtils { * @return The quaternion */ public static Quaternionf getPitchQuat(double pitch){ - Quaternionf pitchQuat = new Quaternionf().fromAxisAngleDeg(MathUtils.getLeftVectorf(), -(float)pitch); + Quaternionf pitchQuat = new Quaternionf().fromAxisAngleDeg(SpatialMathUtils.getLeftVectorf(), -(float)pitch); return pitchQuat; } @@ -206,7 +206,7 @@ public class CameraEntityUtils { * @return The quaternion */ public static Quaternionf getYawQuat(double yaw){ - Quaternionf yawQuat = new Quaternionf().fromAxisAngleDeg(MathUtils.getUpVectorf(), -(float)yaw); + Quaternionf yawQuat = new Quaternionf().fromAxisAngleDeg(SpatialMathUtils.getUpVectorf(), -(float)yaw); return yawQuat; } @@ -219,7 +219,7 @@ public class CameraEntityUtils { public static Matrix4f getCameraViewMatrix(Entity camera){ Vector3f cameraCenter = new Vector3f(0,0,0);//getViewMatrixCenterOffset(camera); Vector3f cameraEye = new Vector3f(cameraCenter).add(getCameraEye(camera)); - Vector3f cameraUp = MathUtils.getUpVectorf(); + Vector3f cameraUp = SpatialMathUtils.getUpVectorf(); //!!before you make the same mistake I made, cameraEye is NOT NECESSARILY normalized/unit vector //the orbital distance and offset are included in this vector //TODO: refactor this to some other matrix of transforms or something?? @@ -318,7 +318,7 @@ public class CameraEntityUtils { Quaternionf quatRaw = CameraEntityUtils.getYawQuat(yaw).mul(CameraEntityUtils.getPitchQuat(pitch)).mul(new Quaternionf().rotateY((float)Math.PI)); Quaterniond quatd = new Quaterniond(quatRaw).normalize(); Matrix4d rotationMat = new Matrix4d().rotate(quatd); - Vector4d rotationVecRaw = MathUtils.getOriginVector4(); + Vector4d rotationVecRaw = SpatialMathUtils.getOriginVector4(); rotationVecRaw = rotationMat.transform(rotationVecRaw); return new Vector3d(rotationVecRaw.x,0,rotationVecRaw.z); } @@ -334,7 +334,7 @@ public class CameraEntityUtils { Quaternionf quatRaw = CameraEntityUtils.getYawQuat(yaw).mul(CameraEntityUtils.getPitchQuat(pitch)).mul(new Quaternionf().rotateY((float)Math.PI)); Quaterniond quatd = new Quaterniond(quatRaw).normalize(); Matrix4d rotationMat = new Matrix4d().rotate(quatd); - Vector4d rotationVecRaw = MathUtils.getOriginVector4(); + Vector4d rotationVecRaw = SpatialMathUtils.getOriginVector4(); rotationVecRaw = rotationMat.transform(rotationVecRaw); return new Vector3d(rotationVecRaw.x,0,rotationVecRaw.z); } @@ -347,10 +347,10 @@ public class CameraEntityUtils { public static Vector3d getFacingVec(Quaterniond rotation){ //quaternion is multiplied by pi because we want to point away from the eye of the camera, NOT towards it Matrix4d rotationMat = new Matrix4d().rotate(rotation); - Vector4d rotationVecRaw = MathUtils.getOriginVector4(); + Vector4d rotationVecRaw = SpatialMathUtils.getOriginVector4(); rotationVecRaw = rotationMat.transform(rotationVecRaw); if(rotationVecRaw.length() < 0.001){ - rotationVecRaw.set(MathUtils.getOriginVector4()); + rotationVecRaw.set(SpatialMathUtils.getOriginVector4()); } return new Vector3d(rotationVecRaw.x,0,rotationVecRaw.z); } diff --git a/src/main/java/electrosphere/client/entity/debug/DebugVisualizerUtils.java b/src/main/java/electrosphere/client/entity/debug/DebugVisualizerUtils.java index 16a8a153..0db0e30a 100644 --- a/src/main/java/electrosphere/client/entity/debug/DebugVisualizerUtils.java +++ b/src/main/java/electrosphere/client/entity/debug/DebugVisualizerUtils.java @@ -10,7 +10,7 @@ import electrosphere.entity.Entity; import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityUtils; import electrosphere.entity.btree.BehaviorTree; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; /** * Debug tools for visualizing things in the game engine @@ -43,7 +43,7 @@ public class DebugVisualizerUtils { */ public static Entity clientSpawnVectorVisualizer(Vector3d point1, Vector3d point2){ Vector3d position = point1; - Quaterniond rotation = MathUtils.calculateRotationFromPointToPoint(point1, point2); + Quaterniond rotation = SpatialMathUtils.calculateRotationFromPointToPoint(point1, point2); Vector3d scale = new Vector3d(point1.distance(point2)); return clientSpawnVectorVisualizer(position, rotation, scale); } diff --git a/src/main/java/electrosphere/controls/CameraHandler.java b/src/main/java/electrosphere/controls/CameraHandler.java index f60e5a23..03621ed5 100644 --- a/src/main/java/electrosphere/controls/CameraHandler.java +++ b/src/main/java/electrosphere/controls/CameraHandler.java @@ -12,7 +12,7 @@ import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.renderer.ui.events.MouseEvent; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; /** * Handler for camera-related events and controls @@ -109,13 +109,13 @@ public class CameraHandler { // CameraEntityUtils.setCameraCenter(Globals.playerCamera, new Vector3f((float)charPos.x,(float)charPos.y,(float)charPos.z)); // } - Quaternionf pitchQuat = new Quaternionf().fromAxisAngleDeg(MathUtils.getLeftVectorf(), -pitch); - Quaternionf yawQuat = new Quaternionf().fromAxisAngleDeg(MathUtils.getUpVectorf(), -yaw); + Quaternionf pitchQuat = new Quaternionf().fromAxisAngleDeg(SpatialMathUtils.getLeftVectorf(), -pitch); + Quaternionf yawQuat = new Quaternionf().fromAxisAngleDeg(SpatialMathUtils.getUpVectorf(), -yaw); // float yawRad = yaw / 180.0f * (float)Math.PI; // float pitchRad = pitch / 180.0f * (float)Math.PI; // float rollRad = 0.0f; // pitchQuat.mul(yawQuat); - cameraRotationVector = pitchQuat.transform(MathUtils.getOriginVectorf()); + cameraRotationVector = pitchQuat.transform(SpatialMathUtils.getOriginVectorf()); cameraRotationVector = yawQuat.transform(cameraRotationVector); cameraRotationVector.normalize(); diff --git a/src/main/java/electrosphere/entity/state/client/particle/ClientParticleEmitterComponent.java b/src/main/java/electrosphere/entity/state/client/particle/ClientParticleEmitterComponent.java index 16ebec51..c17323da 100644 --- a/src/main/java/electrosphere/entity/state/client/particle/ClientParticleEmitterComponent.java +++ b/src/main/java/electrosphere/entity/state/client/particle/ClientParticleEmitterComponent.java @@ -12,7 +12,7 @@ import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.state.equip.ClientEquipState; import electrosphere.game.data.particle.ParticleData; import electrosphere.game.data.particle.ParticleEmitter; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; /** * A component that causes the entity to emit particles @@ -81,10 +81,10 @@ public class ClientParticleEmitterComponent implements BehaviorTree { Quaterniond rot = new Quaterniond(); Vector3d cross = null; Vector3d normalizedVelocity = new Vector3d(initialVelocity).normalize(); - if(Math.abs(normalizedVelocity.dot(MathUtils.getOriginVector())) < 0.8){ - cross = MathUtils.getOriginVector().cross(normalizedVelocity); + if(Math.abs(normalizedVelocity.dot(SpatialMathUtils.getOriginVector())) < 0.8){ + cross = SpatialMathUtils.getOriginVector().cross(normalizedVelocity); } else { - cross = MathUtils.getUpVector().cross(normalizedVelocity); + cross = SpatialMathUtils.getUpVector().cross(normalizedVelocity); } rot.rotateAxis(Math.PI * 2 * particleRand.nextFloat(), normalizedVelocity); rot.rotateAxis((particleRand.nextFloat() * this.particleEmitter.getSpread()) / 180.0 * Math.PI, cross); diff --git a/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java b/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java index e68b190e..8da689a0 100644 --- a/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java +++ b/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java @@ -26,7 +26,7 @@ import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState.Hitbo import electrosphere.game.data.collidable.HitboxData; import electrosphere.game.data.utils.DataFormatUtil; import electrosphere.logger.LoggerInterface; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; /** * The state of the collection of all hitboxes on this entity @@ -405,7 +405,7 @@ public class HitboxCollectionState { //the second quaternion is a rotation along the x axis. This is used to put the hitbox rotation into ode's space //ode is Z-axis-up if(previousWorldPos.distance(worldPosition) > 0.0){ - worldRotation = MathUtils.calculateRotationFromPointToPoint(previousWorldPos,worldPosition).mul(new Quaterniond(0,0.707,0,0.707)); + worldRotation = SpatialMathUtils.calculateRotationFromPointToPoint(previousWorldPos,worldPosition).mul(new Quaterniond(0,0.707,0,0.707)); } //create new capsule diff --git a/src/main/java/electrosphere/entity/state/movement/editor/ClientEditorMovementTree.java b/src/main/java/electrosphere/entity/state/movement/editor/ClientEditorMovementTree.java index 6ce89296..98a2fde6 100644 --- a/src/main/java/electrosphere/entity/state/movement/editor/ClientEditorMovementTree.java +++ b/src/main/java/electrosphere/entity/state/movement/editor/ClientEditorMovementTree.java @@ -21,7 +21,7 @@ import electrosphere.net.synchronization.annotation.SynchronizableEnum; import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree; import electrosphere.net.synchronization.enums.BehaviorTreeIdEnums; import electrosphere.renderer.anim.Animation; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; import java.util.concurrent.CopyOnWriteArrayList; @@ -226,14 +226,14 @@ public class ClientEditorMovementTree implements BehaviorTree { movementVector.rotateY((float)(-135 * Math.PI / 180)).normalize(); break; case UP: { - movementVector = MathUtils.getUpVector(); + movementVector = SpatialMathUtils.getUpVector(); } break; case DOWN: { - movementVector = MathUtils.getUpVector().mul(-1); + movementVector = SpatialMathUtils.getUpVector().mul(-1); } break; } } - Quaterniond movementQuaternion = new Quaterniond().rotationTo(MathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); + Quaterniond movementQuaternion = new Quaterniond().rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); Quaterniond rotation = EntityUtils.getRotation(parent); //parse attached network messages diff --git a/src/main/java/electrosphere/entity/state/movement/editor/ServerEditorMovementTree.java b/src/main/java/electrosphere/entity/state/movement/editor/ServerEditorMovementTree.java index 300e7627..51771fcf 100644 --- a/src/main/java/electrosphere/entity/state/movement/editor/ServerEditorMovementTree.java +++ b/src/main/java/electrosphere/entity/state/movement/editor/ServerEditorMovementTree.java @@ -29,7 +29,7 @@ import electrosphere.renderer.anim.Animation; import electrosphere.script.utils.AccessTransforms; import electrosphere.server.datacell.utils.DataCellSearchUtils; import electrosphere.server.utils.ServerScriptUtils; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; import java.util.concurrent.CopyOnWriteArrayList; @@ -194,14 +194,14 @@ public class ServerEditorMovementTree implements BehaviorTree { movementVector.rotateY((float)(-135 * Math.PI / 180)).normalize(); break; case UP: { - movementVector = MathUtils.getUpVector(); + movementVector = SpatialMathUtils.getUpVector(); } break; case DOWN: { - movementVector = MathUtils.getUpVector().mul(-1); + movementVector = SpatialMathUtils.getUpVector().mul(-1); } break; } } - Quaterniond movementQuaternion = new Quaterniond().rotationTo(MathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); + Quaterniond movementQuaternion = new Quaterniond().rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); Quaterniond rotation = EntityUtils.getRotation(parent); //TODO: optimize away and document (I know for the moment if this exception isn't here it will bite me in the ass later) if(facingVector.length() == 0){ diff --git a/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java b/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java index 99366d0b..43bea2bf 100644 --- a/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java +++ b/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java @@ -29,7 +29,7 @@ import electrosphere.net.synchronization.annotation.SynchronizableEnum; import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree; import electrosphere.net.synchronization.enums.BehaviorTreeIdEnums; import electrosphere.renderer.anim.Animation; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; import electrosphere.renderer.actor.Actor; import java.util.concurrent.CopyOnWriteArrayList; @@ -239,7 +239,7 @@ public class ClientGroundMovementTree implements BehaviorTree { break; } } - Quaterniond movementQuaternion = new Quaterniond().rotationTo(MathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); + Quaterniond movementQuaternion = new Quaterniond().rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); Quaterniond rotation = EntityUtils.getRotation(parent); //parse attached network messages diff --git a/src/main/java/electrosphere/entity/state/movement/groundmove/ServerGroundMovementTree.java b/src/main/java/electrosphere/entity/state/movement/groundmove/ServerGroundMovementTree.java index 10f9e8d2..a720fae0 100644 --- a/src/main/java/electrosphere/entity/state/movement/groundmove/ServerGroundMovementTree.java +++ b/src/main/java/electrosphere/entity/state/movement/groundmove/ServerGroundMovementTree.java @@ -33,7 +33,7 @@ import electrosphere.script.utils.AccessTransforms; import electrosphere.server.datacell.utils.DataCellSearchUtils; import electrosphere.server.poseactor.PoseActor; import electrosphere.server.utils.ServerScriptUtils; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; import java.util.concurrent.CopyOnWriteArrayList; @@ -207,7 +207,7 @@ public class ServerGroundMovementTree implements BehaviorTree { break; } } - Quaterniond movementQuaternion = new Quaterniond().rotationTo(MathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); + Quaterniond movementQuaternion = new Quaterniond().rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); Quaterniond rotation = EntityUtils.getRotation(parent); //TODO: optimize away and document (I know for the moment if this exception isn't here it will bite me in the ass later) if(facingVector.length() == 0){ diff --git a/src/main/java/electrosphere/entity/state/physicssync/upright/ServerAlwaysUprightTree.java b/src/main/java/electrosphere/entity/state/physicssync/upright/ServerAlwaysUprightTree.java index 2c00f07f..97c1b8d5 100644 --- a/src/main/java/electrosphere/entity/state/physicssync/upright/ServerAlwaysUprightTree.java +++ b/src/main/java/electrosphere/entity/state/physicssync/upright/ServerAlwaysUprightTree.java @@ -15,7 +15,7 @@ import electrosphere.entity.state.physicssync.ServerPhysicsSyncTree; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; public class ServerAlwaysUprightTree implements BehaviorTree { @@ -48,7 +48,7 @@ public class ServerAlwaysUprightTree implements BehaviorTree { //calculate rotation based on facing vector if(CreatureUtils.getFacingVector(parent) != null){ Vector3d facingVector = CreatureUtils.getFacingVector(parent); - sourceRotation = new Quaterniond().rotationTo(MathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); + sourceRotation = new Quaterniond().rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); } EntityUtils.getPosition(parent).set(position); diff --git a/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java b/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java index 8e11d8e6..97cdb0dc 100644 --- a/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java +++ b/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java @@ -85,7 +85,7 @@ import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; import electrosphere.server.datacell.utils.ServerEntityTagUtils; import electrosphere.server.poseactor.PoseActor; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; /** * Utilities for creating all entity types @@ -220,7 +220,7 @@ public class CommonEntityUtils { } //round out end of move system entity.putData(EntityDataStrings.CLIENT_MOVEMENT_BT, moveTree); - CreatureUtils.setFacingVector(entity, MathUtils.getOriginVector()); + CreatureUtils.setFacingVector(entity, SpatialMathUtils.getOriginVector()); entity.putData(EntityDataStrings.DATA_STRING_MAX_NATURAL_VELOCITY, groundMovementSystem.getMaxVelocity()); entity.putData(EntityDataStrings.DATA_STRING_ACCELERATION, groundMovementSystem.getAcceleration()); entity.putData(EntityDataStrings.DATA_STRING_VELOCITY, 0f); @@ -340,7 +340,7 @@ public class CommonEntityUtils { } break; case "UNIT_CONTROLS": { ClientAlwaysUprightTree.attachTree(entity); - CreatureUtils.setFacingVector(entity, MathUtils.getOriginVector()); + CreatureUtils.setFacingVector(entity, SpatialMathUtils.getOriginVector()); } break; case "TERRAIN_COLLISION": { CollisionObjUtils.getCollidable(entity).overrideType(Collidable.TYPE_TERRAIN); @@ -515,7 +515,7 @@ public class CommonEntityUtils { } //round out end of move system entity.putData(EntityDataStrings.SERVER_MOVEMENT_BT, moveTree); - CreatureUtils.setFacingVector(entity, MathUtils.getOriginVector()); + CreatureUtils.setFacingVector(entity, SpatialMathUtils.getOriginVector()); entity.putData(EntityDataStrings.DATA_STRING_MAX_NATURAL_VELOCITY, groundMovementSystem.getMaxVelocity()); entity.putData(EntityDataStrings.DATA_STRING_ACCELERATION, groundMovementSystem.getAcceleration()); entity.putData(EntityDataStrings.DATA_STRING_VELOCITY, 0f); @@ -634,7 +634,7 @@ public class CommonEntityUtils { } break; case "UNIT_CONTROLS": { ServerAlwaysUprightTree.attachTree(entity); - CreatureUtils.setFacingVector(entity, MathUtils.getOriginVector()); + CreatureUtils.setFacingVector(entity, SpatialMathUtils.getOriginVector()); } break; case "TERRAIN_COLLISION": { CollisionObjUtils.getCollidable(entity).overrideType(Collidable.TYPE_TERRAIN); diff --git a/src/main/java/electrosphere/entity/types/projectile/ProjectileUtils.java b/src/main/java/electrosphere/entity/types/projectile/ProjectileUtils.java index f5a16b4c..4ab29b23 100644 --- a/src/main/java/electrosphere/entity/types/projectile/ProjectileUtils.java +++ b/src/main/java/electrosphere/entity/types/projectile/ProjectileUtils.java @@ -19,7 +19,7 @@ import electrosphere.game.data.collidable.HitboxData; import electrosphere.game.data.projectile.ProjectileType; import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; public class ProjectileUtils { @@ -39,7 +39,7 @@ public class ProjectileUtils { Globals.assetManager.addModelPathToQueue(model); ProjectileTree tree = new ProjectileTree(rVal,maxLife,new Vector3d(initialVector),velocity); EntityUtils.getPosition(rVal).set(initialPosition); - EntityUtils.getRotation(rVal).rotationTo(MathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); + EntityUtils.getRotation(rVal).rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); Globals.clientSceneWrapper.getScene().registerBehaviorTree(tree); return rVal; } @@ -60,7 +60,7 @@ public class ProjectileUtils { ProjectileTree tree = new ProjectileTree(rVal,maxLife,new Vector3d(initialVector),velocity); EntityUtils.getPosition(rVal).set(initialPosition); // EntityUtils.getRotation(currentEntity).rotationTo(MathUtils.ORIGIN_VECTORF, new Vector3f((float)facingAngle.x,(float)facingAngle.y,(float)facingAngle.z)).mul(parentActor.getBoneRotation(targetBone)).normalize(); - EntityUtils.getRotation(rVal).rotationTo(MathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); + EntityUtils.getRotation(rVal).rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); // ParticleTree particleTree = new ParticleTree(rVal, maxLife, destination, velocity, acceleration, true); // rVal.putData(EntityDataStrings.PARTICLE_TREE, particleTree); // rVal.putData(EntityDataStrings.IS_PARTICLE, true); @@ -82,7 +82,7 @@ public class ProjectileUtils { Entity rVal = EntityCreationUtils.createClientSpatialEntity(); EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath()); //initial coordinates - EntityUtils.getRotation(rVal).rotationTo(MathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); + EntityUtils.getRotation(rVal).rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); EntityUtils.getPosition(rVal).set(initialPosition); //projectile behavior tree ProjectileTree tree = new ProjectileTree(rVal,rawType.getMaxLife(),initialVector,rawType.getVelocity(), rawType.getDamage()); @@ -117,7 +117,7 @@ public class ProjectileUtils { ProjectileType rawType = Globals.gameConfigCurrent.getProjectileMap().getType(projectileType); Entity rVal = EntityCreationUtils.createServerEntity(realm, initialPosition); //initial coordinates - EntityUtils.getRotation(rVal).rotationTo(MathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); + EntityUtils.getRotation(rVal).rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); EntityUtils.getPosition(rVal).set(initialPosition); //projectile behavior tree ProjectileTree tree = new ProjectileTree(rVal,rawType.getMaxLife(),initialVector,rawType.getVelocity(), rawType.getDamage()); diff --git a/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java b/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java index d45c98ec..97052dbb 100644 --- a/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java @@ -16,7 +16,7 @@ import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderPipelineState; import electrosphere.renderer.RenderingEngine; import electrosphere.renderer.actor.Actor; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; /** * Shadow map pipeline @@ -76,7 +76,7 @@ public class ShadowMapPipeline implements RenderPipeline { Matrix4f lightView = new Matrix4f().setLookAt( new Vector3f(eyeX, eyeY, eyeZ), new Vector3f( 0.0f, 0.0f, 0.0f), - MathUtils.getUpVectorf() + SpatialMathUtils.getUpVectorf() ); Globals.lightDepthMatrix = lightProjection.mul(lightView); diff --git a/src/main/java/electrosphere/script/ScriptEngine.java b/src/main/java/electrosphere/script/ScriptEngine.java index f37e207d..472455ca 100644 --- a/src/main/java/electrosphere/script/ScriptEngine.java +++ b/src/main/java/electrosphere/script/ScriptEngine.java @@ -22,7 +22,7 @@ import electrosphere.engine.Main; import electrosphere.logger.LoggerInterface; import electrosphere.script.translation.JSServerUtils; import electrosphere.util.FileUtils; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; /** * Interface for executing scripts in the game engine @@ -91,7 +91,7 @@ public class ScriptEngine { //The classes that will be provided to the scripting engine //https://stackoverflow.com/a/65942034 static final Object[][] staticClasses = new Object[][]{ - {"mathUtils",MathUtils.class}, + {"mathUtils",SpatialMathUtils.class}, {"simulation",Main.class}, {"tutorialUtils",TutorialMenus.class}, {"serverUtils",JSServerUtils.class}, diff --git a/src/main/java/electrosphere/server/ai/nodes/actions/move/FaceTargetNode.java b/src/main/java/electrosphere/server/ai/nodes/actions/move/FaceTargetNode.java index 2285ccf6..39ab6a6f 100644 --- a/src/main/java/electrosphere/server/ai/nodes/actions/move/FaceTargetNode.java +++ b/src/main/java/electrosphere/server/ai/nodes/actions/move/FaceTargetNode.java @@ -10,7 +10,7 @@ import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.server.ai.blackboard.Blackboard; import electrosphere.server.ai.nodes.AITreeNode; import electrosphere.server.ai.nodes.actions.combat.MeleeTargetingNode; -import electrosphere.util.math.MathUtils; +import electrosphere.util.math.SpatialMathUtils; /** * Faces the target @@ -29,7 +29,7 @@ public class FaceTargetNode implements AITreeNode { Entity target = MeleeTargetingNode.getTarget(blackboard); Vector3d parentPos = EntityUtils.getPosition(entity); Vector3d targetPos = EntityUtils.getPosition(target); - Quaterniond rotation = MathUtils.calculateRotationFromPointToPoint(parentPos, targetPos); + Quaterniond rotation = SpatialMathUtils.calculateRotationFromPointToPoint(parentPos, targetPos); EntityUtils.getRotation(entity).set(rotation); CreatureUtils.setFacingVector(entity, CameraEntityUtils.getFacingVec(rotation)); return AITreeNodeResult.SUCCESS; diff --git a/src/main/java/electrosphere/util/math/MathBones.java b/src/main/java/electrosphere/util/math/MathBones.java index 8fbd34a7..9ff7e3f3 100644 --- a/src/main/java/electrosphere/util/math/MathBones.java +++ b/src/main/java/electrosphere/util/math/MathBones.java @@ -45,11 +45,11 @@ public class MathBones { Vector3d facingAngle = CreatureUtils.getFacingVector(actorEntity); if(facingAngle == null){ - facingAngle = MathUtils.getOriginVector(); + facingAngle = SpatialMathUtils.getOriginVector(); } //calculate rotation of model return new Quaterniond() - .rotationTo(MathUtils.getOriginVector(), new Vector3d(facingAngle.x,facingAngle.y,facingAngle.z)) + .rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(facingAngle.x,facingAngle.y,facingAngle.z)) .mul(localRot) .normalize(); } diff --git a/src/main/java/electrosphere/util/math/MathUtils.java b/src/main/java/electrosphere/util/math/SpatialMathUtils.java similarity index 95% rename from src/main/java/electrosphere/util/math/MathUtils.java rename to src/main/java/electrosphere/util/math/SpatialMathUtils.java index 979e5f07..fcc3a71b 100644 --- a/src/main/java/electrosphere/util/math/MathUtils.java +++ b/src/main/java/electrosphere/util/math/SpatialMathUtils.java @@ -10,7 +10,7 @@ import electrosphere.logger.LoggerInterface; /** * Utility functions for doing math */ -public class MathUtils { +public class SpatialMathUtils { /** @@ -90,7 +90,7 @@ public class MathUtils { * @return The up rotation */ public static Quaterniond getUpRotation(){ - return MathUtils.calculateRotationFromPointToPoint(MathUtils.getOriginVector(), MathUtils.getUpVector()); + return SpatialMathUtils.calculateRotationFromPointToPoint(SpatialMathUtils.getOriginVector(), SpatialMathUtils.getUpVector()); } diff --git a/test/java/renderer/ui/test_Screencapture_Match.png b/test/java/renderer/ui/test_Screencapture_Match.png index 1055fc38ea50ad24dc6c0fe1b5b711ab15d1ff21..04b65f77a161b04f6c3eb76b054a6243032f1ccd 100644 GIT binary patch literal 31264 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 literal 28071 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