From f43d4b16de9edb0965f28c9afed09c530eadcbb5 Mon Sep 17 00:00:00 2001 From: IsaacLic <40670945+IsaacLic@users.noreply.github.com> Date: Mon, 24 Aug 2020 23:09:53 -0400 Subject: [PATCH] improvement: textures scale to size (#551) * fix: textures scale to size * fix: added EmptyComponent to whitelist * improvement: graphics are more closely aligned with meshes * docs: added documentation to the alignment code * refactor: made Invisibility a field in Renderable component * docs: cleaned up and added more documentation --- .../org/destinationsol/SolApplication.java | 13 ++--- .../systems/AsteroidBodyCreationSystem.java | 21 +++++++- .../destinationsol/modules/ModuleManager.java | 1 + .../rendering/RenderableElement.java | 48 +++++++++++++++++-- .../rendering/components/Invisible.java | 25 ---------- .../rendering/components/Renderable.java | 3 ++ .../rendering/systems/RenderingSystem.java | 25 +++++++--- 7 files changed, 93 insertions(+), 43 deletions(-) delete mode 100644 engine/src/main/java/org/destinationsol/rendering/components/Invisible.java diff --git a/engine/src/main/java/org/destinationsol/SolApplication.java b/engine/src/main/java/org/destinationsol/SolApplication.java index a85e3052a..a33d65c22 100644 --- a/engine/src/main/java/org/destinationsol/SolApplication.java +++ b/engine/src/main/java/org/destinationsol/SolApplication.java @@ -260,13 +260,17 @@ private void draw() { //TODO remove this block - it is for debugging purposes if (!entityCreated) { + + Size size = new Size(); + size.size = 2; + RenderableElement element = new RenderableElement(); element.texture = SolRandom.randomElement(Assets.listTexturesMatching("engine:asteroid_.*")); - element.relativePosition = new Vector2(0, 0); + element.relativePosition = new Vector2(); element.drawableLevel = DrawableLevel.BODIES; - element.width = 2; - element.height = 2; element.tint = Color.YELLOW; + element.setSize(size.size); + element.graphicsOffset = new Vector2(); Renderable graphicsComponent = new Renderable(); graphicsComponent.elements.add(element); @@ -274,9 +278,6 @@ private void draw() { position.position = solGame.getHero().getShip().getPosition().cpy(); position.position.y += 3; - Size size = new Size(); - size.size = 2; - Health health = new Health(); health.currentHealth = 1; diff --git a/engine/src/main/java/org/destinationsol/asteroids/systems/AsteroidBodyCreationSystem.java b/engine/src/main/java/org/destinationsol/asteroids/systems/AsteroidBodyCreationSystem.java index f0b7a1d89..7b8c5b18c 100644 --- a/engine/src/main/java/org/destinationsol/asteroids/systems/AsteroidBodyCreationSystem.java +++ b/engine/src/main/java/org/destinationsol/asteroids/systems/AsteroidBodyCreationSystem.java @@ -66,7 +66,6 @@ public class AsteroidBodyCreationSystem implements EventReceiver { @ReceiveEvent(components = {AsteroidMesh.class, Size.class, Position.class, Angle.class, Renderable.class}) public EventResult onGenerateBody(GenerateBodyEvent event, EntityRef entity) { - float size = entity.getComponent(Size.class).get().size; Vector2 position = entity.getComponent(Position.class).get().position; float angle = entity.getComponent(Angle.class).get().getAngle(); @@ -90,9 +89,29 @@ public EventResult onGenerateBody(GenerateBodyEvent event, EntityRef entity) { fixtureDef.density = DENSITY; fixtureDef.friction = Const.FRICTION; collisionMeshLoader.attachFixture(body, element.texture.name, fixtureDef, size); + + calculateGraphicsOffset(element); } entitySystemManager.sendEvent(new BodyCreatedEvent(body), entity); return EventResult.CONTINUE; } + + /** + * This calculates the offset of the renderable element from "the origin" (as defined in the JSON that the + * CollisionMeshLoader reads from). + * The origin is where the center of the object should be, which is relevant for physics handling. The + * CollisionMeshLoader creates Fixtures (collision meshes) using that information, so the sprites need to be + * adjusted to overlay the mesh properly. + * LibGDX draws sprites from the bottom left corner. Since the position information is from the center, it + * needs to be adjusted to be at the bottom left of the sprite. To do so, (.5, .5) is subtracted from the origin. + * (The coordinates are scaled to range from zero to one, so (.5, .5) represents the center.) + * The originInformation is the information that was read from the JSON, which is used to calculate the graphics + * offset information. + */ + //TODO separate this method into a separate system once CollisionMeshLoader is modular + private void calculateGraphicsOffset(RenderableElement element) { + Vector2 originInformation = collisionMeshLoader.getOrigin(element.texture.name, 1); + element.graphicsOffset = new Vector2(originInformation.x - .5f, originInformation.y - .5f); + } } diff --git a/engine/src/main/java/org/destinationsol/modules/ModuleManager.java b/engine/src/main/java/org/destinationsol/modules/ModuleManager.java index c27861b0e..2e7f8a4e5 100644 --- a/engine/src/main/java/org/destinationsol/modules/ModuleManager.java +++ b/engine/src/main/java/org/destinationsol/modules/ModuleManager.java @@ -157,6 +157,7 @@ public class ModuleManager { java.io.PipedOutputStream.class, /* Gestalt classes */ org.terasology.gestalt.entitysystem.component.Component.class, + org.terasology.gestalt.entitysystem.component.EmptyComponent.class, org.terasology.gestalt.entitysystem.event.Event.class, org.terasology.gestalt.entitysystem.entity.EntityRef.class, org.terasology.gestalt.entitysystem.entity.EntityIterator.class, diff --git a/engine/src/main/java/org/destinationsol/rendering/RenderableElement.java b/engine/src/main/java/org/destinationsol/rendering/RenderableElement.java index dded2dade..e0df1d201 100644 --- a/engine/src/main/java/org/destinationsol/rendering/RenderableElement.java +++ b/engine/src/main/java/org/destinationsol/rendering/RenderableElement.java @@ -18,7 +18,9 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.math.Vector2; +import org.destinationsol.common.SolMath; import org.destinationsol.game.drawables.DrawableLevel; +import org.destinationsol.size.components.Size; /** * Contains a {@link TextureAtlas.AtlasRegion} (an image), along with information about how it should be drawn. @@ -29,10 +31,10 @@ public class RenderableElement { public TextureAtlas.AtlasRegion texture; /** The width of the texture when drawn. */ - public float width; + private float width; /** The height of the texture when drawn. */ - public float height; + private float height; /** Represents the depth at which this element renders, as well as its logical grouping. */ public DrawableLevel drawableLevel; @@ -46,14 +48,52 @@ public class RenderableElement { /** The tint that the texture should be given. */ public Color tint; + /** + * The amount that the sprite should be moved to line up accurately with the mesh. This should be scaled according + * to the {@link Size}. This is different from the relativePosition, because this is a practical adjustment to align + * the mesh with the sprite, as opposed to moving the sprite relative to the base entity. To draw the sprite + * accurately, it needs to be drawn from the bottom-left of the actual image, not the bottom left of the .png file, + * so this contains the information for calculating the actual start of the sprite. + *
+ * Modification of this can create mesh misalignments, so only change this if you know what you're doing.
+ */
+ public Vector2 graphicsOffset;
+
+
+ //TODO this should be automatically called when the Size component is changed, e.g. the entity shrinks or grows
+ /**
+ * Resizes the renderable element to the given size. The larger dimension of the texture is set to the size, and the
+ * smaller one is scaled down proportionally.
+ */
+ public void setSize(float size) {
+ size /= drawableLevel.depth; // Scales the texture size for objects that are in the background
+ float dimensionsRatio = (float) texture.getRegionWidth() / texture.getRegionHeight();
+ if (dimensionsRatio > 1) {
+ width = size;
+ height = size / dimensionsRatio;
+ } else {
+ width = size / dimensionsRatio;
+ height = size;
+ }
+ }
+
public void copy(RenderableElement other) {
this.texture = new TextureAtlas.AtlasRegion(other.texture);
this.drawableLevel = other.drawableLevel;
this.relativePosition = other.relativePosition.cpy();
this.relativeAngle = other.relativeAngle;
- this.width = other.width;
- this.height = other.height;
+ this.width = other.getWidth();
+ this.height = other.getHeight();
this.tint = other.tint.cpy();
+ this.graphicsOffset = other.graphicsOffset.cpy();
+ }
+
+ public float getWidth() {
+ return width;
+ }
+
+ public float getHeight() {
+ return height;
}
}
diff --git a/engine/src/main/java/org/destinationsol/rendering/components/Invisible.java b/engine/src/main/java/org/destinationsol/rendering/components/Invisible.java
deleted file mode 100644
index 03005163e..000000000
--- a/engine/src/main/java/org/destinationsol/rendering/components/Invisible.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2020 The Terasology Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.destinationsol.rendering.components;
-
-import org.destinationsol.rendering.systems.RenderingSystem;
-import org.terasology.gestalt.entitysystem.component.EmptyComponent;
-
-/**
- * Denotes that the object should not be drawn by the {@link RenderingSystem}.
- */
-public class Invisible extends EmptyComponent