mirror of
https://github.com/Retera/WarsmashModEngine.git
synced 2022-07-31 17:38:59 +02:00
Add game clock functionality and begin work on lighting system
This commit is contained in:
parent
cfa5f952de
commit
59d350dd9e
@ -17,7 +17,8 @@ Path06="."
|
|||||||
|
|
||||||
[Map]
|
[Map]
|
||||||
//FilePath="CombatUnitTests.w3x"
|
//FilePath="CombatUnitTests.w3x"
|
||||||
FilePath="PitchRoll.w3x"
|
//FilePath="PitchRoll.w3x"
|
||||||
|
FilePath="PeonStartingBase.w3x"
|
||||||
//FilePath="PlayerPeasants.w3m"
|
//FilePath="PlayerPeasants.w3m"
|
||||||
//FilePath="FireLord.w3x"
|
//FilePath="FireLord.w3x"
|
||||||
//FilePath="Maps\Campaign\NightElf03.w3m"
|
//FilePath="Maps\Campaign\NightElf03.w3m"
|
@ -27,6 +27,7 @@ import com.etheller.warsmash.viewer5.SolvedPath;
|
|||||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
||||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler;
|
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler;
|
||||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.mdx.MdxViewer;
|
||||||
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
|
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
|
||||||
|
|
||||||
public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvider {
|
public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvider {
|
||||||
@ -62,7 +63,7 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
|
|||||||
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
|
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
|
||||||
this.codebase = new CompoundDataSourceDescriptor(
|
this.codebase = new CompoundDataSourceDescriptor(
|
||||||
Arrays.<DataSourceDescriptor>asList(war3mpq, testingFolder, currentFolder)).createDataSource();
|
Arrays.<DataSourceDescriptor>asList(war3mpq, testingFolder, currentFolder)).createDataSource();
|
||||||
this.viewer = new ModelViewer(this.codebase, this);
|
this.viewer = new MdxViewer(this.codebase, this);
|
||||||
|
|
||||||
this.viewer.addHandler(new MdxHandler());
|
this.viewer.addHandler(new MdxHandler());
|
||||||
this.viewer.enableAudio();
|
this.viewer.enableAudio();
|
||||||
|
@ -56,15 +56,13 @@ import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.ui.MeleeUI;
|
import com.etheller.warsmash.viewer5.handlers.w3x.ui.MeleeUI;
|
||||||
|
|
||||||
public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProvider, InputProcessor {
|
public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProvider, InputProcessor {
|
||||||
private static final float HORIZONTAL_MAXIMUM = (float) Math.toRadians(56);
|
|
||||||
private static final float HORIZONTAL_MINIMUM = (float) -Math.toRadians(56);
|
|
||||||
private static final double HORIZONTAL_ANGLE_INCREMENT = Math.PI / 60;
|
private static final double HORIZONTAL_ANGLE_INCREMENT = Math.PI / 60;
|
||||||
|
|
||||||
private static final Vector3 clickLocationTemp = new Vector3();
|
private static final Vector3 clickLocationTemp = new Vector3();
|
||||||
private static final Vector2 clickLocationTemp2 = new Vector2();
|
private static final Vector2 clickLocationTemp2 = new Vector2();
|
||||||
private DataSource codebase;
|
private DataSource codebase;
|
||||||
private War3MapViewer viewer;
|
private War3MapViewer viewer;
|
||||||
private CameraManager cameraManager;
|
private GameCameraManager cameraManager;
|
||||||
private final Rectangle tempRect = new Rectangle();
|
private final Rectangle tempRect = new Rectangle();
|
||||||
|
|
||||||
// libGDX stuff
|
// libGDX stuff
|
||||||
@ -146,7 +144,20 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cameraManager = new CameraManager();
|
final Element cameraData = this.viewer.miscData.get("Camera");
|
||||||
|
final Element cameraListenerData = this.viewer.miscData.get("Listener");
|
||||||
|
final CameraPreset[] cameraPresets = new CameraPreset[6];
|
||||||
|
for (int i = 0; i < cameraPresets.length; i++) {
|
||||||
|
cameraPresets[i] = new CameraPreset(cameraData.getFieldFloatValue("AOA", i),
|
||||||
|
cameraData.getFieldFloatValue("FOV", i), cameraData.getFieldFloatValue("Rotation", i),
|
||||||
|
cameraData.getFieldFloatValue("Rotation", i + cameraPresets.length),
|
||||||
|
cameraData.getFieldFloatValue("Rotation", i + (cameraPresets.length * 2)),
|
||||||
|
cameraData.getFieldFloatValue("Distance", i), cameraData.getFieldFloatValue("FarZ", i),
|
||||||
|
cameraData.getFieldFloatValue("NearZ", i), cameraData.getFieldFloatValue("Height", i),
|
||||||
|
cameraListenerData.getFieldFloatValue("ListenerDistance", i),
|
||||||
|
cameraListenerData.getFieldFloatValue("ListenerAOA", i));
|
||||||
|
}
|
||||||
|
this.cameraManager = new GameCameraManager(cameraPresets);
|
||||||
|
|
||||||
this.cameraManager.setupCamera(this.viewer.worldScene);
|
this.cameraManager.setupCamera(this.viewer.worldScene);
|
||||||
|
|
||||||
@ -287,9 +298,10 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
final float deltaTime = Gdx.graphics.getDeltaTime();
|
final float deltaTime = Gdx.graphics.getDeltaTime();
|
||||||
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
|
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
|
||||||
this.cameraManager.target.add(this.cameraVelocity.x * deltaTime, this.cameraVelocity.y * deltaTime, 0);
|
this.cameraManager.target.add(this.cameraVelocity.x * deltaTime, this.cameraVelocity.y * deltaTime, 0);
|
||||||
this.cameraManager.target.z = Math.max(
|
this.cameraManager.target.z = (Math.max(
|
||||||
this.viewer.terrain.getGroundHeight(this.cameraManager.target.x, this.cameraManager.target.y),
|
this.viewer.terrain.getGroundHeight(this.cameraManager.target.x, this.cameraManager.target.y),
|
||||||
this.viewer.terrain.getWaterHeight(this.cameraManager.target.x, this.cameraManager.target.y)) - 256;
|
this.viewer.terrain.getWaterHeight(this.cameraManager.target.x, this.cameraManager.target.y)) - 256)
|
||||||
|
+ this.cameraManager.presets[this.cameraManager.currentPreset].height + 256;
|
||||||
this.cameraManager.updateCamera();
|
this.cameraManager.updateCamera();
|
||||||
this.meleeUI.updatePortrait();
|
this.meleeUI.updatePortrait();
|
||||||
this.viewer.updateAndRender();
|
this.viewer.updateAndRender();
|
||||||
@ -400,28 +412,26 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
this.meleeUI.resize();
|
this.meleeUI.resize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CameraManager {
|
public static abstract class CameraManager {
|
||||||
private final float[] cameraPositionTemp = new float[3];
|
protected final float[] cameraPositionTemp = new float[3];
|
||||||
private final float[] cameraTargetTemp = new float[3];
|
protected final float[] cameraTargetTemp = new float[3];
|
||||||
public com.etheller.warsmash.viewer5.handlers.mdx.Camera modelCamera;
|
protected CanvasProvider canvas;
|
||||||
private MdxComplexInstance modelInstance;
|
protected Camera camera;
|
||||||
private CanvasProvider canvas;
|
protected float moveSpeed;
|
||||||
private Camera camera;
|
protected float rotationSpeed;
|
||||||
private float moveSpeed;
|
protected float zoomFactor;
|
||||||
private float rotationSpeed;
|
protected float horizontalAngle;
|
||||||
private float zoomFactor;
|
protected float verticalAngle;
|
||||||
private float horizontalAngle;
|
protected float distance;
|
||||||
private float verticalAngle;
|
protected Vector3 position;
|
||||||
private float verticalAngleAcceleration;
|
protected Vector3 target;
|
||||||
private float distance;
|
protected Vector3 worldUp;
|
||||||
private Vector3 position;
|
protected Vector3 vecHeap;
|
||||||
private Vector3 target;
|
protected Quaternion quatHeap;
|
||||||
private Vector3 worldUp;
|
protected Quaternion quatHeap2;
|
||||||
private Vector3 vecHeap;
|
|
||||||
private Quaternion quatHeap;
|
public CameraManager() {
|
||||||
private Quaternion quatHeap2;
|
}
|
||||||
private boolean insertDown;
|
|
||||||
private boolean deleteDown;
|
|
||||||
|
|
||||||
// An orbit camera setup example.
|
// An orbit camera setup example.
|
||||||
// Left mouse button controls the orbit itself.
|
// Left mouse button controls the orbit itself.
|
||||||
@ -449,45 +459,58 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
// cameraUpdate();
|
// cameraUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract void updateCamera();
|
||||||
|
|
||||||
|
// private void cameraUpdate() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class GameCameraManager extends CameraManager {
|
||||||
|
private final CameraPreset[] presets;
|
||||||
|
private int currentPreset = 0;
|
||||||
|
|
||||||
|
protected boolean insertDown;
|
||||||
|
protected boolean deleteDown;
|
||||||
|
|
||||||
|
public GameCameraManager(final CameraPreset[] presets) {
|
||||||
|
this.presets = presets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void updateCamera() {
|
public void updateCamera() {
|
||||||
|
this.quatHeap2.idt();
|
||||||
|
final CameraPreset cameraPreset = this.presets[this.currentPreset];
|
||||||
this.quatHeap.idt();
|
this.quatHeap.idt();
|
||||||
|
this.horizontalAngle = (float) Math
|
||||||
|
.toRadians(cameraPreset.getRotation(this.insertDown, this.deleteDown) - 90);
|
||||||
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
|
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
|
||||||
if (this.insertDown && !this.deleteDown) {
|
this.distance = Math.max(1200, cameraPreset.distance);
|
||||||
this.horizontalAngle -= HORIZONTAL_ANGLE_INCREMENT;
|
this.verticalAngle = (float) Math.toRadians(Math.min(335, cameraPreset.aoa) - 270);
|
||||||
if (this.horizontalAngle < HORIZONTAL_MINIMUM) {
|
this.quatHeap2.setFromAxisRad(1, 0, 0, this.verticalAngle);
|
||||||
this.horizontalAngle = HORIZONTAL_MINIMUM;
|
this.quatHeap.mul(this.quatHeap2);
|
||||||
}
|
|
||||||
}
|
this.position.set(0, 0, 1);
|
||||||
else if (this.deleteDown && !this.insertDown) {
|
this.quatHeap.transform(this.position);
|
||||||
this.horizontalAngle += HORIZONTAL_ANGLE_INCREMENT;
|
this.position.nor();
|
||||||
if (this.horizontalAngle > HORIZONTAL_MAXIMUM) {
|
this.position.scl(this.distance);
|
||||||
this.horizontalAngle = HORIZONTAL_MAXIMUM;
|
this.position = this.position.add(this.target);
|
||||||
}
|
this.camera.perspective((float) Math.toRadians(cameraPreset.fov / 2), this.camera.getAspect(),
|
||||||
}
|
cameraPreset.nearZ, cameraPreset.farZ);
|
||||||
else {
|
|
||||||
if (Math.abs(this.horizontalAngle) < HORIZONTAL_ANGLE_INCREMENT) {
|
this.camera.moveToAndFace(this.position, this.target, this.worldUp);
|
||||||
this.horizontalAngle = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.horizontalAngle -= HORIZONTAL_ANGLE_INCREMENT * Math.signum(this.horizontalAngle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final class PortraitCameraManager extends CameraManager {
|
||||||
|
public com.etheller.warsmash.viewer5.handlers.mdx.Camera modelCamera;
|
||||||
|
protected MdxComplexInstance modelInstance;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateCamera() {
|
||||||
|
this.quatHeap.idt();
|
||||||
|
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
|
||||||
this.quatHeap2.idt();
|
this.quatHeap2.idt();
|
||||||
this.verticalAngle += this.verticalAngleAcceleration;
|
|
||||||
this.verticalAngleAcceleration *= 0.975f;
|
|
||||||
if (this.verticalAngle > ((Math.PI / 2) - Math.toRadians(17))) {
|
|
||||||
this.verticalAngle = (float) ((Math.PI / 2) - Math.toRadians(17));
|
|
||||||
if (this.verticalAngleAcceleration > 0) {
|
|
||||||
this.verticalAngleAcceleration = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.verticalAngle < (float) Math.toRadians(34)) {
|
|
||||||
this.verticalAngle = (float) Math.toRadians(34);
|
|
||||||
if (this.verticalAngleAcceleration < 0) {
|
|
||||||
this.verticalAngleAcceleration = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.quatHeap2.setFromAxisRad(1, 0, 0, this.verticalAngle);
|
this.quatHeap2.setFromAxisRad(1, 0, 0, this.verticalAngle);
|
||||||
this.quatHeap.mul(this.quatHeap2);
|
this.quatHeap.mul(this.quatHeap2);
|
||||||
|
|
||||||
@ -525,10 +548,6 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
this.modelCamera = portraitModel.getCameras().get(0);
|
this.modelCamera = portraitModel.getCameras().get(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void cameraUpdate() {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final float cameraSpeed = 4096.0f; // per second
|
private final float cameraSpeed = 4096.0f; // per second
|
||||||
@ -697,12 +716,12 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean scrolled(final int amount) {
|
public boolean scrolled(final int amount) {
|
||||||
this.cameraManager.verticalAngleAcceleration -= amount / 100.f;
|
this.cameraManager.currentPreset -= amount;
|
||||||
if (this.cameraManager.verticalAngleAcceleration > (Math.PI / 128)) {
|
if (this.cameraManager.currentPreset < 0) {
|
||||||
this.cameraManager.verticalAngleAcceleration = (float) (Math.PI / 128);
|
this.cameraManager.currentPreset = 0;
|
||||||
}
|
}
|
||||||
if (this.cameraManager.verticalAngleAcceleration < (-Math.PI / 128)) {
|
if (this.cameraManager.currentPreset >= this.cameraManager.presets.length) {
|
||||||
this.cameraManager.verticalAngleAcceleration = -(float) (Math.PI / 128);
|
this.cameraManager.currentPreset = this.cameraManager.presets.length - 1;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -716,4 +735,44 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class CameraPreset {
|
||||||
|
private final float aoa;
|
||||||
|
private final float fov;
|
||||||
|
private final float rotation;
|
||||||
|
private final float rotationInsert;
|
||||||
|
private final float rotationDelete;
|
||||||
|
private final float distance;
|
||||||
|
private final float farZ;
|
||||||
|
private final float nearZ;
|
||||||
|
private final float height;
|
||||||
|
private final float listenerDistance;
|
||||||
|
private final float listenerAOA;
|
||||||
|
|
||||||
|
public CameraPreset(final float aoa, final float fov, final float rotation, final float rotationInsert,
|
||||||
|
final float rotationDelete, final float distance, final float farZ, final float nearZ,
|
||||||
|
final float height, final float listenerDistance, final float listenerAOA) {
|
||||||
|
this.aoa = aoa;
|
||||||
|
this.fov = fov;
|
||||||
|
this.rotation = rotation;
|
||||||
|
this.rotationInsert = rotationInsert;
|
||||||
|
this.rotationDelete = rotationDelete;
|
||||||
|
this.distance = distance;
|
||||||
|
this.farZ = farZ;
|
||||||
|
this.nearZ = nearZ;
|
||||||
|
this.height = height;
|
||||||
|
this.listenerDistance = listenerDistance;
|
||||||
|
this.listenerAOA = listenerAOA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRotation(final boolean insertDown, final boolean deleteDown) {
|
||||||
|
if (insertDown && !deleteDown) {
|
||||||
|
return this.rotationInsert;
|
||||||
|
}
|
||||||
|
if (!insertDown && deleteDown) {
|
||||||
|
return this.rotationDelete;
|
||||||
|
}
|
||||||
|
return this.rotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,6 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
|
|||||||
final MdxModel model = (MdxModel) this.modelViewer.load(backgroundArt, this.modelViewer.mapPathSolver,
|
final MdxModel model = (MdxModel) this.modelViewer.load(backgroundArt, this.modelViewer.mapPathSolver,
|
||||||
this.modelViewer.solverParams);
|
this.modelViewer.solverParams);
|
||||||
spriteFrame.setModel(model);
|
spriteFrame.setModel(model);
|
||||||
spriteFrame.setSequence(0);
|
|
||||||
viewport2 = this.fdfCoordinateResolutionDummyViewport;
|
viewport2 = this.fdfCoordinateResolutionDummyViewport;
|
||||||
inflatedFrame = spriteFrame;
|
inflatedFrame = spriteFrame;
|
||||||
}
|
}
|
||||||
|
@ -50,4 +50,22 @@ public class SpriteFrame extends AbstractRenderableFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAnimationSpeed(final float speedRatio) {
|
||||||
|
if (this.instance != null) {
|
||||||
|
this.instance.setAnimationSpeed(speedRatio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrame(final int animationFrame) {
|
||||||
|
if (this.instance != null) {
|
||||||
|
this.instance.setFrame(animationFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrameByRatio(final float ratioOfAnimationCompleted) {
|
||||||
|
if (this.instance != null) {
|
||||||
|
this.instance.setFrameByRatio(ratioOfAnimationCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ public interface GameObject {
|
|||||||
|
|
||||||
public float getFieldFloatValue(String field);
|
public float getFieldFloatValue(String field);
|
||||||
|
|
||||||
|
public float getFieldFloatValue(String field, int index);
|
||||||
|
|
||||||
public List<? extends GameObject> getFieldAsList(String field, ObjectData objectData);
|
public List<? extends GameObject> getFieldAsList(String field, ObjectData objectData);
|
||||||
|
|
||||||
public String getId();
|
public String getId();
|
||||||
@ -75,6 +77,11 @@ public interface GameObject {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getFieldFloatValue(final String field, final int index) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<? extends GameObject> getFieldAsList(final String field, final ObjectData objectData) {
|
public List<? extends GameObject> getFieldAsList(final String field, final ObjectData objectData) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
@ -79,6 +79,18 @@ public abstract class HashedGameObject implements GameObject {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getFieldFloatValue(final String field, final int index) {
|
||||||
|
float i = 0;
|
||||||
|
try {
|
||||||
|
i = Float.parseFloat(getField(field, index));
|
||||||
|
}
|
||||||
|
catch (final NumberFormatException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setField(final String field, final String value, final int index) {
|
public void setField(final String field, final String value, final int index) {
|
||||||
final StringKey key = new StringKey(field);
|
final StringKey key = new StringKey(field);
|
||||||
|
@ -504,6 +504,17 @@ public class StandardObjectData {
|
|||||||
return 0f;
|
return 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getFieldFloatValue(final String field, final int index) {
|
||||||
|
for (final DataTable table : this.dataSource.getTables()) {
|
||||||
|
final Element element = table.get(this.id);
|
||||||
|
if ((element != null) && element.hasField(field)) {
|
||||||
|
return element.getFieldFloatValue(field, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc) I'm not entirely sure this is still safe to use
|
* (non-Javadoc) I'm not entirely sure this is still safe to use
|
||||||
*
|
*
|
||||||
|
@ -8,10 +8,12 @@ import java.nio.IntBuffer;
|
|||||||
import java.nio.ShortBuffer;
|
import java.nio.ShortBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.math.Intersector;
|
||||||
import com.badlogic.gdx.math.Matrix4;
|
import com.badlogic.gdx.math.Matrix4;
|
||||||
import com.badlogic.gdx.math.Quaternion;
|
import com.badlogic.gdx.math.Quaternion;
|
||||||
import com.badlogic.gdx.math.Rectangle;
|
import com.badlogic.gdx.math.Rectangle;
|
||||||
import com.badlogic.gdx.math.Vector3;
|
import com.badlogic.gdx.math.Vector3;
|
||||||
|
import com.badlogic.gdx.math.collision.Ray;
|
||||||
|
|
||||||
public enum RenderMathUtils {
|
public enum RenderMathUtils {
|
||||||
;
|
;
|
||||||
@ -451,6 +453,128 @@ public enum RenderMathUtils {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Vector3 best = new Vector3();
|
||||||
|
static Vector3 tmp = new Vector3();
|
||||||
|
static Vector3 tmp1 = new Vector3();
|
||||||
|
static Vector3 tmp2 = new Vector3();
|
||||||
|
static Vector3 tmp3 = new Vector3();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intersects the given ray with list of triangles. Returns the nearest
|
||||||
|
* intersection point in intersection
|
||||||
|
*
|
||||||
|
* @param ray The ray
|
||||||
|
* @param vertices the vertices
|
||||||
|
* @param indices the indices, each successive 3 shorts index the 3
|
||||||
|
* vertices of a triangle
|
||||||
|
* @param vertexSize the size of a vertex in floats
|
||||||
|
* @param intersection The nearest intersection point (optional)
|
||||||
|
* @return Whether the ray and the triangles intersect.
|
||||||
|
*/
|
||||||
|
public static boolean intersectRayTriangles(final Ray ray, final float[] vertices, final int[] indices,
|
||||||
|
final int vertexSize, final Vector3 intersection) {
|
||||||
|
float min_dist = Float.MAX_VALUE;
|
||||||
|
boolean hit = false;
|
||||||
|
|
||||||
|
if ((indices.length % 3) != 0) {
|
||||||
|
throw new RuntimeException("triangle list size is not a multiple of 3");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < indices.length; i += 3) {
|
||||||
|
final int i1 = indices[i] * vertexSize;
|
||||||
|
final int i2 = indices[i + 1] * vertexSize;
|
||||||
|
final int i3 = indices[i + 2] * vertexSize;
|
||||||
|
|
||||||
|
final boolean result = Intersector.intersectRayTriangle(ray,
|
||||||
|
tmp1.set(vertices[i1], vertices[i1 + 1], vertices[i1 + 2]),
|
||||||
|
tmp2.set(vertices[i2], vertices[i2 + 1], vertices[i2 + 2]),
|
||||||
|
tmp3.set(vertices[i3], vertices[i3 + 1], vertices[i3 + 2]), tmp);
|
||||||
|
|
||||||
|
if (result == true) {
|
||||||
|
final float dist = ray.origin.dst2(tmp);
|
||||||
|
if (dist < min_dist) {
|
||||||
|
min_dist = dist;
|
||||||
|
best.set(tmp);
|
||||||
|
hit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hit == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (intersection != null) {
|
||||||
|
intersection.set(best);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intersects the given ray with list of triangles. Returns the nearest
|
||||||
|
* intersection point in intersection
|
||||||
|
*
|
||||||
|
* @param ray The ray
|
||||||
|
* @param vertices the vertices
|
||||||
|
* @param indices the indices, each successive 3 shorts index the 3
|
||||||
|
* vertices of a triangle
|
||||||
|
* @param vertexSize the size of a vertex in floats
|
||||||
|
* @param intersection The nearest intersection point (optional)
|
||||||
|
* @return Whether the ray and the triangles intersect.
|
||||||
|
*/
|
||||||
|
public static boolean intersectRayTriangles(final Ray ray, final float[] vertices, final int[] indices,
|
||||||
|
final int vertexSize, final Vector3 worldLocation, final float facingRadians, final Vector3 intersection) {
|
||||||
|
float min_dist = Float.MAX_VALUE;
|
||||||
|
boolean hit = false;
|
||||||
|
|
||||||
|
if ((indices.length % 3) != 0) {
|
||||||
|
throw new RuntimeException("triangle list size is not a multiple of 3");
|
||||||
|
}
|
||||||
|
|
||||||
|
final float facingX_X = (float) Math.cos(facingRadians);
|
||||||
|
final float facingX_Y = (float) Math.sin(facingRadians);
|
||||||
|
final double halfPi = Math.PI / 2;
|
||||||
|
final float facingY_X = (float) Math.cos(facingRadians + halfPi);
|
||||||
|
final float facingY_Y = (float) Math.sin(facingRadians + halfPi);
|
||||||
|
for (int i = 0; i < indices.length; i += 3) {
|
||||||
|
final int i1 = indices[i] * vertexSize;
|
||||||
|
final int i2 = indices[i + 1] * vertexSize;
|
||||||
|
final int i3 = indices[i + 2] * vertexSize;
|
||||||
|
|
||||||
|
final boolean result = Intersector.intersectRayTriangle(ray,
|
||||||
|
tmp1.set((vertices[i1] * facingX_X) + (vertices[i1 + 1] * facingY_X) + worldLocation.x,
|
||||||
|
(vertices[i1] * facingX_Y) + (vertices[i1 + 1] * facingY_Y) + worldLocation.y,
|
||||||
|
vertices[i1 + 2] + worldLocation.z),
|
||||||
|
tmp2.set((vertices[i2] * facingX_X) + (vertices[i2 + 1] * facingY_X) + worldLocation.x,
|
||||||
|
(vertices[i2] * facingX_Y) + (vertices[i2 + 1] * facingY_Y) + worldLocation.y,
|
||||||
|
vertices[i2 + 2] + worldLocation.z),
|
||||||
|
tmp3.set((vertices[i3] * facingX_X) + (vertices[i3 + 1] * facingY_X) + worldLocation.x,
|
||||||
|
(vertices[i3] * facingX_Y) + (vertices[i3 + 1] * facingY_Y) + worldLocation.y,
|
||||||
|
vertices[i3 + 2] + worldLocation.z),
|
||||||
|
tmp);
|
||||||
|
|
||||||
|
if (result == true) {
|
||||||
|
final float dist = ray.origin.dst2(tmp);
|
||||||
|
if (dist < min_dist) {
|
||||||
|
min_dist = dist;
|
||||||
|
best.set(tmp);
|
||||||
|
hit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hit == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (intersection != null) {
|
||||||
|
intersection.set(best);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ==== All of the following "wrap" calls are horribly inefficient. Eventually
|
// ==== All of the following "wrap" calls are horribly inefficient. Eventually
|
||||||
// they should be removed entirely with better design.
|
// they should be removed entirely with better design.
|
||||||
// Until that happens, be sure to only call them during setup and not while the
|
// Until that happens, be sure to only call them during setup and not while the
|
||||||
|
@ -77,9 +77,13 @@ public abstract class ModelInstance extends Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateLights(scene);
|
||||||
|
|
||||||
this.updateFrame = this.model.viewer.frame;
|
this.updateFrame = this.model.viewer.frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract void updateLights(Scene scene2);
|
||||||
|
|
||||||
public boolean setScene(final Scene scene) {
|
public boolean setScene(final Scene scene) {
|
||||||
return scene.addInstance(this);
|
return scene.addInstance(this);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ import com.etheller.warsmash.viewer5.gl.WebGL;
|
|||||||
import com.etheller.warsmash.viewer5.handlers.ResourceHandler;
|
import com.etheller.warsmash.viewer5.handlers.ResourceHandler;
|
||||||
import com.etheller.warsmash.viewer5.handlers.ResourceHandlerConstructionParams;
|
import com.etheller.warsmash.viewer5.handlers.ResourceHandlerConstructionParams;
|
||||||
|
|
||||||
public class ModelViewer {
|
public abstract class ModelViewer {
|
||||||
public DataSource dataSource;
|
public DataSource dataSource;
|
||||||
public final CanvasProvider canvas;
|
public final CanvasProvider canvas;
|
||||||
public List<Resource> resources;
|
public List<Resource> resources;
|
||||||
@ -366,4 +366,6 @@ public class ModelViewer {
|
|||||||
private void onResourceLoadError() {
|
private void onResourceLoadError() {
|
||||||
System.err.println("error, this, InvalidHandler, FailedToLoad");
|
System.err.println("error, this, InvalidHandler, FailedToLoad");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract SceneLightManager createLightManager();
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ public abstract class Scene {
|
|||||||
* If true, alpha works as usual.
|
* If true, alpha works as usual.
|
||||||
*/
|
*/
|
||||||
public boolean alpha = false;
|
public boolean alpha = false;
|
||||||
|
private final SceneLightManager lightManager;
|
||||||
|
|
||||||
public Scene(final ModelViewer viewer) {
|
public Scene(final ModelViewer viewer) {
|
||||||
final CanvasProvider canvas = viewer.canvas;
|
final CanvasProvider canvas = viewer.canvas;
|
||||||
@ -85,6 +86,8 @@ public abstract class Scene {
|
|||||||
this.instanceDepthComparator = new InstanceDepthComparator();
|
this.instanceDepthComparator = new InstanceDepthComparator();
|
||||||
this.visibleCells = 0;
|
this.visibleCells = 0;
|
||||||
this.visibleInstances = 0;
|
this.visibleInstances = 0;
|
||||||
|
|
||||||
|
this.lightManager = this.viewer.createLightManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean enableAudio() {
|
public boolean enableAudio() {
|
||||||
@ -300,6 +303,14 @@ public abstract class Scene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addLight(final SceneLightInstance lightInstance) {
|
||||||
|
this.lightManager.add(lightInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeLight(final SceneLightInstance lightInstance) {
|
||||||
|
this.lightManager.remove(lightInstance);
|
||||||
|
}
|
||||||
|
|
||||||
private static final class InstanceDepthComparator implements Comparator<ModelInstance> {
|
private static final class InstanceDepthComparator implements Comparator<ModelInstance> {
|
||||||
@Override
|
@Override
|
||||||
public int compare(final ModelInstance o1, final ModelInstance o2) {
|
public int compare(final ModelInstance o1, final ModelInstance o2) {
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.etheller.warsmash.viewer5;
|
||||||
|
|
||||||
|
public interface SceneLightInstance {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.etheller.warsmash.viewer5;
|
||||||
|
|
||||||
|
public interface SceneLightManager {
|
||||||
|
public void add(final SceneLightInstance lightInstance);
|
||||||
|
|
||||||
|
public void remove(final SceneLightInstance lightInstance);
|
||||||
|
}
|
@ -5,6 +5,8 @@ import com.badlogic.gdx.math.Matrix4;
|
|||||||
import com.badlogic.gdx.math.Vector3;
|
import com.badlogic.gdx.math.Vector3;
|
||||||
import com.badlogic.gdx.math.collision.BoundingBox;
|
import com.badlogic.gdx.math.collision.BoundingBox;
|
||||||
import com.badlogic.gdx.math.collision.Ray;
|
import com.badlogic.gdx.math.collision.Ray;
|
||||||
|
import com.etheller.warsmash.util.RenderMathUtils;
|
||||||
|
import com.etheller.warsmash.viewer5.GenericNode;
|
||||||
|
|
||||||
public class CollisionShape extends GenericObject {
|
public class CollisionShape extends GenericObject {
|
||||||
private static Vector3 intersectHeap = new Vector3();
|
private static Vector3 intersectHeap = new Vector3();
|
||||||
@ -87,4 +89,22 @@ public class CollisionShape extends GenericObject {
|
|||||||
return Intersector.intersectRaySphere(ray, intersectHeap, this.radius, intersection);
|
return Intersector.intersectRaySphere(ray, intersectHeap, this.radius, intersection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean intersectRayTriangles(final Ray ray, final GenericNode mdxNode, final float[] vertices,
|
||||||
|
final int[] indices, final int vertexSize, final Vector3 intersection) {
|
||||||
|
intersectMatrixHeap.set(mdxNode.worldMatrix);
|
||||||
|
Matrix4.inv(intersectMatrixHeap.val);
|
||||||
|
intersectHeap.set(ray.origin);
|
||||||
|
intersectHeap2.set(ray.direction);
|
||||||
|
intersectHeap2.add(ray.origin);
|
||||||
|
intersectHeap.prj(intersectMatrixHeap);
|
||||||
|
intersectHeap2.prj(intersectMatrixHeap);
|
||||||
|
intersectHeap2.sub(intersectHeap);
|
||||||
|
intersectRayHeap.set(intersectHeap, intersectHeap2);
|
||||||
|
if (RenderMathUtils.intersectRayTriangles(intersectRayHeap, vertices, indices, vertexSize, intersection)) {
|
||||||
|
intersection.prj(mdxNode.worldMatrix);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,13 @@ public class Geoset {
|
|||||||
private final int openGLSkinType;
|
private final int openGLSkinType;
|
||||||
private final int skinStride;
|
private final int skinStride;
|
||||||
private final int boneCountOffsetBytes;
|
private final int boneCountOffsetBytes;
|
||||||
|
public final boolean unselectable;
|
||||||
|
public final com.etheller.warsmash.parsers.mdlx.Geoset mdlxGeoset;
|
||||||
|
|
||||||
public Geoset(final MdxModel model, final int index, final int positionOffset, final int normalOffset,
|
public Geoset(final MdxModel model, final int index, final int positionOffset, final int normalOffset,
|
||||||
final int uvOffset, final int skinOffset, final int faceOffset, final int vertices, final int elements,
|
final int uvOffset, final int skinOffset, final int faceOffset, final int vertices, final int elements,
|
||||||
final int openGLSkinType, final int skinStride, final int boneCountOffsetBytes) {
|
final int openGLSkinType, final int skinStride, final int boneCountOffsetBytes, final boolean unselectable,
|
||||||
|
final com.etheller.warsmash.parsers.mdlx.Geoset mdlxGeoset) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.positionOffset = positionOffset;
|
this.positionOffset = positionOffset;
|
||||||
@ -40,6 +43,8 @@ public class Geoset {
|
|||||||
this.openGLSkinType = openGLSkinType;
|
this.openGLSkinType = openGLSkinType;
|
||||||
this.skinStride = skinStride;
|
this.skinStride = skinStride;
|
||||||
this.boneCountOffsetBytes = boneCountOffsetBytes;
|
this.boneCountOffsetBytes = boneCountOffsetBytes;
|
||||||
|
this.unselectable = unselectable;
|
||||||
|
this.mdlxGeoset = mdlxGeoset;
|
||||||
|
|
||||||
for (final GeosetAnimation geosetAnimation : model.getGeosetAnimations()) {
|
for (final GeosetAnimation geosetAnimation : model.getGeosetAnimations()) {
|
||||||
if (geosetAnimation.geosetId == index) {
|
if (geosetAnimation.geosetId == index) {
|
||||||
|
@ -4,7 +4,7 @@ import com.etheller.warsmash.parsers.mdlx.AnimationMap;
|
|||||||
|
|
||||||
public class Light extends GenericObject {
|
public class Light extends GenericObject {
|
||||||
|
|
||||||
private final int type;
|
private final Type type;
|
||||||
private final float[] attenuation;
|
private final float[] attenuation;
|
||||||
private final float[] color;
|
private final float[] color;
|
||||||
private final float intensity;
|
private final float intensity;
|
||||||
@ -14,7 +14,18 @@ public class Light extends GenericObject {
|
|||||||
public Light(final MdxModel model, final com.etheller.warsmash.parsers.mdlx.Light light, final int index) {
|
public Light(final MdxModel model, final com.etheller.warsmash.parsers.mdlx.Light light, final int index) {
|
||||||
super(model, light, index);
|
super(model, light, index);
|
||||||
|
|
||||||
this.type = light.getType();
|
switch (light.getType()) {
|
||||||
|
case 0:
|
||||||
|
this.type = Type.OMNIDIRECTIONAL;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this.type = Type.DIRECTIONAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case 1:
|
||||||
|
this.type = Type.AMBIENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
this.attenuation = light.getAttenuation();
|
this.attenuation = light.getAttenuation();
|
||||||
this.color = light.getColor();
|
this.color = light.getColor();
|
||||||
this.intensity = light.getIntensity();
|
this.intensity = light.getIntensity();
|
||||||
@ -22,6 +33,10 @@ public class Light extends GenericObject {
|
|||||||
this.ambientIntensity = light.getAmbientIntensity();
|
this.ambientIntensity = light.getAmbientIntensity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
public int getAttenuationStart(final float[] out, final int sequence, final int frame, final int counter) {
|
public int getAttenuationStart(final float[] out, final int sequence, final int frame, final int counter) {
|
||||||
return this.getScalarValue(out, AnimationMap.KLAS.getWar3id(), sequence, frame, counter, this.attenuation[0]);
|
return this.getScalarValue(out, AnimationMap.KLAS.getWar3id(), sequence, frame, counter, this.attenuation[0]);
|
||||||
}
|
}
|
||||||
@ -45,4 +60,15 @@ public class Light extends GenericObject {
|
|||||||
public int getAmbientColor(final float[] out, final int sequence, final int frame, final int counter) {
|
public int getAmbientColor(final float[] out, final int sequence, final int frame, final int counter) {
|
||||||
return this.getVectorValue(out, AnimationMap.KLBC.getWar3id(), sequence, frame, counter, this.ambientColor);
|
return this.getVectorValue(out, AnimationMap.KLBC.getWar3id(), sequence, frame, counter, this.ambientColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static enum Type {
|
||||||
|
// Omnidirectional light used for in-game sun
|
||||||
|
OMNIDIRECTIONAL,
|
||||||
|
// Directional light used for torches in the game world, and similar objects
|
||||||
|
// that "glow"
|
||||||
|
DIRECTIONAL,
|
||||||
|
// Directional ambient light used for torches in the game world, and similar
|
||||||
|
// objects that "glow"
|
||||||
|
AMBIENT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.mdx;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.viewer5.Scene;
|
||||||
|
import com.etheller.warsmash.viewer5.SceneLightInstance;
|
||||||
|
import com.etheller.warsmash.viewer5.UpdatableObject;
|
||||||
|
|
||||||
|
public class LightInstance implements UpdatableObject, SceneLightInstance {
|
||||||
|
private static final float[] vectorHeap = new float[3];
|
||||||
|
private static final float[] scalarHeap = new float[1];
|
||||||
|
protected final MdxNode node;
|
||||||
|
protected final Light light;
|
||||||
|
private boolean visible;
|
||||||
|
private boolean loadedInScene;
|
||||||
|
|
||||||
|
public LightInstance(final MdxComplexInstance instance, final Light light) {
|
||||||
|
this.node = instance.nodes[light.index];
|
||||||
|
this.light = light;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind(final int offset, final FloatBuffer floatBuffer, final int sequence, final int frame,
|
||||||
|
final int counter) {
|
||||||
|
this.light.getAttenuationStart(scalarHeap, sequence, frame, counter);
|
||||||
|
final float attenuationStart = scalarHeap[0];
|
||||||
|
this.light.getAttenuationEnd(scalarHeap, sequence, frame, counter);
|
||||||
|
final float attenuationEnd = scalarHeap[0];
|
||||||
|
this.light.getIntensity(scalarHeap, sequence, frame, counter);
|
||||||
|
final float intensity = scalarHeap[0];
|
||||||
|
this.light.getColor(vectorHeap, sequence, frame, counter);
|
||||||
|
final float colorRed = vectorHeap[0];
|
||||||
|
final float colorGreen = vectorHeap[1];
|
||||||
|
final float colorBlue = vectorHeap[2];
|
||||||
|
this.light.getAmbientIntensity(scalarHeap, sequence, frame, counter);
|
||||||
|
final float ambientIntensity = scalarHeap[0];
|
||||||
|
this.light.getAmbientColor(vectorHeap, sequence, frame, counter);
|
||||||
|
final float ambientColorRed = vectorHeap[0];
|
||||||
|
final float ambientColorGreen = vectorHeap[1];
|
||||||
|
final float ambientColorBlue = vectorHeap[2];
|
||||||
|
floatBuffer.put(offset, this.node.worldLocation.x);
|
||||||
|
floatBuffer.put(offset + 1, this.node.worldLocation.y);
|
||||||
|
floatBuffer.put(offset + 2, this.node.worldLocation.z);
|
||||||
|
// I use some padding to make the memory structure of the light be a 4x4 float
|
||||||
|
// grid, when somebody who actually has experience with this stuff comes along
|
||||||
|
// to change this to something smart, maybe they'll remove the padding if it's
|
||||||
|
// not necessary. I'm basing how I implement this on how Ghostwolf did
|
||||||
|
// BoneTexture
|
||||||
|
floatBuffer.put(offset + 3, 0);
|
||||||
|
floatBuffer.put(offset + 4, this.light.getType().ordinal());
|
||||||
|
floatBuffer.put(offset + 5, attenuationStart);
|
||||||
|
floatBuffer.put(offset + 6, attenuationEnd);
|
||||||
|
floatBuffer.put(offset + 7, 0);
|
||||||
|
floatBuffer.put(offset + 8, colorRed);
|
||||||
|
floatBuffer.put(offset + 9, colorGreen);
|
||||||
|
floatBuffer.put(offset + 10, colorBlue);
|
||||||
|
floatBuffer.put(offset + 11, intensity);
|
||||||
|
floatBuffer.put(offset + 12, ambientColorRed);
|
||||||
|
floatBuffer.put(offset + 13, ambientColorGreen);
|
||||||
|
floatBuffer.put(offset + 14, ambientColorBlue);
|
||||||
|
floatBuffer.put(offset + 15, ambientIntensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(final float dt, final boolean visible) {
|
||||||
|
this.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(final Scene scene) {
|
||||||
|
if (this.loadedInScene != this.visible) {
|
||||||
|
if (this.visible) {
|
||||||
|
scene.addLight(this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scene.removeLight(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,7 @@ public class MdxComplexInstance extends ModelInstance {
|
|||||||
private static final float[] alphaHeap = new float[1];
|
private static final float[] alphaHeap = new float[1];
|
||||||
private static final long[] textureIdHeap = new long[1];
|
private static final long[] textureIdHeap = new long[1];
|
||||||
|
|
||||||
|
public List<LightInstance> lights = new ArrayList<>();
|
||||||
public List<AttachmentInstance> attachments = new ArrayList<>();
|
public List<AttachmentInstance> attachments = new ArrayList<>();
|
||||||
public List<ParticleEmitter> particleEmitters = new ArrayList<>();
|
public List<ParticleEmitter> particleEmitters = new ArrayList<>();
|
||||||
public List<ParticleEmitter2> particleEmitters2 = new ArrayList<>();
|
public List<ParticleEmitter2> particleEmitters2 = new ArrayList<>();
|
||||||
@ -106,7 +107,9 @@ public class MdxComplexInstance extends ModelInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (final Light light : model.lights) {
|
for (final Light light : model.lights) {
|
||||||
this.initNode(this.nodes, this.nodes[nodeIndex++], light);
|
final LightInstance lightInstance = new LightInstance(this, light);
|
||||||
|
this.lights.add(lightInstance);
|
||||||
|
this.initNode(this.nodes, this.nodes[nodeIndex++], light, lightInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final Helper helper : model.helpers) {
|
for (final Helper helper : model.helpers) {
|
||||||
@ -601,6 +604,13 @@ public class MdxComplexInstance extends ModelInstance {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateLights(final Scene scene) {
|
||||||
|
for (final LightInstance light : this.lights) {
|
||||||
|
light.update(scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the team color of this instance.
|
* Set the team color of this instance.
|
||||||
*/
|
*/
|
||||||
@ -715,16 +725,47 @@ public class MdxComplexInstance extends ModelInstance {
|
|||||||
* @param ray
|
* @param ray
|
||||||
*/
|
*/
|
||||||
public boolean intersectRayWithCollision(final Ray ray, final Vector3 intersection) {
|
public boolean intersectRayWithCollision(final Ray ray, final Vector3 intersection) {
|
||||||
for (final CollisionShape collisionShape : ((MdxModel) this.model).collisionShapes) {
|
final MdxModel mdxModel = (MdxModel) this.model;
|
||||||
|
final List<CollisionShape> collisionShapes = mdxModel.collisionShapes;
|
||||||
|
if (collisionShapes.isEmpty()) {
|
||||||
|
for (final Geoset geoset : mdxModel.geosets) {
|
||||||
|
if (!geoset.unselectable) {
|
||||||
|
geoset.getAlpha(alphaHeap, this.sequence, this.frame, this.counter);
|
||||||
|
if (alphaHeap[0] > 0) {
|
||||||
|
final com.etheller.warsmash.parsers.mdlx.Geoset mdlxGeoset = geoset.mdlxGeoset;
|
||||||
|
if (CollisionShape.intersectRayTriangles(ray, this, mdlxGeoset.getVertices(),
|
||||||
|
mdlxGeoset.getFaces(), 3, intersection)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (final CollisionShape collisionShape : collisionShapes) {
|
||||||
final MdxNode mdxNode = this.nodes[collisionShape.index];
|
final MdxNode mdxNode = this.nodes[collisionShape.index];
|
||||||
if (collisionShape.checkIntersect(ray, mdxNode, intersection)) {
|
if (collisionShape.checkIntersect(ray, mdxNode, intersection)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAnimationSpeed(final float speedRatio) {
|
public void setAnimationSpeed(final float speedRatio) {
|
||||||
this.animationSpeed = speedRatio;
|
this.animationSpeed = speedRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFrame(final int frame) {
|
||||||
|
this.frame = frame;
|
||||||
|
this.floatingFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrameByRatio(final float ratioOfAnimationCompleted) {
|
||||||
|
final Sequence currentlyPlayingSequence = ((MdxModel) this.model).sequences.get(this.sequence);
|
||||||
|
this.floatingFrame = currentlyPlayingSequence.getInterval()[0]
|
||||||
|
+ ((currentlyPlayingSequence.getInterval()[1] - currentlyPlayingSequence.getInterval()[0])
|
||||||
|
* ratioOfAnimationCompleted);
|
||||||
|
this.frame = (int) this.floatingFrame;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import com.etheller.warsmash.viewer5.BatchedInstance;
|
|||||||
import com.etheller.warsmash.viewer5.Model;
|
import com.etheller.warsmash.viewer5.Model;
|
||||||
import com.etheller.warsmash.viewer5.PathSolver;
|
import com.etheller.warsmash.viewer5.PathSolver;
|
||||||
import com.etheller.warsmash.viewer5.RenderBatch;
|
import com.etheller.warsmash.viewer5.RenderBatch;
|
||||||
|
import com.etheller.warsmash.viewer5.Scene;
|
||||||
import com.etheller.warsmash.viewer5.Texture;
|
import com.etheller.warsmash.viewer5.Texture;
|
||||||
import com.etheller.warsmash.viewer5.TextureMapper;
|
import com.etheller.warsmash.viewer5.TextureMapper;
|
||||||
|
|
||||||
@ -32,6 +33,10 @@ public class MdxSimpleInstance extends BatchedInstance {
|
|||||||
public void renderTranslucent() {
|
public void renderTranslucent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateLights(final Scene scene2) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load() {
|
public void load() {
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.mdx;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.datasources.DataSource;
|
||||||
|
import com.etheller.warsmash.viewer5.CanvasProvider;
|
||||||
|
import com.etheller.warsmash.viewer5.ModelViewer;
|
||||||
|
import com.etheller.warsmash.viewer5.SceneLightManager;
|
||||||
|
|
||||||
|
public class MdxViewer extends ModelViewer {
|
||||||
|
|
||||||
|
public MdxViewer(final DataSource dataSource, final CanvasProvider canvas) {
|
||||||
|
super(dataSource, canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SceneLightManager createLightManager() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -155,9 +155,10 @@ public class SetupGeosets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final boolean unselectable = geoset.getSelectionFlags() == 4;
|
||||||
final Geoset vGeoset = new Geoset(model, model.getGeosets().size(), positionOffset, normalOffset,
|
final Geoset vGeoset = new Geoset(model, model.getGeosets().size(), positionOffset, normalOffset,
|
||||||
uvOffset, skinOffset, faceOffset, vertices, faces.length, openGLSkinType, skinStride,
|
uvOffset, skinOffset, faceOffset, vertices, faces.length, openGLSkinType, skinStride,
|
||||||
boneCountOffsetBytes);
|
boneCountOffsetBytes, unselectable, geoset);
|
||||||
|
|
||||||
model.getGeosets().add(vGeoset);
|
model.getGeosets().add(vGeoset);
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ public class SequenceUtils {
|
|||||||
filtered.sort(STAND_SEQUENCE_COMPARATOR);
|
filtered.sort(STAND_SEQUENCE_COMPARATOR);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
final double randomRoll = Math.random() * 100;
|
||||||
for (final int l = filtered.size(); i < l; i++) {
|
for (final int l = filtered.size(); i < l; i++) {
|
||||||
final Sequence sequence = filtered.get(i).sequence;
|
final Sequence sequence = filtered.get(i).sequence;
|
||||||
final float rarity = sequence.getRarity();
|
final float rarity = sequence.getRarity();
|
||||||
@ -75,7 +76,7 @@ public class SequenceUtils {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Math.random() * 10) > rarity) {
|
if (randomRoll < (10 - rarity)) {
|
||||||
return filtered.get(i);
|
return filtered.get(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,6 +99,7 @@ public class SequenceUtils {
|
|||||||
filtered.sort(STAND_SEQUENCE_COMPARATOR);
|
filtered.sort(STAND_SEQUENCE_COMPARATOR);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
final double randomRoll = Math.random() * 100;
|
||||||
for (final int l = filtered.size(); i < l; i++) {
|
for (final int l = filtered.size(); i < l; i++) {
|
||||||
final Sequence sequence = filtered.get(i).sequence;
|
final Sequence sequence = filtered.get(i).sequence;
|
||||||
final float rarity = sequence.getRarity();
|
final float rarity = sequence.getRarity();
|
||||||
@ -106,7 +108,7 @@ public class SequenceUtils {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((Math.random() * 10) > rarity) && allowRarityVariations) {
|
if ((randomRoll < (10 - rarity)) && allowRarityVariations) {
|
||||||
return filtered.get(i);
|
return filtered.get(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x;
|
||||||
|
|
||||||
|
public class W3xSceneLight {
|
||||||
|
|
||||||
|
public static enum Type {
|
||||||
|
OMNIDIRECTIONAL,
|
||||||
|
DIRECTIONAL;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.viewer5.SceneLightInstance;
|
||||||
|
import com.etheller.warsmash.viewer5.SceneLightManager;
|
||||||
|
import com.etheller.warsmash.viewer5.gl.DataTexture;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.mdx.LightInstance;
|
||||||
|
|
||||||
|
public class W3xSceneLightManager implements SceneLightManager {
|
||||||
|
public final List<LightInstance> lights;
|
||||||
|
private final DataTexture unitLightsTexture;
|
||||||
|
private final DataTexture terrainLightsTexture;
|
||||||
|
|
||||||
|
public W3xSceneLightManager(final War3MapViewer viewer) {
|
||||||
|
this.lights = new ArrayList<>();
|
||||||
|
this.unitLightsTexture = new DataTexture(viewer.gl, 4, 4, 1);
|
||||||
|
this.terrainLightsTexture = new DataTexture(viewer.gl, 4, 4, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(final SceneLightInstance lightInstance) {
|
||||||
|
// TODO redesign to avoid cast
|
||||||
|
final LightInstance mdxLight = (LightInstance) lightInstance;
|
||||||
|
this.lights.add(mdxLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(final SceneLightInstance lightInstance) {
|
||||||
|
// TODO redesign to avoid cast
|
||||||
|
final LightInstance mdxLight = (LightInstance) lightInstance;
|
||||||
|
this.lights.remove(mdxLight);
|
||||||
|
}
|
||||||
|
}
|
@ -42,10 +42,12 @@ import com.etheller.warsmash.parsers.w3x.w3i.War3MapW3i;
|
|||||||
import com.etheller.warsmash.parsers.w3x.wpm.War3MapWpm;
|
import com.etheller.warsmash.parsers.w3x.wpm.War3MapWpm;
|
||||||
import com.etheller.warsmash.units.DataTable;
|
import com.etheller.warsmash.units.DataTable;
|
||||||
import com.etheller.warsmash.units.Element;
|
import com.etheller.warsmash.units.Element;
|
||||||
|
import com.etheller.warsmash.units.StandardObjectData;
|
||||||
import com.etheller.warsmash.units.manager.MutableObjectData;
|
import com.etheller.warsmash.units.manager.MutableObjectData;
|
||||||
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||||
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
||||||
import com.etheller.warsmash.util.MappedData;
|
import com.etheller.warsmash.util.MappedData;
|
||||||
|
import com.etheller.warsmash.util.RenderMathUtils;
|
||||||
import com.etheller.warsmash.util.War3ID;
|
import com.etheller.warsmash.util.War3ID;
|
||||||
import com.etheller.warsmash.util.WarsmashConstants;
|
import com.etheller.warsmash.util.WarsmashConstants;
|
||||||
import com.etheller.warsmash.util.WorldEditStrings;
|
import com.etheller.warsmash.util.WorldEditStrings;
|
||||||
@ -56,6 +58,7 @@ import com.etheller.warsmash.viewer5.ModelInstance;
|
|||||||
import com.etheller.warsmash.viewer5.ModelViewer;
|
import com.etheller.warsmash.viewer5.ModelViewer;
|
||||||
import com.etheller.warsmash.viewer5.PathSolver;
|
import com.etheller.warsmash.viewer5.PathSolver;
|
||||||
import com.etheller.warsmash.viewer5.Scene;
|
import com.etheller.warsmash.viewer5.Scene;
|
||||||
|
import com.etheller.warsmash.viewer5.SceneLightManager;
|
||||||
import com.etheller.warsmash.viewer5.Texture;
|
import com.etheller.warsmash.viewer5.Texture;
|
||||||
import com.etheller.warsmash.viewer5.WorldScene;
|
import com.etheller.warsmash.viewer5.WorldScene;
|
||||||
import com.etheller.warsmash.viewer5.gl.WebGL;
|
import com.etheller.warsmash.viewer5.gl.WebGL;
|
||||||
@ -118,7 +121,6 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
public SolverParams solverParams = new SolverParams();
|
public SolverParams solverParams = new SolverParams();
|
||||||
public WorldScene worldScene;
|
public WorldScene worldScene;
|
||||||
public boolean anyReady;
|
public boolean anyReady;
|
||||||
public boolean terrainCliffsAndWaterLoaded;
|
|
||||||
public MappedData terrainData = new MappedData();
|
public MappedData terrainData = new MappedData();
|
||||||
public MappedData cliffTypesData = new MappedData();
|
public MappedData cliffTypesData = new MappedData();
|
||||||
public MappedData waterData = new MappedData();
|
public MappedData waterData = new MappedData();
|
||||||
@ -151,9 +153,11 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
public List<RenderUnit> selected = new ArrayList<>();
|
public List<RenderUnit> selected = new ArrayList<>();
|
||||||
private DataTable unitAckSoundsTable;
|
private DataTable unitAckSoundsTable;
|
||||||
private DataTable unitCombatSoundsTable;
|
private DataTable unitCombatSoundsTable;
|
||||||
private DataTable miscData;
|
public DataTable miscData;
|
||||||
private DataTable unitGlobalStrings;
|
private DataTable unitGlobalStrings;
|
||||||
private MdxComplexInstance confirmationInstance;
|
private MdxComplexInstance confirmationInstance;
|
||||||
|
private MdxComplexInstance dncUnit;
|
||||||
|
private MdxComplexInstance dncTerrain;
|
||||||
public CSimulation simulation;
|
public CSimulation simulation;
|
||||||
private float updateTime;
|
private float updateTime;
|
||||||
|
|
||||||
@ -195,7 +199,6 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
stringDataCallback);
|
stringDataCallback);
|
||||||
|
|
||||||
// == when loaded, which is always in our system ==
|
// == when loaded, which is always in our system ==
|
||||||
this.terrainCliffsAndWaterLoaded = true;
|
|
||||||
this.terrainData.load(terrain.data.toString());
|
this.terrainData.load(terrain.data.toString());
|
||||||
this.cliffTypesData.load(cliffTypes.data.toString());
|
this.cliffTypesData.load(cliffTypes.data.toString());
|
||||||
this.waterData.load(water.data.toString());
|
this.waterData.load(water.data.toString());
|
||||||
@ -254,6 +257,9 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("Units\\MiscGame.txt")) {
|
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("Units\\MiscGame.txt")) {
|
||||||
this.miscData.readTXT(miscDataTxtStream, true);
|
this.miscData.readTXT(miscDataTxtStream, true);
|
||||||
}
|
}
|
||||||
|
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("UI\\SoundInfo\\MiscData.txt")) {
|
||||||
|
this.miscData.readTXT(miscDataTxtStream, true);
|
||||||
|
}
|
||||||
this.unitGlobalStrings = new DataTable(worldEditStrings);
|
this.unitGlobalStrings = new DataTable(worldEditStrings);
|
||||||
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("Units\\UnitGlobalStrings.txt")) {
|
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("Units\\UnitGlobalStrings.txt")) {
|
||||||
this.unitGlobalStrings.readTXT(miscDataTxtStream, true);
|
this.unitGlobalStrings.readTXT(miscDataTxtStream, true);
|
||||||
@ -342,8 +348,11 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
|
|
||||||
final War3MapWpm terrainPathing = this.mapMpq.readPathing();
|
final War3MapWpm terrainPathing = this.mapMpq.readPathing();
|
||||||
|
|
||||||
|
final StandardObjectData standardObjectData = new StandardObjectData(this.dataSource);
|
||||||
|
this.worldEditData = standardObjectData.getWorldEditData();
|
||||||
|
|
||||||
this.terrain = new Terrain(terrainData, terrainPathing, w3iFile, this.webGL, this.dataSource, worldEditStrings,
|
this.terrain = new Terrain(terrainData, terrainPathing, w3iFile, this.webGL, this.dataSource, worldEditStrings,
|
||||||
this);
|
this, this.worldEditData);
|
||||||
|
|
||||||
final float[] centerOffset = terrainData.getCenterOffset();
|
final float[] centerOffset = terrainData.getCenterOffset();
|
||||||
final int[] mapSize = terrainData.getMapSize();
|
final int[] mapSize = terrainData.getMapSize();
|
||||||
@ -363,13 +372,6 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
this.confirmationInstance.setSequence(0);
|
this.confirmationInstance.setSequence(0);
|
||||||
this.confirmationInstance.setScene(this.worldScene);
|
this.confirmationInstance.setScene(this.worldScene);
|
||||||
|
|
||||||
if (this.terrainCliffsAndWaterLoaded) {
|
|
||||||
this.loadTerrainCliffsAndWater(terrainData);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises");
|
|
||||||
}
|
|
||||||
|
|
||||||
final Warcraft3MapObjectData modifications = this.mapMpq.readModifications();
|
final Warcraft3MapObjectData modifications = this.mapMpq.readModifications();
|
||||||
this.simulation = new CSimulation(this.miscData, modifications.getUnits(), modifications.getAbilities(),
|
this.simulation = new CSimulation(this.miscData, modifications.getUnits(), modifications.getAbilities(),
|
||||||
new SimulationRenderController() {
|
new SimulationRenderController() {
|
||||||
@ -388,12 +390,7 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
final float projectileLaunchY = simulation.getUnitData().getProjectileLaunchY(typeId);
|
final float projectileLaunchY = simulation.getUnitData().getProjectileLaunchY(typeId);
|
||||||
final float projectileLaunchZ = simulation.getUnitData().getProjectileLaunchZ(typeId);
|
final float projectileLaunchZ = simulation.getUnitData().getProjectileLaunchZ(typeId);
|
||||||
|
|
||||||
if (missileArt.toLowerCase().endsWith(".mdl")) {
|
missileArt = mdx(missileArt);
|
||||||
missileArt = missileArt.substring(0, missileArt.length() - 4);
|
|
||||||
}
|
|
||||||
if (!missileArt.toLowerCase().endsWith(".mdx")) {
|
|
||||||
missileArt += ".mdx";
|
|
||||||
}
|
|
||||||
final float facing = launchFacing;
|
final float facing = launchFacing;
|
||||||
final float sinFacing = (float) Math.sin(facing);
|
final float sinFacing = (float) Math.sin(facing);
|
||||||
final float cosFacing = (float) Math.cos(facing);
|
final float cosFacing = (float) Math.cos(facing);
|
||||||
@ -435,12 +432,7 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
.getProjectileLaunchX(typeId);
|
.getProjectileLaunchX(typeId);
|
||||||
final float projectileLaunchY = War3MapViewer.this.simulation.getUnitData()
|
final float projectileLaunchY = War3MapViewer.this.simulation.getUnitData()
|
||||||
.getProjectileLaunchY(typeId);
|
.getProjectileLaunchY(typeId);
|
||||||
if (missileArt.toLowerCase().endsWith(".mdl")) {
|
missileArt = mdx(missileArt);
|
||||||
missileArt = missileArt.substring(0, missileArt.length() - 4);
|
|
||||||
}
|
|
||||||
if (!missileArt.toLowerCase().endsWith(".mdx")) {
|
|
||||||
missileArt += ".mdx";
|
|
||||||
}
|
|
||||||
final float facing = (float) Math.toRadians(source.getFacing());
|
final float facing = (float) Math.toRadians(source.getFacing());
|
||||||
final float sinFacing = (float) Math.sin(facing);
|
final float sinFacing = (float) Math.sin(facing);
|
||||||
final float cosFacing = (float) Math.cos(facing);
|
final float cosFacing = (float) Math.cos(facing);
|
||||||
@ -507,9 +499,17 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
|
|
||||||
this.terrain.initShadows();
|
this.terrain.initShadows();
|
||||||
this.terrain.createWaves();
|
this.terrain.createWaves();
|
||||||
|
|
||||||
|
loadLightsAndShading(tileset);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadTerrainCliffsAndWater(final War3MapW3e w3e) {
|
private void loadLightsAndShading(final char tileset) {
|
||||||
|
// TODO this should be set by the war3map.j actually, not by the tileset, so the
|
||||||
|
// call to set day night models is just for testing to make the test look pretty
|
||||||
|
final Element defaultTerrainLights = this.worldEditData.get("TerrainLights");
|
||||||
|
final Element defaultUnitLights = this.worldEditData.get("UnitLights");
|
||||||
|
setDayNightModels(defaultTerrainLights.getField(Character.toString(tileset)),
|
||||||
|
defaultUnitLights.getField(Character.toString(tileset)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,6 +902,10 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
this.updateTime -= WarsmashConstants.SIMULATION_STEP_TIME;
|
this.updateTime -= WarsmashConstants.SIMULATION_STEP_TIME;
|
||||||
this.simulation.update();
|
this.simulation.update();
|
||||||
}
|
}
|
||||||
|
this.dncTerrain.setFrameByRatio(
|
||||||
|
this.simulation.getGameTimeOfDay() / this.simulation.getGameplayConstants().getGameDayHours());
|
||||||
|
this.dncUnit.setFrameByRatio(
|
||||||
|
this.simulation.getGameTimeOfDay() / this.simulation.getGameplayConstants().getGameDayHours());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1007,7 +1011,7 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
this.worldScene.camera.screenToWorldRay(ray, mousePosHeap);
|
this.worldScene.camera.screenToWorldRay(ray, mousePosHeap);
|
||||||
gdxRayHeap.set(ray[0], ray[1], ray[2], ray[3] - ray[0], ray[4] - ray[1], ray[5] - ray[2]);
|
gdxRayHeap.set(ray[0], ray[1], ray[2], ray[3] - ray[0], ray[4] - ray[1], ray[5] - ray[2]);
|
||||||
gdxRayHeap.direction.nor();// needed for libgdx
|
gdxRayHeap.direction.nor();// needed for libgdx
|
||||||
Terrain.intersectRayTriangles(gdxRayHeap, this.terrain.softwareGroundMesh.vertices,
|
RenderMathUtils.intersectRayTriangles(gdxRayHeap, this.terrain.softwareGroundMesh.vertices,
|
||||||
this.terrain.softwareGroundMesh.indices, 3, out);
|
this.terrain.softwareGroundMesh.indices, 3, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1144,6 +1148,7 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
|
|
||||||
private static final int MAXIMUM_ACCEPTED = 1 << 30;
|
private static final int MAXIMUM_ACCEPTED = 1 << 30;
|
||||||
private float selectionCircleScaleFactor;
|
private float selectionCircleScaleFactor;
|
||||||
|
private DataTable worldEditData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a power of two size for the given target capacity.
|
* Returns a power of two size for the given target capacity.
|
||||||
@ -1240,4 +1245,30 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
this.textureDotted = textureDotted;
|
this.textureDotted = textureDotted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDayNightModels(final String terrainDNCFile, final String unitDNCFile) {
|
||||||
|
final MdxModel terrainDNCModel = (MdxModel) load(mdx(terrainDNCFile), PathSolver.DEFAULT, null);
|
||||||
|
this.dncTerrain = (MdxComplexInstance) terrainDNCModel.addInstance();
|
||||||
|
this.dncTerrain.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
|
||||||
|
this.dncTerrain.setSequence(0);
|
||||||
|
final MdxModel unitDNCModel = (MdxModel) load(mdx(unitDNCFile), PathSolver.DEFAULT, null);
|
||||||
|
this.dncUnit = (MdxComplexInstance) unitDNCModel.addInstance();
|
||||||
|
this.dncUnit.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
|
||||||
|
this.dncUnit.setSequence(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String mdx(String mdxPath) {
|
||||||
|
if (mdxPath.toLowerCase().endsWith(".mdl")) {
|
||||||
|
mdxPath = mdxPath.substring(0, mdxPath.length() - 4);
|
||||||
|
}
|
||||||
|
if (!mdxPath.toLowerCase().endsWith(".mdx")) {
|
||||||
|
mdxPath += ".mdx";
|
||||||
|
}
|
||||||
|
return mdxPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SceneLightManager createLightManager() {
|
||||||
|
return new W3xSceneLightManager(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ import com.badlogic.gdx.math.Intersector;
|
|||||||
import com.badlogic.gdx.math.Matrix4;
|
import com.badlogic.gdx.math.Matrix4;
|
||||||
import com.badlogic.gdx.math.Rectangle;
|
import com.badlogic.gdx.math.Rectangle;
|
||||||
import com.badlogic.gdx.math.Vector3;
|
import com.badlogic.gdx.math.Vector3;
|
||||||
import com.badlogic.gdx.math.collision.Ray;
|
|
||||||
import com.etheller.warsmash.datasources.DataSource;
|
import com.etheller.warsmash.datasources.DataSource;
|
||||||
import com.etheller.warsmash.parsers.w3x.w3e.Corner;
|
import com.etheller.warsmash.parsers.w3x.w3e.Corner;
|
||||||
import com.etheller.warsmash.parsers.w3x.w3e.War3MapW3e;
|
import com.etheller.warsmash.parsers.w3x.w3e.War3MapW3e;
|
||||||
@ -34,7 +33,6 @@ import com.etheller.warsmash.parsers.w3x.w3i.War3MapW3i;
|
|||||||
import com.etheller.warsmash.parsers.w3x.wpm.War3MapWpm;
|
import com.etheller.warsmash.parsers.w3x.wpm.War3MapWpm;
|
||||||
import com.etheller.warsmash.units.DataTable;
|
import com.etheller.warsmash.units.DataTable;
|
||||||
import com.etheller.warsmash.units.Element;
|
import com.etheller.warsmash.units.Element;
|
||||||
import com.etheller.warsmash.units.StandardObjectData;
|
|
||||||
import com.etheller.warsmash.util.ImageUtils;
|
import com.etheller.warsmash.util.ImageUtils;
|
||||||
import com.etheller.warsmash.util.RenderMathUtils;
|
import com.etheller.warsmash.util.RenderMathUtils;
|
||||||
import com.etheller.warsmash.util.War3ID;
|
import com.etheller.warsmash.util.War3ID;
|
||||||
@ -127,7 +125,7 @@ public class Terrain {
|
|||||||
|
|
||||||
public Terrain(final War3MapW3e w3eFile, final War3MapWpm terrainPathing, final War3MapW3i w3iFile,
|
public Terrain(final War3MapW3e w3eFile, final War3MapWpm terrainPathing, final War3MapW3i w3iFile,
|
||||||
final WebGL webGL, final DataSource dataSource, final WorldEditStrings worldEditStrings,
|
final WebGL webGL, final DataSource dataSource, final WorldEditStrings worldEditStrings,
|
||||||
final War3MapViewer viewer) throws IOException {
|
final War3MapViewer viewer, final DataTable worldEditData) throws IOException {
|
||||||
this.webGL = webGL;
|
this.webGL = webGL;
|
||||||
this.viewer = viewer;
|
this.viewer = viewer;
|
||||||
this.camera = viewer.worldScene.camera;
|
this.camera = viewer.worldScene.camera;
|
||||||
@ -221,8 +219,6 @@ public class Terrain {
|
|||||||
this.groundTextureToId.put(groundTile.asStringValue(), this.groundTextures.size() - 1);
|
this.groundTextureToId.put(groundTile.asStringValue(), this.groundTextures.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
final StandardObjectData standardObjectData = new StandardObjectData(dataSource);
|
|
||||||
final DataTable worldEditData = standardObjectData.getWorldEditData();
|
|
||||||
final Element tilesets = worldEditData.get("TileSets");
|
final Element tilesets = worldEditData.get("TileSets");
|
||||||
|
|
||||||
this.blightTextureIndex = this.groundTextures.size();
|
this.blightTextureIndex = this.groundTextures.size();
|
||||||
@ -1179,67 +1175,10 @@ public class Terrain {
|
|||||||
// return out;
|
// return out;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
static Vector3 best = new Vector3();
|
|
||||||
static Vector3 tmp = new Vector3();
|
|
||||||
static Vector3 tmp1 = new Vector3();
|
|
||||||
static Vector3 tmp2 = new Vector3();
|
|
||||||
static Vector3 tmp3 = new Vector3();
|
|
||||||
private final WaveBuilder waveBuilder;
|
private final WaveBuilder waveBuilder;
|
||||||
public PathingGrid pathingGrid;
|
public PathingGrid pathingGrid;
|
||||||
private final Rectangle shaderMapBoundsRectangle;
|
private final Rectangle shaderMapBoundsRectangle;
|
||||||
|
|
||||||
/**
|
|
||||||
* Intersects the given ray with list of triangles. Returns the nearest
|
|
||||||
* intersection point in intersection
|
|
||||||
*
|
|
||||||
* @param ray The ray
|
|
||||||
* @param vertices the vertices
|
|
||||||
* @param indices the indices, each successive 3 shorts index the 3
|
|
||||||
* vertices of a triangle
|
|
||||||
* @param vertexSize the size of a vertex in floats
|
|
||||||
* @param intersection The nearest intersection point (optional)
|
|
||||||
* @return Whether the ray and the triangles intersect.
|
|
||||||
*/
|
|
||||||
public static boolean intersectRayTriangles(final Ray ray, final float[] vertices, final int[] indices,
|
|
||||||
final int vertexSize, final Vector3 intersection) {
|
|
||||||
float min_dist = Float.MAX_VALUE;
|
|
||||||
boolean hit = false;
|
|
||||||
|
|
||||||
if ((indices.length % 3) != 0) {
|
|
||||||
throw new RuntimeException("triangle list size is not a multiple of 3");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < indices.length; i += 3) {
|
|
||||||
final int i1 = indices[i] * vertexSize;
|
|
||||||
final int i2 = indices[i + 1] * vertexSize;
|
|
||||||
final int i3 = indices[i + 2] * vertexSize;
|
|
||||||
|
|
||||||
final boolean result = Intersector.intersectRayTriangle(ray,
|
|
||||||
tmp1.set(vertices[i1], vertices[i1 + 1], vertices[i1 + 2]),
|
|
||||||
tmp2.set(vertices[i2], vertices[i2 + 1], vertices[i2 + 2]),
|
|
||||||
tmp3.set(vertices[i3], vertices[i3 + 1], vertices[i3 + 2]), tmp);
|
|
||||||
|
|
||||||
if (result == true) {
|
|
||||||
final float dist = ray.origin.dst2(tmp);
|
|
||||||
if (dist < min_dist) {
|
|
||||||
min_dist = dist;
|
|
||||||
best.set(tmp);
|
|
||||||
hit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hit == false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (intersection != null) {
|
|
||||||
intersection.set(best);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class UnloadedTexture {
|
private static final class UnloadedTexture {
|
||||||
private final int width;
|
private final int width;
|
||||||
private final int height;
|
private final int height;
|
||||||
|
@ -19,6 +19,10 @@ public class CGameplayConstants {
|
|||||||
private final float boneDecayTime;
|
private final float boneDecayTime;
|
||||||
private final float bulletDeathTime;
|
private final float bulletDeathTime;
|
||||||
private final float closeEnoughRange;
|
private final float closeEnoughRange;
|
||||||
|
private final float dawnTimeGameHours;
|
||||||
|
private final float duskTimeGameHours;
|
||||||
|
private final float gameDayHours;
|
||||||
|
private final float gameDayLength;
|
||||||
|
|
||||||
public CGameplayConstants(final DataTable parsedDataTable) {
|
public CGameplayConstants(final DataTable parsedDataTable) {
|
||||||
final Element miscData = parsedDataTable.get("Misc");
|
final Element miscData = parsedDataTable.get("Misc");
|
||||||
@ -30,6 +34,11 @@ public class CGameplayConstants {
|
|||||||
this.bulletDeathTime = miscData.getFieldFloatValue("BulletDeathTime");
|
this.bulletDeathTime = miscData.getFieldFloatValue("BulletDeathTime");
|
||||||
this.closeEnoughRange = miscData.getFieldFloatValue("CloseEnoughRange");
|
this.closeEnoughRange = miscData.getFieldFloatValue("CloseEnoughRange");
|
||||||
|
|
||||||
|
this.dawnTimeGameHours = miscData.getFieldFloatValue("Dawn");
|
||||||
|
this.duskTimeGameHours = miscData.getFieldFloatValue("Dusk");
|
||||||
|
this.gameDayHours = miscData.getFieldFloatValue("DayHours");
|
||||||
|
this.gameDayLength = miscData.getFieldFloatValue("DayLength");
|
||||||
|
|
||||||
final CDefenseType[] defenseTypeOrder = { CDefenseType.SMALL, CDefenseType.MEDIUM, CDefenseType.LARGE,
|
final CDefenseType[] defenseTypeOrder = { CDefenseType.SMALL, CDefenseType.MEDIUM, CDefenseType.LARGE,
|
||||||
CDefenseType.FORT, CDefenseType.NORMAL, CDefenseType.HERO, CDefenseType.DIVINE, CDefenseType.NONE, };
|
CDefenseType.FORT, CDefenseType.NORMAL, CDefenseType.HERO, CDefenseType.DIVINE, CDefenseType.NONE, };
|
||||||
this.damageBonusTable = new float[CAttackType.values().length][defenseTypeOrder.length];
|
this.damageBonusTable = new float[CAttackType.values().length][defenseTypeOrder.length];
|
||||||
@ -80,4 +89,20 @@ public class CGameplayConstants {
|
|||||||
public float getCloseEnoughRange() {
|
public float getCloseEnoughRange() {
|
||||||
return this.closeEnoughRange;
|
return this.closeEnoughRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getGameDayHours() {
|
||||||
|
return this.gameDayHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getGameDayLength() {
|
||||||
|
return this.gameDayLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getDawnTimeGameHours() {
|
||||||
|
return this.dawnTimeGameHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getDuskTimeGameHours() {
|
||||||
|
return this.duskTimeGameHours;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ public class CSimulation {
|
|||||||
private final CPathfindingProcessor pathfindingProcessor;
|
private final CPathfindingProcessor pathfindingProcessor;
|
||||||
private final CGameplayConstants gameplayConstants;
|
private final CGameplayConstants gameplayConstants;
|
||||||
private final Random seededRandom;
|
private final Random seededRandom;
|
||||||
|
private float currentGameDayTimeElapsed;
|
||||||
|
|
||||||
public CSimulation(final DataTable miscData, final MutableObjectData parsedUnitData,
|
public CSimulation(final DataTable miscData, final MutableObjectData parsedUnitData,
|
||||||
final MutableObjectData parsedAbilityData, final SimulationRenderController simulationRenderController,
|
final MutableObjectData parsedAbilityData, final SimulationRenderController simulationRenderController,
|
||||||
@ -145,6 +146,13 @@ public class CSimulation {
|
|||||||
this.projectiles.addAll(this.newProjectiles);
|
this.projectiles.addAll(this.newProjectiles);
|
||||||
this.newProjectiles.clear();
|
this.newProjectiles.clear();
|
||||||
this.gameTurnTick++;
|
this.gameTurnTick++;
|
||||||
|
this.currentGameDayTimeElapsed = (this.currentGameDayTimeElapsed + WarsmashConstants.SIMULATION_STEP_TIME)
|
||||||
|
% this.gameplayConstants.getGameDayLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getGameTimeOfDay() {
|
||||||
|
return (this.currentGameDayTimeElapsed / this.gameplayConstants.getGameDayLength())
|
||||||
|
* this.gameplayConstants.getGameDayHours();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getGameTurnTick() {
|
public int getGameTurnTick() {
|
||||||
|
@ -132,6 +132,26 @@ public class CUnitData {
|
|||||||
final int speed = unitType.getFieldAsInteger(MOVEMENT_SPEED_BASE, 0);
|
final int speed = unitType.getFieldAsInteger(MOVEMENT_SPEED_BASE, 0);
|
||||||
final int defense = unitType.getFieldAsInteger(DEFENSE, 0);
|
final int defense = unitType.getFieldAsInteger(DEFENSE, 0);
|
||||||
|
|
||||||
|
final CUnitType unitTypeInstance = getUnitTypeInstance(typeId, buildingPathingPixelMap, unitType);
|
||||||
|
|
||||||
|
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
|
||||||
|
speed, defense, unitTypeInstance);
|
||||||
|
if (speed > 0) {
|
||||||
|
unit.add(simulation, CAbilityMove.INSTANCE);
|
||||||
|
unit.add(simulation, CAbilityPatrol.INSTANCE);
|
||||||
|
unit.add(simulation, CAbilityHoldPosition.INSTANCE);
|
||||||
|
unit.add(simulation, CAbilityStop.INSTANCE);
|
||||||
|
}
|
||||||
|
final int dmgDice1 = unitType.getFieldAsInteger(ATTACK1_DMG_DICE, 0);
|
||||||
|
final int dmgDice2 = unitType.getFieldAsInteger(ATTACK2_DMG_DICE, 0);
|
||||||
|
if ((dmgDice1 != 0) || (dmgDice2 != 0)) {
|
||||||
|
unit.add(simulation, CAbilityAttack.INSTANCE);
|
||||||
|
}
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage buildingPathingPixelMap,
|
||||||
|
final MutableGameObject unitType) {
|
||||||
CUnitType unitTypeInstance = this.unitIdToUnitType.get(typeId);
|
CUnitType unitTypeInstance = this.unitIdToUnitType.get(typeId);
|
||||||
if (unitTypeInstance == null) {
|
if (unitTypeInstance == null) {
|
||||||
final float moveHeight = unitType.getFieldAsFloat(MOVE_HEIGHT, 0);
|
final float moveHeight = unitType.getFieldAsFloat(MOVE_HEIGHT, 0);
|
||||||
@ -252,21 +272,7 @@ public class CUnitData {
|
|||||||
targetedAs);
|
targetedAs);
|
||||||
this.unitIdToUnitType.put(typeId, unitTypeInstance);
|
this.unitIdToUnitType.put(typeId, unitTypeInstance);
|
||||||
}
|
}
|
||||||
|
return unitTypeInstance;
|
||||||
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
|
|
||||||
speed, defense, unitTypeInstance);
|
|
||||||
if (speed > 0) {
|
|
||||||
unit.add(simulation, CAbilityMove.INSTANCE);
|
|
||||||
unit.add(simulation, CAbilityPatrol.INSTANCE);
|
|
||||||
unit.add(simulation, CAbilityHoldPosition.INSTANCE);
|
|
||||||
unit.add(simulation, CAbilityStop.INSTANCE);
|
|
||||||
}
|
|
||||||
final int dmgDice1 = unitType.getFieldAsInteger(ATTACK1_DMG_DICE, 0);
|
|
||||||
final int dmgDice2 = unitType.getFieldAsInteger(ATTACK2_DMG_DICE, 0);
|
|
||||||
if ((dmgDice1 != 0) || (dmgDice2 != 0)) {
|
|
||||||
unit.add(simulation, CAbilityAttack.INSTANCE);
|
|
||||||
}
|
|
||||||
return unit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CUnitAttack createAttack(final float animationBackswingPoint, final float animationDamagePoint,
|
private CUnitAttack createAttack(final float animationBackswingPoint, final float animationDamagePoint,
|
||||||
|
@ -18,6 +18,7 @@ import com.etheller.warsmash.parsers.fdf.GameUI;
|
|||||||
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
|
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
|
||||||
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
|
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
|
||||||
import com.etheller.warsmash.parsers.fdf.frames.SetPoint;
|
import com.etheller.warsmash.parsers.fdf.frames.SetPoint;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame;
|
||||||
import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
|
import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
|
||||||
import com.etheller.warsmash.parsers.fdf.frames.TextureFrame;
|
import com.etheller.warsmash.parsers.fdf.frames.TextureFrame;
|
||||||
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
|
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
|
||||||
@ -55,7 +56,7 @@ public class MeleeUI implements CUnitStateListener {
|
|||||||
private StringFrame resourceBarLumberText;
|
private StringFrame resourceBarLumberText;
|
||||||
private StringFrame resourceBarSupplyText;
|
private StringFrame resourceBarSupplyText;
|
||||||
private StringFrame resourceBarUpkeepText;
|
private StringFrame resourceBarUpkeepText;
|
||||||
private UIFrame timeIndicator;
|
private SpriteFrame timeIndicator;
|
||||||
private UIFrame unitPortrait;
|
private UIFrame unitPortrait;
|
||||||
private StringFrame unitLifeText;
|
private StringFrame unitLifeText;
|
||||||
private StringFrame unitManaText;
|
private StringFrame unitManaText;
|
||||||
@ -107,7 +108,7 @@ public class MeleeUI implements CUnitStateListener {
|
|||||||
// =================================
|
// =================================
|
||||||
// Load skins and templates
|
// Load skins and templates
|
||||||
// =================================
|
// =================================
|
||||||
this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, 3), this.uiViewport,
|
this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, 0), this.uiViewport,
|
||||||
this.fontGenerator, this.uiScene, this.war3MapViewer);
|
this.fontGenerator, this.uiScene, this.war3MapViewer);
|
||||||
try {
|
try {
|
||||||
this.rootFrame.loadTOCFile("UI\\FrameDef\\FrameDef.toc");
|
this.rootFrame.loadTOCFile("UI\\FrameDef\\FrameDef.toc");
|
||||||
@ -148,7 +149,9 @@ public class MeleeUI implements CUnitStateListener {
|
|||||||
this.resourceBarUpkeepText.setColor(Color.RED);
|
this.resourceBarUpkeepText.setColor(Color.RED);
|
||||||
|
|
||||||
// Create the Time Indicator (clock)
|
// Create the Time Indicator (clock)
|
||||||
this.timeIndicator = this.rootFrame.createFrame("TimeOfDayIndicator", this.rootFrame, 0, 0);
|
this.timeIndicator = (SpriteFrame) this.rootFrame.createFrame("TimeOfDayIndicator", this.rootFrame, 0, 0);
|
||||||
|
this.timeIndicator.setSequence(0); // play the stand
|
||||||
|
this.timeIndicator.setAnimationSpeed(0.0f); // do not advance automatically
|
||||||
|
|
||||||
// Create the unit portrait stuff
|
// Create the unit portrait stuff
|
||||||
this.portrait = new Portrait(this.war3MapViewer);
|
this.portrait = new Portrait(this.war3MapViewer);
|
||||||
@ -221,6 +224,9 @@ public class MeleeUI implements CUnitStateListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.timeIndicator.setFrameByRatio(this.war3MapViewer.simulation.getGameTimeOfDay()
|
||||||
|
/ this.war3MapViewer.simulation.getGameplayConstants().getGameDayHours());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void portraitTalk() {
|
public void portraitTalk() {
|
||||||
@ -229,12 +235,12 @@ public class MeleeUI implements CUnitStateListener {
|
|||||||
|
|
||||||
private static final class Portrait {
|
private static final class Portrait {
|
||||||
private MdxComplexInstance modelInstance;
|
private MdxComplexInstance modelInstance;
|
||||||
private final WarsmashGdxMapGame.CameraManager portraitCameraManager;
|
private final WarsmashGdxMapGame.PortraitCameraManager portraitCameraManager;
|
||||||
private final Scene portraitScene;
|
private final Scene portraitScene;
|
||||||
|
|
||||||
public Portrait(final War3MapViewer war3MapViewer) {
|
public Portrait(final War3MapViewer war3MapViewer) {
|
||||||
this.portraitScene = war3MapViewer.addSimpleScene();
|
this.portraitScene = war3MapViewer.addSimpleScene();
|
||||||
this.portraitCameraManager = new WarsmashGdxMapGame.CameraManager();
|
this.portraitCameraManager = new WarsmashGdxMapGame.PortraitCameraManager();
|
||||||
this.portraitCameraManager.setupCamera(this.portraitScene);
|
this.portraitCameraManager.setupCamera(this.portraitScene);
|
||||||
this.portraitScene.camera.viewport(new Rectangle(100, 0, 6400, 48));
|
this.portraitScene.camera.viewport(new Rectangle(100, 0, 6400, 48));
|
||||||
}
|
}
|
||||||
@ -303,6 +309,11 @@ public class MeleeUI implements CUnitStateListener {
|
|||||||
this.simpleNameValue.setText(unit.getSimulationUnit().getUnitType().getName());
|
this.simpleNameValue.setText(unit.getSimulationUnit().getUnitType().getName());
|
||||||
String classText = null;
|
String classText = null;
|
||||||
for (final CUnitClassification classification : unit.getSimulationUnit().getClassifications()) {
|
for (final CUnitClassification classification : unit.getSimulationUnit().getClassifications()) {
|
||||||
|
if ((classification == CUnitClassification.MECHANICAL)
|
||||||
|
&& unit.getSimulationUnit().getUnitType().isBuilding()) {
|
||||||
|
// buildings dont display MECHANICAL
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (classification.getDisplayName() != null) {
|
if (classification.getDisplayName() != null) {
|
||||||
classText = classification.getDisplayName();
|
classText = classification.getDisplayName();
|
||||||
}
|
}
|
||||||
@ -325,7 +336,11 @@ public class MeleeUI implements CUnitStateListener {
|
|||||||
}
|
}
|
||||||
this.simpleBuildingActionLabel.setText("");
|
this.simpleBuildingActionLabel.setText("");
|
||||||
|
|
||||||
if (unit.getSimulationUnit().getUnitType().getAttacks().size() > 0) {
|
final boolean anyAttacks = unit.getSimulationUnit().getUnitType().getAttacks().size() > 0;
|
||||||
|
final UIFrame localArmorIcon;
|
||||||
|
final TextureFrame localArmorIconBackdrop;
|
||||||
|
final StringFrame localArmorInfoPanelIconValue;
|
||||||
|
if (anyAttacks) {
|
||||||
final CUnitAttack attackOne = unit.getSimulationUnit().getUnitType().getAttacks().get(0);
|
final CUnitAttack attackOne = unit.getSimulationUnit().getUnitType().getAttacks().get(0);
|
||||||
this.attack1Icon.setVisible(attackOne.isShowUI());
|
this.attack1Icon.setVisible(attackOne.isShowUI());
|
||||||
this.attack1IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackOne.getAttackType()));
|
this.attack1IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackOne.getAttackType()));
|
||||||
@ -339,21 +354,29 @@ public class MeleeUI implements CUnitStateListener {
|
|||||||
else {
|
else {
|
||||||
this.attack2Icon.setVisible(false);
|
this.attack2Icon.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localArmorIcon = this.armorIcon;
|
||||||
|
localArmorIconBackdrop = this.armorIconBackdrop;
|
||||||
|
localArmorInfoPanelIconValue = this.armorInfoPanelIconValue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.attack1Icon.setVisible(false);
|
this.armorIcon.setVisible(false);
|
||||||
this.attack2Icon.setVisible(false);
|
this.attack2Icon.setVisible(false);
|
||||||
|
|
||||||
|
localArmorIcon = this.attack1Icon;
|
||||||
|
localArmorIconBackdrop = this.attack1IconBackdrop;
|
||||||
|
localArmorInfoPanelIconValue = this.attack1InfoPanelIconValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.armorIcon.setVisible(true);
|
localArmorIcon.setVisible(true);
|
||||||
final Texture defenseTexture = this.defenseBackdrops
|
final Texture defenseTexture = this.defenseBackdrops
|
||||||
.getTexture(unit.getSimulationUnit().getUnitType().getDefenseType());
|
.getTexture(unit.getSimulationUnit().getUnitType().getDefenseType());
|
||||||
if (defenseTexture == null) {
|
if (defenseTexture == null) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
unit.getSimulationUnit().getUnitType().getDefenseType() + " can't find texture!");
|
unit.getSimulationUnit().getUnitType().getDefenseType() + " can't find texture!");
|
||||||
}
|
}
|
||||||
this.armorIconBackdrop.setTexture(defenseTexture);
|
localArmorIconBackdrop.setTexture(defenseTexture);
|
||||||
this.armorInfoPanelIconValue.setText(Integer.toString(unit.getSimulationUnit().getDefense()));
|
localArmorInfoPanelIconValue.setText(Integer.toString(unit.getSimulationUnit().getDefense()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user