Invulnerable ability, first draft of multi select, colored selection circles

This commit is contained in:
Retera 2021-06-06 01:29:05 -04:00
parent 46ac4ade21
commit 24590f7783
40 changed files with 1472 additions and 686 deletions

View File

@ -53,7 +53,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.ui.MeleeUI;
public class WarsmashGdxMapScreen implements InputProcessor, Screen { public class WarsmashGdxMapScreen implements InputProcessor, Screen {
public static final boolean ENABLE_AUDIO = true; public static final boolean ENABLE_AUDIO = true;
private static final boolean ENABLE_MUSIC = true; private static final boolean ENABLE_MUSIC = false;
private final War3MapViewer viewer; private final War3MapViewer viewer;
private final Rectangle tempRect = new Rectangle(); private final Rectangle tempRect = new Rectangle();

View File

@ -221,7 +221,7 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
} }
} }
public boolean hasSkinField(String file) { public boolean hasSkinField(final String file) {
return (file != null) && this.skin.hasField(file); return (file != null) && this.skin.hasField(file);
} }
@ -329,7 +329,7 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
|| ((parentDefinitionIfAvailable != null) || ((parentDefinitionIfAvailable != null)
&& parentDefinitionIfAvailable.has("DecorateFileNames")); && parentDefinitionIfAvailable.has("DecorateFileNames"));
final SimpleStatusBarFrame simpleStatusBarFrame = new SimpleStatusBarFrame(frameDefinition.getName(), final SimpleStatusBarFrame simpleStatusBarFrame = new SimpleStatusBarFrame(frameDefinition.getName(),
parent, decorateFileNames); parent, decorateFileNames, false, 0.0f);
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) { for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
simpleStatusBarFrame.add(inflate(childDefinition, simpleStatusBarFrame, frameDefinition, simpleStatusBarFrame.add(inflate(childDefinition, simpleStatusBarFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"))); inDecorateFileNames || childDefinition.has("DecorateFileNames")));

View File

@ -7,19 +7,28 @@ public class SimpleStatusBarFrame extends AbstractUIFrame {
private final boolean decorateFileNames; private final boolean decorateFileNames;
private final TextureFrame barFrame; private final TextureFrame barFrame;
private final TextureFrame borderFrame; private final TextureFrame borderFrame;
private final float barInset;
public SimpleStatusBarFrame(final String name, final UIFrame parent, final boolean decorateFileNames) { public SimpleStatusBarFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
final boolean borderBelow, final float barInset) {
super(name, parent); super(name, parent);
this.decorateFileNames = decorateFileNames; this.decorateFileNames = decorateFileNames;
this.barInset = barInset;
this.barFrame = new TextureFrame(name + "Bar", this, decorateFileNames, new Vector4Definition(0, 1, 0, 1)); this.barFrame = new TextureFrame(name + "Bar", this, decorateFileNames, new Vector4Definition(0, 1, 0, 1));
this.borderFrame = new TextureFrame(name + "Border", this, decorateFileNames, this.borderFrame = new TextureFrame(name + "Border", this, decorateFileNames,
new Vector4Definition(0, 1, 0, 1)); new Vector4Definition(0, 1, 0, 1));
this.borderFrame.setSetAllPoints(true); this.borderFrame.setSetAllPoints(true);
this.barFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this, FramePoint.TOPLEFT, 0, 0)); this.barFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this, FramePoint.TOPLEFT, barInset, -barInset));
this.barFrame.addSetPoint(new SetPoint(FramePoint.BOTTOMLEFT, this, FramePoint.BOTTOMLEFT, 0, 0)); this.barFrame.addSetPoint(new SetPoint(FramePoint.BOTTOMLEFT, this, FramePoint.BOTTOMLEFT, barInset, barInset));
this.barFrame.setSetAllPoints(true); this.barFrame.setSetAllPoints(true, barInset);
add(this.barFrame); if (borderBelow) {
add(this.borderFrame); add(this.borderFrame);
add(this.barFrame);
}
else {
add(this.barFrame);
add(this.borderFrame);
}
} }
public boolean isDecorateFileNames() { public boolean isDecorateFileNames() {
@ -28,7 +37,7 @@ public class SimpleStatusBarFrame extends AbstractUIFrame {
public void setValue(final float value) { public void setValue(final float value) {
this.barFrame.setTexCoord(0, value, 0, 1); this.barFrame.setTexCoord(0, value, 0, 1);
this.barFrame.setWidth(this.renderBounds.width * value); this.barFrame.setWidth(((this.renderBounds.width - (this.barInset * 2)) * value));
} }
public TextureFrame getBarFrame() { public TextureFrame getBarFrame() {

View File

@ -46,6 +46,17 @@ public class TextureFrame extends AbstractRenderableFrame {
this.color = color; this.color = color;
} }
public void setColor(final float r, final float g, final float b, final float a) {
if (this.color == null) {
this.color = new Color();
}
this.color.r = r;
this.color.g = g;
this.color.b = b;
this.color.a = a;
}
public void setTexture(String file, final GameUI gameUI) { public void setTexture(String file, final GameUI gameUI) {
if (this.decorateFileNames) { if (this.decorateFileNames) {
file = gameUI.trySkinField(file); file = gameUI.trySkinField(file);

View File

@ -9,7 +9,6 @@ public class WarsmashConstants {
public static int GAME_VERSION = 1; public static int GAME_VERSION = 1;
public static final int REPLACEABLE_TEXTURE_LIMIT = 64; public static final int REPLACEABLE_TEXTURE_LIMIT = 64;
public static final float SIMULATION_STEP_TIME = 1 / 20f; public static final float SIMULATION_STEP_TIME = 1 / 20f;
public static final float PLAYER_UNIT_MOUSE_HIGHLIGHT_UPDATE_STEP_TIME = 1 / 20f;
public static final int PORT_NUMBER = 6115; public static final int PORT_NUMBER = 6115;
public static final float BUILDING_CONSTRUCT_START_LIFE = 0.1f; public static final float BUILDING_CONSTRUCT_START_LIFE = 0.1f;
public static final int BUILD_QUEUE_SIZE = 7; public static final int BUILD_QUEUE_SIZE = 7;

View File

@ -1,5 +1,8 @@
package com.etheller.warsmash.viewer5; package com.etheller.warsmash.viewer5;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler.ShaderEnvironmentType;
public class Shaders { public class Shaders {
public static final String boneTexture = ""// public static final String boneTexture = ""//
+ " uniform sampler2D u_boneMap;\r\n" + // + " uniform sampler2D u_boneMap;\r\n" + //
@ -58,6 +61,7 @@ public class Shaders {
public static String lightSystem(final String normalName, final String positionName, final String lightTexture, public static String lightSystem(final String normalName, final String positionName, final String lightTexture,
final String lightTextureHeight, final String lightCount, final boolean terrain) { final String lightTextureHeight, final String lightCount, final boolean terrain) {
new RuntimeException("lightSystem").printStackTrace();
return " vec3 lightFactor = vec3(0.0,0.0,0.0);\r\n" + // return " vec3 lightFactor = vec3(0.0,0.0,0.0);\r\n" + //
" for(float lightIndex = 0.5; lightIndex < " + lightCount + "; lightIndex += 1.0) {\r\n" + // " for(float lightIndex = 0.5; lightIndex < " + lightCount + "; lightIndex += 1.0) {\r\n" + //
" float rowPos = (lightIndex) / " + lightTextureHeight + ";\r\n" + // " float rowPos = (lightIndex) / " + lightTextureHeight + ";\r\n" + //
@ -103,13 +107,14 @@ public class Shaders {
" lightFactor += lightFactorContribution + (lightAmbColor.a/(pow(dist, 2.0))) * lightAmbColor.rgb;\r\n" " lightFactor += lightFactorContribution + (lightAmbColor.a/(pow(dist, 2.0))) * lightAmbColor.rgb;\r\n"
+ // + //
" }\r\n" + // " }\r\n" + //
" }\r\n";// + // " }\r\n" + //
(MdxHandler.CURRENT_SHADER_TYPE == ShaderEnvironmentType.MENU
// " vec4 sRGB = vec4(lightFactor, 1.0);" + // ? " vec4 sRGB = vec4(lightFactor, 1.0);" + //
// " bvec4 cutoff = lessThan(sRGB, vec4(0.04045));" + // " bvec4 cutoff = lessThan(sRGB, vec4(0.04045));" + //
// " vec4 higher = pow((sRGB + vec4(0.055))/vec4(1.055), vec4(2.4));" + // " vec4 higher = pow((sRGB + vec4(0.055))/vec4(1.055), vec4(2.4));" + //
// " vec4 lower = sRGB/vec4(12.92);" + // " vec4 lower = sRGB/vec4(12.92);" + //
// "" + // "" + //
// " lightFactor = (higher * (vec4(1.0) - vec4(cutoff)) + lower * vec4(cutoff)).xyz;"; " lightFactor = (higher * (vec4(1.0) - vec4(cutoff)) + lower * vec4(cutoff)).xyz;"
: "");
} }
} }

View File

@ -41,18 +41,18 @@ public class BatchGroup extends GenericGroup {
if (isExtended) { if (isExtended) {
if (DynamicShadowManager.IS_SHADOW_MAPPING) { if (DynamicShadowManager.IS_SHADOW_MAPPING) {
shader = MdxHandler.Shaders.extendedShadowMap; shader = handler.shaders.extendedShadowMap;
} }
else { else {
shader = MdxHandler.Shaders.extended; shader = handler.shaders.extended;
} }
} }
else { else {
if (DynamicShadowManager.IS_SHADOW_MAPPING) { if (DynamicShadowManager.IS_SHADOW_MAPPING) {
shader = MdxHandler.Shaders.complexShadowMap; shader = handler.shaders.complexShadowMap;
} }
else { else {
shader = MdxHandler.Shaders.complex; shader = handler.shaders.complex;
} }
} }

View File

@ -87,7 +87,10 @@ public class CollisionShape extends GenericObject {
public boolean checkIntersect(final Ray ray, final MdxNode mdxNode, final Vector3 intersection) { public boolean checkIntersect(final Ray ray, final MdxNode mdxNode, final Vector3 intersection) {
intersectHeap.set(this.center); intersectHeap.set(this.center);
intersectHeap.prj(mdxNode.worldMatrix); intersectHeap.prj(mdxNode.worldMatrix);
return Intersector.intersectRaySphere(ray, intersectHeap, this.radius, intersection); if (Intersector.intersectRaySphere(ray, intersectHeap, this.radius, intersection)) {
return true;
}
return false;
} }
} }
@ -120,6 +123,10 @@ public class CollisionShape extends GenericObject {
intersectHeap2.prj(intersectMatrixHeap); intersectHeap2.prj(intersectMatrixHeap);
intersectHeap2.sub(intersectHeap); intersectHeap2.sub(intersectHeap);
intersectRayHeap.set(intersectHeap, intersectHeap2); intersectRayHeap.set(intersectHeap, intersectHeap2);
return bounds.intersectRay(intersectRayHeap, intersection); if (bounds.intersectRay(intersectRayHeap, intersection)) {
intersection.prj(worldMatrix);
return true;
}
return false;
} }
} }

View File

@ -29,7 +29,7 @@ public class EmitterGroup extends GenericGroup {
final ModelViewer viewer = model.viewer; final ModelViewer viewer = model.viewer;
final GL20 gl = viewer.gl; final GL20 gl = viewer.gl;
final ANGLEInstancedArrays instancedArrays = viewer.webGL.instancedArrays; final ANGLEInstancedArrays instancedArrays = viewer.webGL.instancedArrays;
final ShaderProgram shader = MdxHandler.Shaders.particles; final ShaderProgram shader = ((MdxModel) model).handler.shaders.particles;
gl.glDepthMask(false); gl.glDepthMask(false);
gl.glEnable(GL20.GL_BLEND); gl.glEnable(GL20.GL_BLEND);

View File

@ -15,7 +15,9 @@ import com.etheller.warsmash.viewer5.Texture;
import com.etheller.warsmash.viewer5.TextureMapper; import com.etheller.warsmash.viewer5.TextureMapper;
import com.etheller.warsmash.viewer5.gl.ANGLEInstancedArrays; import com.etheller.warsmash.viewer5.gl.ANGLEInstancedArrays;
import com.etheller.warsmash.viewer5.gl.ClientBuffer; import com.etheller.warsmash.viewer5.gl.ClientBuffer;
import com.etheller.warsmash.viewer5.gl.DataTexture;
import com.etheller.warsmash.viewer5.handlers.EmitterObject; import com.etheller.warsmash.viewer5.handlers.EmitterObject;
import com.etheller.warsmash.viewer5.handlers.w3x.W3xSceneLightManager;
//The total storage that emitted objects can use. //The total storage that emitted objects can use.
//This is enough to support all of the MDX geometry emitters. //This is enough to support all of the MDX geometry emitters.
@ -191,6 +193,15 @@ public class GeometryEmitterFuncs {
shader.setUniformf("u_columns", emitterObject.columns); shader.setUniformf("u_columns", emitterObject.columns);
shader.setUniformf("u_rows", emitterObject.rows); shader.setUniformf("u_rows", emitterObject.rows);
shader.setUniformf("u_teamColored", emitterObject.teamColored); shader.setUniformf("u_teamColored", emitterObject.teamColored);
shader.setUniformi("u_unshaded", emitterObject.emitterUsesMdlOrUnshaded != 0 ? 1 : 0);
final W3xSceneLightManager lightManager = (W3xSceneLightManager) scene.getLightManager();
final DataTexture unitLightsTexture = lightManager.getUnitLightsTexture();
unitLightsTexture.bind(14);
shader.setUniformi("u_lightTexture", 14);
shader.setUniformf("u_lightCount", lightManager.getUnitLightCount());
shader.setUniformf("u_lightTextureHeight", unitLightsTexture.getHeight());
shader.setUniform3fv("u_intervals[0]", intervals[0], 0, 3); shader.setUniform3fv("u_intervals[0]", intervals[0], 0, 3);
shader.setUniform3fv("u_intervals[1]", intervals[1], 0, 3); shader.setUniform3fv("u_intervals[1]", intervals[1], 0, 3);
@ -210,9 +221,7 @@ public class GeometryEmitterFuncs {
shader.setUniform3fv("u_vertices[3]", asFloatArray(vectors[3]), 0, 3); shader.setUniform3fv("u_vertices[3]", asFloatArray(vectors[3]), 0, 3);
} }
if (emitterObject.tail) { shader.setUniform3fv("u_cameraZ", asFloatArray(camera.billboardedVectors[6]), 0, 3);
shader.setUniform3fv("u_cameraZ", asFloatArray(camera.billboardedVectors[6]), 0, 3);
}
} }
public static void bindRibbonEmitterBuffer(final RibbonEmitter emitter, final ClientBuffer buffer) { public static void bindRibbonEmitterBuffer(final RibbonEmitter emitter, final ClientBuffer buffer) {

View File

@ -36,6 +36,7 @@ public class MdxComplexInstance extends ModelInstance {
private static final float[] colorHeap = new float[3]; private static final float[] colorHeap = new float[3];
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];
private static final Vector3 intersectionHeap = new Vector3();
public List<LightInstance> lights = new ArrayList<>(); public List<LightInstance> lights = new ArrayList<>();
public List<AttachmentInstance> attachments = new ArrayList<>(); public List<AttachmentInstance> attachments = new ArrayList<>();
@ -778,13 +779,18 @@ public class MdxComplexInstance extends ModelInstance {
public boolean intersectRayWithCollisionSimple(final Ray ray, final Vector3 intersection) { public boolean intersectRayWithCollisionSimple(final Ray ray, final Vector3 intersection) {
final MdxModel mdxModel = (MdxModel) this.model; final MdxModel mdxModel = (MdxModel) this.model;
final List<CollisionShape> collisionShapes = mdxModel.collisionShapes; final List<CollisionShape> collisionShapes = mdxModel.collisionShapes;
boolean intersected = false;
ray.getEndPoint(intersection, 99999);
for (final CollisionShape collisionShape : collisionShapes) { 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, intersectionHeap)) {
return true; if (intersectionHeap.dst2(ray.origin) < intersection.dst2(ray.origin)) {
intersection.set(intersectionHeap);
}
intersected = true;
} }
} }
return intersectRayBounds(ray, intersection); return intersected || intersectRayBounds(ray, intersection);
} }
/** /**
@ -796,19 +802,24 @@ public class MdxComplexInstance extends ModelInstance {
*/ */
public boolean intersectRayWithMeshSlow(final Ray ray, final Vector3 intersection) { public boolean intersectRayWithMeshSlow(final Ray ray, final Vector3 intersection) {
final MdxModel mdxModel = (MdxModel) this.model; final MdxModel mdxModel = (MdxModel) this.model;
boolean intersected = false;
ray.getEndPoint(intersection, 99999);
for (final Geoset geoset : mdxModel.geosets) { for (final Geoset geoset : mdxModel.geosets) {
if (!geoset.unselectable) { if (!geoset.unselectable) {
geoset.getAlpha(alphaHeap, this.sequence, this.frame, this.counter); geoset.getAlpha(alphaHeap, this.sequence, this.frame, this.counter);
if (alphaHeap[0] > 0) { if (alphaHeap[0] > 0) {
final MdlxGeoset mdlxGeoset = geoset.mdlxGeoset; final MdlxGeoset mdlxGeoset = geoset.mdlxGeoset;
if (CollisionShape.intersectRayTriangles(ray, this, mdlxGeoset.getVertices(), mdlxGeoset.getFaces(), if (CollisionShape.intersectRayTriangles(ray, this, mdlxGeoset.getVertices(), mdlxGeoset.getFaces(),
3, intersection)) { 3, intersectionHeap)) {
return true; if (intersectionHeap.dst2(ray.origin) < intersection.dst2(ray.origin)) {
intersection.set(intersectionHeap);
}
intersected = true;
} }
} }
} }
} }
return false; return intersected;
} }
/** /**

View File

@ -12,6 +12,14 @@ import com.etheller.warsmash.viewer5.handlers.blp.DdsHandler;
import com.etheller.warsmash.viewer5.handlers.tga.TgaHandler; import com.etheller.warsmash.viewer5.handlers.tga.TgaHandler;
public class MdxHandler extends ModelHandler { public class MdxHandler extends ModelHandler {
public final Shaders shaders = new Shaders();
public static enum ShaderEnvironmentType {
MENU,
GAME
};
public static ShaderEnvironmentType CURRENT_SHADER_TYPE;
public MdxHandler() { public MdxHandler() {
this.extensions = new ArrayList<>(); this.extensions = new ArrayList<>();
@ -26,14 +34,14 @@ public class MdxHandler extends ModelHandler {
viewer.addHandler(new DdsHandler()); viewer.addHandler(new DdsHandler());
viewer.addHandler(new TgaHandler()); viewer.addHandler(new TgaHandler());
Shaders.complex = viewer.webGL.createShaderProgram(MdxShaders.vsComplex, MdxShaders.fsComplex); this.shaders.complex = viewer.webGL.createShaderProgram(MdxShaders.vsComplex(), MdxShaders.fsComplex);
Shaders.extended = viewer.webGL.createShaderProgram("#define EXTENDED_BONES\r\n" + MdxShaders.vsComplex, this.shaders.extended = viewer.webGL.createShaderProgram("#define EXTENDED_BONES\r\n" + MdxShaders.vsComplex(),
MdxShaders.fsComplex); MdxShaders.fsComplex);
Shaders.complexShadowMap = viewer.webGL.createShaderProgram(MdxShaders.vsComplex, this.shaders.complexShadowMap = viewer.webGL.createShaderProgram(MdxShaders.vsComplex(),
MdxShaders.fsComplexShadowMap); MdxShaders.fsComplexShadowMap);
Shaders.extendedShadowMap = viewer.webGL.createShaderProgram( this.shaders.extendedShadowMap = viewer.webGL.createShaderProgram(
"#define EXTENDED_BONES\r\n" + MdxShaders.vsComplex, MdxShaders.fsComplexShadowMap); "#define EXTENDED_BONES\r\n" + MdxShaders.vsComplex(), MdxShaders.fsComplexShadowMap);
Shaders.particles = viewer.webGL.createShaderProgram(MdxShaders.vsParticles, MdxShaders.fsParticles); this.shaders.particles = viewer.webGL.createShaderProgram(MdxShaders.vsParticles(), MdxShaders.fsParticles);
// Shaders.simple = viewer.webGL.createShaderProgram(MdxShaders.vsSimple, // Shaders.simple = viewer.webGL.createShaderProgram(MdxShaders.vsSimple,
// MdxShaders.fsSimple); // MdxShaders.fsSimple);
// Shaders.hd = viewer.webGL.createShaderProgram(MdxShaders.vsHd, MdxShaders.fsHd); // Shaders.hd = viewer.webGL.createShaderProgram(MdxShaders.vsHd, MdxShaders.fsHd);
@ -41,7 +49,8 @@ public class MdxHandler extends ModelHandler {
// If a shader failed to compile, don't allow the handler to be registered, and // If a shader failed to compile, don't allow the handler to be registered, and
// send an error instead. // send an error instead.
return Shaders.complex.isCompiled() && Shaders.extended.isCompiled() && Shaders.particles.isCompiled() return this.shaders.complex.isCompiled() && this.shaders.extended.isCompiled()
&& this.shaders.particles.isCompiled()
/* && Shaders.simple.isCompiled() && Shaders.hd.isCompiled() */; /* && Shaders.simple.isCompiled() && Shaders.hd.isCompiled() */;
} }
@ -56,12 +65,12 @@ public class MdxHandler extends ModelHandler {
} }
public static ShaderProgram complex; public ShaderProgram complex;
public static ShaderProgram complexShadowMap; public ShaderProgram complexShadowMap;
public static ShaderProgram extended; public ShaderProgram extended;
public static ShaderProgram extendedShadowMap; public ShaderProgram extendedShadowMap;
public static ShaderProgram simple; public ShaderProgram simple;
public static ShaderProgram particles; public ShaderProgram particles;
public static ShaderProgram hd; public ShaderProgram hd;
} }
} }

View File

@ -73,7 +73,7 @@ public class MdxRenderBatch extends RenderBatch {
final GL20 gl = viewer.gl; final GL20 gl = viewer.gl;
final WebGL webGL = viewer.webGL; final WebGL webGL = viewer.webGL;
final ANGLEInstancedArrays instancedArrays = webGL.instancedArrays; final ANGLEInstancedArrays instancedArrays = webGL.instancedArrays;
final ShaderProgram shader = MdxHandler.Shaders.simple; final ShaderProgram shader = model.handler.shaders.simple;
final int m0 = shader.getAttributeLocation("a_m0"); final int m0 = shader.getAttributeLocation("a_m0");
final int m1 = shader.getAttributeLocation("a_m1"); final int m1 = shader.getAttributeLocation("a_m1");
final int m2 = shader.getAttributeLocation("a_m2"); final int m2 = shader.getAttributeLocation("a_m2");

View File

@ -83,81 +83,84 @@ public class MdxShaders {
" gl_FragColor = color;\r\n" + // " gl_FragColor = color;\r\n" + //
" }\r\n"; " }\r\n";
public static final String vsComplex = "\r\n" + // public static final String vsComplex() {
"\r\n" + // return "\r\n" + //
" uniform mat4 u_mvp;\r\n" + // "\r\n" + //
" uniform vec4 u_vertexColor;\r\n" + // " uniform mat4 u_mvp;\r\n" + //
" uniform vec4 u_geosetColor;\r\n" + // " uniform vec4 u_vertexColor;\r\n" + //
" uniform float u_layerAlpha;\r\n" + // " uniform vec4 u_geosetColor;\r\n" + //
" uniform vec2 u_uvTrans;\r\n" + // " uniform float u_layerAlpha;\r\n" + //
" uniform vec2 u_uvRot;\r\n" + // " uniform vec2 u_uvTrans;\r\n" + //
" uniform float u_uvScale;\r\n" + // " uniform vec2 u_uvRot;\r\n" + //
" uniform bool u_hasBones;\r\n" + // " uniform float u_uvScale;\r\n" + //
" uniform bool u_unshaded;\r\n" + // " uniform bool u_hasBones;\r\n" + //
" attribute vec3 a_position;\r\n" + // " uniform bool u_unshaded;\r\n" + //
" attribute vec3 a_normal;\r\n" + // " attribute vec3 a_position;\r\n" + //
" attribute vec2 a_uv;\r\n" + // " attribute vec3 a_normal;\r\n" + //
" attribute vec4 a_bones;\r\n" + // " attribute vec2 a_uv;\r\n" + //
" #ifdef EXTENDED_BONES\r\n" + // " attribute vec4 a_bones;\r\n" + //
" attribute vec4 a_extendedBones;\r\n" + // " #ifdef EXTENDED_BONES\r\n" + //
" #endif\r\n" + // " attribute vec4 a_extendedBones;\r\n" + //
" attribute float a_boneNumber;\r\n" + // " #endif\r\n" + //
" varying vec2 v_uv;\r\n" + // " attribute float a_boneNumber;\r\n" + //
" varying vec4 v_color;\r\n" + // " varying vec2 v_uv;\r\n" + //
" varying vec4 v_uvTransRot;\r\n" + // " varying vec4 v_color;\r\n" + //
" varying float v_uvScale;\r\n" + // " varying vec4 v_uvTransRot;\r\n" + //
" uniform sampler2D u_lightTexture;\r\n" + // " varying float v_uvScale;\r\n" + //
" uniform float u_lightCount;\r\n" + // " uniform sampler2D u_lightTexture;\r\n" + //
" uniform float u_lightTextureHeight;\r\n" + // " uniform float u_lightCount;\r\n" + //
Shaders.boneTexture + "\r\n" + // " uniform float u_lightTextureHeight;\r\n" + //
" void transform(inout vec3 position, inout vec3 normal) {\r\n" + // Shaders.boneTexture + "\r\n" + //
" // For the broken models out there, since the game supports this.\r\n" + // " void transform(inout vec3 position, inout vec3 normal) {\r\n" + //
" if (a_boneNumber > 0.0) {\r\n" + // " // For the broken models out there, since the game supports this.\r\n" + //
" vec4 position4 = vec4(position, 1.0);\r\n" + // " if (a_boneNumber > 0.0) {\r\n" + //
" vec4 normal4 = vec4(normal, 0.0);\r\n" + // " vec4 position4 = vec4(position, 1.0);\r\n" + //
" mat4 bone;\r\n" + // " vec4 normal4 = vec4(normal, 0.0);\r\n" + //
" vec4 p = vec4(0.0,0.0,0.0,0.0);\r\n" + // " mat4 bone;\r\n" + //
" vec4 n = vec4(0.0,0.0,0.0,0.0);\r\n" + // " vec4 p = vec4(0.0,0.0,0.0,0.0);\r\n" + //
" for (int i = 0; i < 4; i++) {\r\n" + // " vec4 n = vec4(0.0,0.0,0.0,0.0);\r\n" + //
" if (a_bones[i] > 0.0) {\r\n" + // " for (int i = 0; i < 4; i++) {\r\n" + //
" bone = fetchMatrix(a_bones[i] - 1.0, 0.0);\r\n" + // " if (a_bones[i] > 0.0) {\r\n" + //
" p += bone * position4;\r\n" + // " bone = fetchMatrix(a_bones[i] - 1.0, 0.0);\r\n" + //
" n += bone * normal4;\r\n" + // " p += bone * position4;\r\n" + //
" }\r\n" + // " n += bone * normal4;\r\n" + //
" }\r\n" + // " }\r\n" + //
" #ifdef EXTENDED_BONES\r\n" + // " }\r\n" + //
" for (int i = 0; i < 4; i++) {\r\n" + // " #ifdef EXTENDED_BONES\r\n" + //
" if (a_extendedBones[i] > 0.0) {\r\n" + // " for (int i = 0; i < 4; i++) {\r\n" + //
" bone = fetchMatrix(a_extendedBones[i] - 1.0, 0.0);\r\n" + // " if (a_extendedBones[i] > 0.0) {\r\n" + //
" p += bone * position4;\r\n" + // " bone = fetchMatrix(a_extendedBones[i] - 1.0, 0.0);\r\n" + //
" n += bone * normal4;\r\n" + // " p += bone * position4;\r\n" + //
" }\r\n" + // " n += bone * normal4;\r\n" + //
" }\r\n" + // " }\r\n" + //
" #endif\r\n" + // " }\r\n" + //
" position = p.xyz / a_boneNumber;\r\n" + // " #endif\r\n" + //
" normal = normalize(n.xyz);\r\n" + // " position = p.xyz / a_boneNumber;\r\n" + //
" } else {\r\n" + // " normal = normalize(n.xyz);\r\n" + //
" position.x += 100.0;\r\n" + // " } else {\r\n" + //
" }\r\n" + // " position.x += 100.0;\r\n" + //
"\r\n" + // " }\r\n" + //
" }\r\n" + // "\r\n" + //
" void main() {\r\n" + // " }\r\n" + //
" vec3 position = a_position;\r\n" + // " void main() {\r\n" + //
" vec3 normal = a_normal;\r\n" + // " vec3 position = a_position;\r\n" + //
" if (u_hasBones) {\r\n" + // " vec3 normal = a_normal;\r\n" + //
" transform(position, normal);\r\n" + // " if (u_hasBones) {\r\n" + //
" }\r\n" + // " transform(position, normal);\r\n" + //
" v_uv = a_uv;\r\n" + // " }\r\n" + //
" v_color = u_vertexColor * u_geosetColor.bgra * vec4(1.0, 1.0, 1.0, u_layerAlpha);\r\n" + // " v_uv = a_uv;\r\n" + //
" v_uvTransRot = vec4(u_uvTrans, u_uvRot);\r\n" + // " v_color = u_vertexColor * u_geosetColor.bgra * vec4(1.0, 1.0, 1.0, u_layerAlpha);\r\n" + //
" v_uvScale = u_uvScale;\r\n" + // " v_uvTransRot = vec4(u_uvTrans, u_uvRot);\r\n" + //
" gl_Position = u_mvp * vec4(position, 1.0);\r\n" + // " v_uvScale = u_uvScale;\r\n" + //
" if(!u_unshaded) {\r\n" + // " gl_Position = u_mvp * vec4(position, 1.0);\r\n" + //
Shaders.lightSystem("normal", "position", "u_lightTexture", "u_lightTextureHeight", "u_lightCount", false) " if(!u_unshaded) {\r\n" + //
+ "\r\n" + // Shaders.lightSystem("normal", "position", "u_lightTexture", "u_lightTextureHeight", "u_lightCount",
" v_color.xyz *= clamp(lightFactor, 0.0, 1.0);\r\n" + // false)
" }\r\n" + // + "\r\n" + //
" }"; " v_color.xyz *= clamp(lightFactor, 0.0, 1.0);\r\n" + //
" }\r\n" + //
" }";
}
public static final String fsComplex = Shaders.quatTransform + "\r\n\r\n" + // public static final String fsComplex = Shaders.quatTransform + "\r\n\r\n" + //
" uniform sampler2D u_texture;\r\n" + // " uniform sampler2D u_texture;\r\n" + //
@ -219,239 +222,256 @@ public class MdxShaders {
" gl_FragColor = vec4(0.0, 0, 0, 1.0);//gl_FragCoord.z;\r\n" + // " gl_FragColor = vec4(0.0, 0, 0, 1.0);//gl_FragCoord.z;\r\n" + //
" }"; " }";
public static final String vsParticles = "\r\n" + // public static final String vsParticles() {
" #define EMITTER_PARTICLE2 0.0\r\n" + // return "\r\n" + //
" #define EMITTER_RIBBON 1.0\r\n" + // " #define EMITTER_PARTICLE2 0.0\r\n" + //
" #define EMITTER_SPLAT 2.0\r\n" + // " #define EMITTER_RIBBON 1.0\r\n" + //
" #define EMITTER_UBERSPLAT 3.0\r\n" + // " #define EMITTER_SPLAT 2.0\r\n" + //
" #define HEAD 0.0\r\n" + // " #define EMITTER_UBERSPLAT 3.0\r\n" + //
" uniform mat4 u_mvp;\r\n" + // " #define HEAD 0.0\r\n" + //
" uniform mediump float u_emitter;\r\n" + // " uniform mat4 u_mvp;\r\n" + //
" // Shared\r\n" + // " uniform mediump float u_emitter;\r\n" + //
" uniform vec4 u_colors[3];\r\n" + // " // Shared\r\n" + //
" uniform vec3 u_vertices[4];\r\n" + // " uniform vec4 u_colors[3];\r\n" + //
" uniform vec3 u_intervals[4];\r\n" + // " uniform vec3 u_vertices[4];\r\n" + //
" uniform float u_lifeSpan;\r\n" + // " uniform vec3 u_intervals[4];\r\n" + //
" uniform float u_columns;\r\n" + // " uniform float u_lifeSpan;\r\n" + //
" uniform float u_rows;\r\n" + // " uniform float u_columns;\r\n" + //
" // Particle2\r\n" + // " uniform float u_rows;\r\n" + //
" uniform vec3 u_scaling;\r\n" + // " // Particle2\r\n" + //
" uniform vec3 u_cameraZ;\r\n" + // " uniform vec3 u_scaling;\r\n" + //
" uniform float u_timeMiddle;\r\n" + // " uniform vec3 u_cameraZ;\r\n" + //
" uniform bool u_teamColored;\r\n" + // " uniform float u_timeMiddle;\r\n" + //
" // Splat and Uber.\r\n" + // " uniform bool u_teamColored;\r\n" + //
" uniform vec3 u_intervalTimes;\r\n" + // " uniform bool u_unshaded;\r\n" + //
" // Vertices\r\n" + // " uniform sampler2D u_lightTexture;\r\n" + //
" attribute float a_position;\r\n" + // " uniform float u_lightCount;\r\n" + //
" // Instances\r\n" + // " uniform float u_lightTextureHeight;\r\n" + //
" attribute vec3 a_p0;\r\n" + // " // Splat and Uber.\r\n" + //
" attribute vec3 a_p1;\r\n" + // " uniform vec3 u_intervalTimes;\r\n" + //
" attribute vec3 a_p2;\r\n" + // " // Vertices\r\n" + //
" attribute vec3 a_p3;\r\n" + // " attribute float a_position;\r\n" + //
" attribute float a_health;\r\n" + // " // Instances\r\n" + //
" attribute vec4 a_color;\r\n" + // " attribute vec3 a_p0;\r\n" + //
" attribute float a_tail;\r\n" + // " attribute vec3 a_p1;\r\n" + //
" attribute vec3 a_leftRightTop;\r\n" + // " attribute vec3 a_p2;\r\n" + //
" varying vec2 v_texcoord;\r\n" + // " attribute vec3 a_p3;\r\n" + //
" varying vec4 v_color;\r\n" + // " attribute float a_health;\r\n" + //
" float getCell(vec3 interval, float factor) {\r\n" + // " attribute vec4 a_color;\r\n" + //
" float start = interval[0];\r\n" + // " attribute float a_tail;\r\n" + //
" float end = interval[1];\r\n" + // " attribute vec3 a_leftRightTop;\r\n" + //
" float repeat = interval[2];\r\n" + // " varying vec2 v_texcoord;\r\n" + //
" float spriteCount = end - start;\r\n" + // " varying vec4 v_color;\r\n" + //
" if (spriteCount > 0.0) {\r\n" + // " float getCell(vec3 interval, float factor) {\r\n" + //
" // Repeating speeds up the sprite animation, which makes it effectively run N times in its interval.\r\n" " float start = interval[0];\r\n" + //
+ // " float end = interval[1];\r\n" + //
" // E.g. if repeat is 4, the sprite animation will be seen 4 times, and thus also run 4 times as fast.\r\n" " float repeat = interval[2];\r\n" + //
+ // " float spriteCount = end - start;\r\n" + //
" // The sprite index is limited to the number of actual sprites.\r\n" + // " if (spriteCount > 0.0) {\r\n" + //
" return min(start + mod(floor(spriteCount * repeat * factor), spriteCount), u_columns * u_rows - 1.0);\r\n" " // Repeating speeds up the sprite animation, which makes it effectively run N times in its interval.\r\n"
+ // + //
" }\r\n" + // " // E.g. if repeat is 4, the sprite animation will be seen 4 times, and thus also run 4 times as fast.\r\n"
" return 0.0;\r\n" + // + //
" }\r\n" + // " // The sprite index is limited to the number of actual sprites.\r\n" + //
" void particle2() {\r\n" + // " return min(start + mod(floor(spriteCount * repeat * factor), spriteCount), u_columns * u_rows - 1.0);\r\n"
" float factor = (u_lifeSpan - a_health) / u_lifeSpan;\r\n" + // + //
" int index = 0;\r\n" + // " }\r\n" + //
" if (factor < u_timeMiddle) {\r\n" + // " return 0.0;\r\n" + //
" factor = factor / u_timeMiddle;\r\n" + // " }\r\n" + //
" index = 0;\r\n" + // " void particle2() {\r\n" + //
" } else {\r\n" + // " float factor = (u_lifeSpan - a_health) / u_lifeSpan;\r\n" + //
" factor = (factor - u_timeMiddle) / (1.0 - u_timeMiddle);\r\n" + // " int index = 0;\r\n" + //
" index = 1;\r\n" + // " if (factor < u_timeMiddle) {\r\n" + //
" }\r\n" + // " factor = factor / u_timeMiddle;\r\n" + //
" factor = min(factor, 1.0);\r\n" + // " index = 0;\r\n" + //
" float scale = mix(u_scaling[index], u_scaling[index + 1], factor);\r\n" + // " } else {\r\n" + //
" vec4 color = mix(u_colors[index], u_colors[index + 1], factor);\r\n" + // " factor = (factor - u_timeMiddle) / (1.0 - u_timeMiddle);\r\n" + //
" float cell = 0.0;\r\n" + // " index = 1;\r\n" + //
" if (u_teamColored) {\r\n" + // " }\r\n" + //
" cell = a_leftRightTop[0];\r\n" + // " factor = min(factor, 1.0);\r\n" + //
" } else {\r\n" + // " float scale = mix(u_scaling[index], u_scaling[index + 1], factor);\r\n" + //
" vec3 interval;\r\n" + // " vec4 color = mix(u_colors[index], u_colors[index + 1], factor);\r\n" + //
" if (a_tail == HEAD) {\r\n" + // " float cell = 0.0;\r\n" + //
" interval = u_intervals[index];\r\n" + // " if (u_teamColored) {\r\n" + //
" } else {\r\n" + // " cell = a_leftRightTop[0];\r\n" + //
" interval = u_intervals[index + 2];\r\n" + // " } else {\r\n" + //
" }\r\n" + // " vec3 interval;\r\n" + //
" cell = getCell(interval, factor);\r\n" + // " if (a_tail == HEAD) {\r\n" + //
" }\r\n" + // " interval = u_intervals[index];\r\n" + //
" float left = floor(mod(cell, u_columns));\r\n" + // " } else {\r\n" + //
" float top = floor(cell / u_columns);\r\n" + // " interval = u_intervals[index + 2];\r\n" + //
" float right = left + 1.0;\r\n" + // " }\r\n" + //
" float bottom = top + 1.0;\r\n" + // " cell = getCell(interval, factor);\r\n" + //
" left /= u_columns;\r\n" + // " }\r\n" + //
" right /= u_columns;\r\n" + // " float left = floor(mod(cell, u_columns));\r\n" + //
" top /= u_rows;\r\n" + // " float top = floor(cell / u_columns);\r\n" + //
" bottom /= u_rows;\r\n" + // " float right = left + 1.0;\r\n" + //
" if (a_position == 0.0) {\r\n" + // " float bottom = top + 1.0;\r\n" + //
" v_texcoord = vec2(right, top);\r\n" + // " left /= u_columns;\r\n" + //
" } else if (a_position == 1.0) {\r\n" + // " right /= u_columns;\r\n" + //
" v_texcoord = vec2(left, top);\r\n" + // " top /= u_rows;\r\n" + //
" } else if (a_position == 2.0) {\r\n" + // " bottom /= u_rows;\r\n" + //
" v_texcoord = vec2(left, bottom);\r\n" + // " if (a_position == 0.0) {\r\n" + //
" } else if (a_position == 3.0) {\r\n" + // " v_texcoord = vec2(right, top);\r\n" + //
" v_texcoord = vec2(right, bottom);\r\n" + // " } else if (a_position == 1.0) {\r\n" + //
" }\r\n" + // " v_texcoord = vec2(left, top);\r\n" + //
" v_color = color;\r\n" + // " } else if (a_position == 2.0) {\r\n" + //
" \r\n" + // " v_texcoord = vec2(left, bottom);\r\n" + //
" if (a_tail == HEAD) {\r\n" + // " } else if (a_position == 3.0) {\r\n" + //
" vec3 vertices[4];\r\n" + // " v_texcoord = vec2(right, bottom);\r\n" + //
" if(a_p1[0] != 0.0 || a_p1[1] != 0.0) {\r\n" + // " }\r\n" + //
" vec3 vx;\r\n" + // " v_color = color;\r\n" + //
" vx[0] = a_p1[0];\r\n" + // " \r\n" + //
" vx[1] = a_p1[1];\r\n" + // " vec3 lightingNormal;\r\n" + //
" vx[2] = 0.0;\r\n" + // " vec3 position;\r\n" + //
" vx = normalize(vx);\r\n" + // " if (a_tail == HEAD) {\r\n" + //
" vec3 vy;\r\n" + // " vec3 vertices[4];\r\n" + //
" vy[0] = -vx[1];\r\n" + // " if(a_p1[0] != 0.0 || a_p1[1] != 0.0) {\r\n" + //
" vy[1] = vx[0];\r\n" + // " lightingNormal = vec3(0.0, 0.0, 1.0);\r\n" + //
" vy[2] = 0.0;\r\n" + // " vec3 vx;\r\n" + //
" vertices[2] = - vx - vy;\r\n" + // " vx[0] = a_p1[0];\r\n" + //
" vertices[1] = vx - vy;\r\n" + // " vx[1] = a_p1[1];\r\n" + //
" vertices[0] = -vertices[2];\r\n" + // " vx[2] = 0.0;\r\n" + //
" vertices[3] = -vertices[1];\r\n" + // " vx = normalize(vx);\r\n" + //
" } else {\r\n" + // " vec3 vy;\r\n" + //
" vertices[0] = u_vertices[0];\r\n" + // " vy[0] = -vx[1];\r\n" + //
" vertices[1] = u_vertices[1];\r\n" + // " vy[1] = vx[0];\r\n" + //
" vertices[2] = u_vertices[2];\r\n" + // " vy[2] = 0.0;\r\n" + //
" vertices[3] = u_vertices[3];\r\n" + // " vertices[2] = - vx - vy;\r\n" + //
" }\r\n" + // " vertices[1] = vx - vy;\r\n" + //
" gl_Position = u_mvp * vec4(a_p0 + (vertices[int(a_position)] * scale), 1.0);\r\n" + // " vertices[0] = -vertices[2];\r\n" + //
" } else {\r\n" + // " vertices[3] = -vertices[1];\r\n" + //
" // Get the normal to the tail in camera space.\r\n" + // " } else {\r\n" + //
" // This allows to build a 2D rectangle around the 3D tail.\r\n" + // " lightingNormal = normalize(u_cameraZ);\r\n" + //
" vec3 normal = cross(u_cameraZ, normalize(a_p1 - a_p0));\r\n" + // " vertices[0] = u_vertices[0];\r\n" + //
" vec3 boundary = normal * scale * a_p2[0];\r\n" + // " vertices[1] = u_vertices[1];\r\n" + //
" vec3 position;\r\n" + // " vertices[2] = u_vertices[2];\r\n" + //
" if (a_position == 0.0) {\r\n" + // " vertices[3] = u_vertices[3];\r\n" + //
" position = a_p0 - boundary;\r\n" + // " }\r\n" + //
" } else if (a_position == 1.0) {\r\n" + // " position = a_p0 + (vertices[int(a_position)] * scale);\r\n" + //
" position = a_p1 - boundary;\r\n" + // " gl_Position = u_mvp * vec4(position, 1.0);\r\n" + //
" } else if (a_position == 2.0) {\r\n" + // " } else {\r\n" + //
" position = a_p1 + boundary;\r\n" + // " // Get the normal to the tail in camera space.\r\n" + //
" } else if (a_position == 3.0) {\r\n" + // " // This allows to build a 2D rectangle around the 3D tail.\r\n" + //
" position = a_p0 + boundary;\r\n" + // " vec3 normal = cross(u_cameraZ, normalize(a_p1 - a_p0));\r\n" + //
" }\r\n" + // " vec3 boundary = normal * scale * a_p2[0];\r\n" + //
" gl_Position = u_mvp * vec4(position, 1.0);\r\n" + // " if (a_position == 0.0) {\r\n" + //
" }\r\n" + // " position = a_p0 - boundary;\r\n" + //
" }\r\n" + // " } else if (a_position == 1.0) {\r\n" + //
" void ribbon() {\r\n" + // " position = a_p1 - boundary;\r\n" + //
" vec3 position;\r\n" + // " } else if (a_position == 2.0) {\r\n" + //
" float left = a_leftRightTop[0] / 255.0;\r\n" + // " position = a_p1 + boundary;\r\n" + //
" float right = a_leftRightTop[1] / 255.0;\r\n" + // " } else if (a_position == 3.0) {\r\n" + //
" float top = a_leftRightTop[2] / 255.0;\r\n" + // " position = a_p0 + boundary;\r\n" + //
" float bottom = top + 1.0;\r\n" + // " }\r\n" + //
" if (a_position == 0.0) {\r\n" + // " gl_Position = u_mvp * vec4(position, 1.0);\r\n" + //
" v_texcoord = vec2(right, top);\r\n" + // " lightingNormal = normalize(u_cameraZ);\r\n" + //
" position = a_p0;\r\n" + // " }\r\n" + //
" } else if (a_position == 1.0) {\r\n" + // " if(!u_unshaded) {\r\n" + //
" v_texcoord = vec2(right, bottom);\r\n" + // Shaders.lightSystem("lightingNormal", "position", "u_lightTexture", "u_lightTextureHeight",
" position = a_p1;\r\n" + // "u_lightCount", false)
" } else if (a_position == 2.0) {\r\n" + // + "\r\n" + //
" v_texcoord = vec2(left, bottom);\r\n" + // " v_color.xyz *= clamp(lightFactor, 0.0, 1.0);\r\n" + //
" position = a_p2;\r\n" + // " }\r\n" + //
" } else if (a_position == 3.0) {\r\n" + // " }\r\n" + //
" v_texcoord = vec2(left, top);\r\n" + // " void ribbon() {\r\n" + //
" position = a_p3;\r\n" + // " vec3 position;\r\n" + //
" }\r\n" + // " float left = a_leftRightTop[0] / 255.0;\r\n" + //
" v_texcoord[0] /= u_columns;\r\n" + // " float right = a_leftRightTop[1] / 255.0;\r\n" + //
" v_texcoord[1] /= u_rows;\r\n" + // " float top = a_leftRightTop[2] / 255.0;\r\n" + //
" v_color = a_color;\r\n" + // " float bottom = top + 1.0;\r\n" + //
" gl_Position = u_mvp * vec4(position, 1.0);\r\n" + // " if (a_position == 0.0) {\r\n" + //
" }\r\n" + // " v_texcoord = vec2(right, top);\r\n" + //
" void splat() {\r\n" + // " position = a_p0;\r\n" + //
" float factor = u_lifeSpan - a_health;\r\n" + // " } else if (a_position == 1.0) {\r\n" + //
" int index;\r\n" + // " v_texcoord = vec2(right, bottom);\r\n" + //
" if (factor < u_intervalTimes[0]) {\r\n" + // " position = a_p1;\r\n" + //
" factor = factor / u_intervalTimes[0];\r\n" + // " } else if (a_position == 2.0) {\r\n" + //
" index = 0;\r\n" + // " v_texcoord = vec2(left, bottom);\r\n" + //
" } else {\r\n" + // " position = a_p2;\r\n" + //
" factor = (factor - u_intervalTimes[0]) / u_intervalTimes[1];\r\n" + // " } else if (a_position == 3.0) {\r\n" + //
" index = 1;\r\n" + // " v_texcoord = vec2(left, top);\r\n" + //
" }\r\n" + // " position = a_p3;\r\n" + //
" float cell = getCell(u_intervals[index], factor);\r\n" + // " }\r\n" + //
" float left = floor(mod(cell, u_columns));\r\n" + // " v_texcoord[0] /= u_columns;\r\n" + //
" float top = floor(cell / u_columns);\r\n" + // " v_texcoord[1] /= u_rows;\r\n" + //
" float right = left + 1.0;\r\n" + // " v_color = a_color;\r\n" + //
" float bottom = top + 1.0;\r\n" + // " gl_Position = u_mvp * vec4(position, 1.0);\r\n" + //
" vec3 position;\r\n" + // " }\r\n" + //
" if (a_position == 0.0) {\r\n" + // " void splat() {\r\n" + //
" v_texcoord = vec2(left, top);\r\n" + // " float factor = u_lifeSpan - a_health;\r\n" + //
" position = a_p0;\r\n" + // " int index;\r\n" + //
" } else if (a_position == 1.0) {\r\n" + // " if (factor < u_intervalTimes[0]) {\r\n" + //
" v_texcoord = vec2(left, bottom);\r\n" + // " factor = factor / u_intervalTimes[0];\r\n" + //
" position = a_p1;\r\n" + // " index = 0;\r\n" + //
" } else if (a_position == 2.0) {\r\n" + // " } else {\r\n" + //
" v_texcoord = vec2(right, bottom);\r\n" + // " factor = (factor - u_intervalTimes[0]) / u_intervalTimes[1];\r\n" + //
" position = a_p2;\r\n" + // " index = 1;\r\n" + //
" } else if (a_position == 3.0) {\r\n" + // " }\r\n" + //
" v_texcoord = vec2(right, top);\r\n" + // " float cell = getCell(u_intervals[index], factor);\r\n" + //
" position = a_p3;\r\n" + // " float left = floor(mod(cell, u_columns));\r\n" + //
" }\r\n" + // " float top = floor(cell / u_columns);\r\n" + //
" v_texcoord[0] /= u_columns;\r\n" + // " float right = left + 1.0;\r\n" + //
" v_texcoord[1] /= u_rows;\r\n" + // " float bottom = top + 1.0;\r\n" + //
" v_color = mix(u_colors[index], u_colors[index + 1], factor) / 255.0;\r\n" + // " vec3 position;\r\n" + //
" gl_Position = u_mvp * vec4(position, 1.0);\r\n" + // " if (a_position == 0.0) {\r\n" + //
" }\r\n" + // " v_texcoord = vec2(left, top);\r\n" + //
" void ubersplat() {\r\n" + // " position = a_p0;\r\n" + //
" float factor = u_lifeSpan - a_health;\r\n" + // " } else if (a_position == 1.0) {\r\n" + //
" vec4 color;\r\n" + // " v_texcoord = vec2(left, bottom);\r\n" + //
" if (factor < u_intervalTimes[0]) {\r\n" + // " position = a_p1;\r\n" + //
" color = mix(u_colors[0], u_colors[1], factor / u_intervalTimes[0]);\r\n" + // " } else if (a_position == 2.0) {\r\n" + //
" } else if (factor < u_intervalTimes[0] + u_intervalTimes[1]) {\r\n" + // " v_texcoord = vec2(right, bottom);\r\n" + //
" color = u_colors[1];\r\n" + // " position = a_p2;\r\n" + //
" } else {\r\n" + // " } else if (a_position == 3.0) {\r\n" + //
" color = mix(u_colors[1], u_colors[2], (factor - u_intervalTimes[0] - u_intervalTimes[1]) / u_intervalTimes[2]);\r\n" " v_texcoord = vec2(right, top);\r\n" + //
+ // " position = a_p3;\r\n" + //
" }\r\n" + // " }\r\n" + //
" vec3 position;\r\n" + // " v_texcoord[0] /= u_columns;\r\n" + //
" if (a_position == 0.0) {\r\n" + // " v_texcoord[1] /= u_rows;\r\n" + //
" v_texcoord = vec2(0.0, 0.0);\r\n" + // " v_color = mix(u_colors[index], u_colors[index + 1], factor) / 255.0;\r\n" + //
" position = a_p0;\r\n" + // " gl_Position = u_mvp * vec4(position, 1.0);\r\n" + //
" } else if (a_position == 1.0) {\r\n" + // " }\r\n" + //
" v_texcoord = vec2(0.0, 1.0);\r\n" + // " void ubersplat() {\r\n" + //
" position = a_p1;\r\n" + // " float factor = u_lifeSpan - a_health;\r\n" + //
" } else if (a_position == 2.0) {\r\n" + // " vec4 color;\r\n" + //
" v_texcoord = vec2(1.0, 1.0);\r\n" + // " if (factor < u_intervalTimes[0]) {\r\n" + //
" position = a_p2;\r\n" + // " color = mix(u_colors[0], u_colors[1], factor / u_intervalTimes[0]);\r\n" + //
" } else if (a_position == 3.0) {\r\n" + // " } else if (factor < u_intervalTimes[0] + u_intervalTimes[1]) {\r\n" + //
" v_texcoord = vec2(1.0, 0.0);\r\n" + // " color = u_colors[1];\r\n" + //
" position = a_p3;\r\n" + // " } else {\r\n" + //
" }\r\n" + // " color = mix(u_colors[1], u_colors[2], (factor - u_intervalTimes[0] - u_intervalTimes[1]) / u_intervalTimes[2]);\r\n"
" v_color = color / 255.0;\r\n" + // + //
" gl_Position = u_mvp * vec4(position, 1.0);\r\n" + // " }\r\n" + //
" }\r\n" + // " vec3 position;\r\n" + //
" void main() {\r\n" + // " if (a_position == 0.0) {\r\n" + //
" if (u_emitter == EMITTER_PARTICLE2) {\r\n" + // " v_texcoord = vec2(0.0, 0.0);\r\n" + //
" particle2();\r\n" + // " position = a_p0;\r\n" + //
" } else if (u_emitter == EMITTER_RIBBON) {\r\n" + // " } else if (a_position == 1.0) {\r\n" + //
" ribbon();\r\n" + // " v_texcoord = vec2(0.0, 1.0);\r\n" + //
" } else if (u_emitter == EMITTER_SPLAT) {\r\n" + // " position = a_p1;\r\n" + //
" splat();\r\n" + // " } else if (a_position == 2.0) {\r\n" + //
" } else if (u_emitter == EMITTER_UBERSPLAT) {\r\n" + // " v_texcoord = vec2(1.0, 1.0);\r\n" + //
" ubersplat();\r\n" + // " position = a_p2;\r\n" + //
" }\r\n" + // " } else if (a_position == 3.0) {\r\n" + //
" }"; " v_texcoord = vec2(1.0, 0.0);\r\n" + //
" position = a_p3;\r\n" + //
" }\r\n" + //
" v_color = color / 255.0;\r\n" + //
" gl_Position = u_mvp * vec4(position, 1.0);\r\n" + //
" }\r\n" + //
" void main() {\r\n" + //
" if (u_emitter == EMITTER_PARTICLE2) {\r\n" + //
" particle2();\r\n" + //
" } else if (u_emitter == EMITTER_RIBBON) {\r\n" + //
" ribbon();\r\n" + //
" } else if (u_emitter == EMITTER_SPLAT) {\r\n" + //
" splat();\r\n" + //
" } else if (u_emitter == EMITTER_UBERSPLAT) {\r\n" + //
" ubersplat();\r\n" + //
" }\r\n" + //
" }";
}
public static final String fsParticles = "\r\n" + // public static final String fsParticles = "\r\n" + //
" #define EMITTER_RIBBON 1.0\r\n" + // " #define EMITTER_RIBBON 1.0\r\n" + //

View File

@ -7,6 +7,7 @@ import com.etheller.warsmash.util.WorldEditStrings;
import com.etheller.warsmash.viewer5.CanvasProvider; import com.etheller.warsmash.viewer5.CanvasProvider;
import com.etheller.warsmash.viewer5.SceneLightManager; import com.etheller.warsmash.viewer5.SceneLightManager;
import com.etheller.warsmash.viewer5.handlers.AbstractMdxModelViewer; import com.etheller.warsmash.viewer5.handlers.AbstractMdxModelViewer;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler.ShaderEnvironmentType;
import com.etheller.warsmash.viewer5.handlers.w3x.W3xScenePortraitLightManager; import com.etheller.warsmash.viewer5.handlers.w3x.W3xScenePortraitLightManager;
public class MdxViewer extends AbstractMdxModelViewer { public class MdxViewer extends AbstractMdxModelViewer {
@ -16,6 +17,7 @@ public class MdxViewer extends AbstractMdxModelViewer {
public MdxViewer(final DataSource dataSource, final CanvasProvider canvas, final Vector3 defaultLighting) { public MdxViewer(final DataSource dataSource, final CanvasProvider canvas, final Vector3 defaultLighting) {
super(dataSource, canvas); super(dataSource, canvas);
MdxHandler.CURRENT_SHADER_TYPE = ShaderEnvironmentType.MENU;
this.defaultLighting = defaultLighting; this.defaultLighting = defaultLighting;
this.worldEditStrings = new WorldEditStrings(this.dataSource); this.worldEditStrings = new WorldEditStrings(this.dataSource);
} }

View File

@ -7,59 +7,65 @@ public class W3xShaders {
private UberSplat() { private UberSplat() {
} }
public static final String vert = "\r\n" + // public static final String vert() {
"\r\n" + // return "\r\n" + //
" uniform mat4 u_mvp;\r\n" + // "\r\n" + //
" uniform sampler2D u_heightMap;\r\n" + // " uniform mat4 u_mvp;\r\n" + //
" uniform vec2 u_pixel;\r\n" + // " uniform sampler2D u_heightMap;\r\n" + //
" uniform vec2 u_size;\r\n" + // " uniform vec2 u_pixel;\r\n" + //
" uniform vec2 u_shadowPixel;\r\n" + // " uniform vec2 u_size;\r\n" + //
" uniform vec2 u_centerOffset;\r\n" + // " uniform vec2 u_shadowPixel;\r\n" + //
" uniform sampler2D u_lightTexture;\r\n" + // " uniform vec2 u_centerOffset;\r\n" + //
" uniform float u_lightCount;\r\n" + // " uniform sampler2D u_lightTexture;\r\n" + //
" uniform float u_lightTextureHeight;\r\n" + // " uniform float u_lightCount;\r\n" + //
" attribute vec3 a_position;\r\n" + // " uniform float u_lightTextureHeight;\r\n" + //
" attribute vec2 a_uv;\r\n" + // " attribute vec3 a_position;\r\n" + //
" attribute float a_absoluteHeight;\r\n" + // " attribute vec2 a_uv;\r\n" + //
" varying vec2 v_uv;\r\n" + // " attribute float a_absoluteHeight;\r\n" + //
" varying vec2 v_suv;\r\n" + // " varying vec2 v_uv;\r\n" + //
" varying vec3 v_normal;\r\n" + // " varying vec2 v_suv;\r\n" + //
" varying float a_positionHeight;\r\n" + // " varying vec3 v_normal;\r\n" + //
" varying vec3 shadeColor;\r\n" + // " varying float a_positionHeight;\r\n" + //
" const float normalDist = 0.25;\r\n" + // " varying vec3 shadeColor;\r\n" + //
" void main() {\r\n" + // " const float normalDist = 0.25;\r\n" + //
" vec2 halfPixel = u_pixel * 0.5;\r\n" + // " void main() {\r\n" + //
" vec2 base = (a_position.xy - u_centerOffset) / 128.0;\r\n" + // " vec2 halfPixel = u_pixel * 0.5;\r\n" + //
" float height;\r\n" + // " vec2 base = (a_position.xy - u_centerOffset) / 128.0;\r\n" + //
" float hL;\r\n" + // " float height;\r\n" + //
" float hR;\r\n" + // " float hL;\r\n" + //
" float hD;\r\n" + // " float hR;\r\n" + //
" float hU;\r\n" + // " float hD;\r\n" + //
" if (a_absoluteHeight < -256.0) {\r\n" + // " float hU;\r\n" + //
" height = texture2D(u_heightMap, base * u_pixel + halfPixel).r * 128.0;\r\n" + // " if (a_absoluteHeight < -256.0) {\r\n" + //
" hL = texture2D(u_heightMap, vec2(base - vec2(normalDist, 0.0)) * u_pixel + halfPixel).r;\r\n" + // " height = texture2D(u_heightMap, base * u_pixel + halfPixel).r * 128.0;\r\n" + //
" hR = texture2D(u_heightMap, vec2(base + vec2(normalDist, 0.0)) * u_pixel + halfPixel).r;\r\n" + // " hL = texture2D(u_heightMap, vec2(base - vec2(normalDist, 0.0)) * u_pixel + halfPixel).r;\r\n"
" hD = texture2D(u_heightMap, vec2(base - vec2(0.0, normalDist)) * u_pixel + halfPixel).r;\r\n" + // + //
" hU = texture2D(u_heightMap, vec2(base + vec2(0.0, normalDist)) * u_pixel + halfPixel).r;\r\n" + // " hR = texture2D(u_heightMap, vec2(base + vec2(normalDist, 0.0)) * u_pixel + halfPixel).r;\r\n"
" } else {\r\n" + // + //
" height = a_absoluteHeight;\r\n" + // " hD = texture2D(u_heightMap, vec2(base - vec2(0.0, normalDist)) * u_pixel + halfPixel).r;\r\n"
" hL = a_absoluteHeight;\r\n" + // + //
" hR = a_absoluteHeight;\r\n" + // " hU = texture2D(u_heightMap, vec2(base + vec2(0.0, normalDist)) * u_pixel + halfPixel).r;\r\n"
" hD = a_absoluteHeight;\r\n" + // + //
" hU = a_absoluteHeight;\r\n" + // " } else {\r\n" + //
" }\r\n" + // " height = a_absoluteHeight;\r\n" + //
" v_normal = normalize(vec3(hL - hR, hD - hU, normalDist * 2.0));\r\n" + // " hL = a_absoluteHeight;\r\n" + //
" v_uv = a_uv;\r\n" + // " hR = a_absoluteHeight;\r\n" + //
" v_suv = base / u_size;\r\n" + // " hD = a_absoluteHeight;\r\n" + //
" vec3 myposition = vec3(a_position.xy, height + a_position.z);\r\n" + // " hU = a_absoluteHeight;\r\n" + //
" gl_Position = u_mvp * vec4(myposition.xyz, 1.0);\r\n" + // " }\r\n" + //
" a_positionHeight = a_position.z;\r\n" + // " v_normal = normalize(vec3(hL - hR, hD - hU, normalDist * 2.0));\r\n" + //
Shaders.lightSystem("v_normal", "myposition", "u_lightTexture", "u_lightTextureHeight", "u_lightCount", " v_uv = a_uv;\r\n" + //
true) " v_suv = base / u_size;\r\n" + //
+ "\r\n" + // " vec3 myposition = vec3(a_position.xy, height + a_position.z);\r\n" + //
" shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + // " gl_Position = u_mvp * vec4(myposition.xyz, 1.0);\r\n" + //
" }\r\n" + // " a_positionHeight = a_position.z;\r\n" + //
" "; Shaders.lightSystem("v_normal", "myposition", "u_lightTexture", "u_lightTextureHeight",
"u_lightCount", true)
+ "\r\n" + //
" shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + //
" }\r\n" + //
" ";
}
public static final String frag = "\r\n" + // public static final String frag = "\r\n" + //
" uniform sampler2D u_texture;\r\n" + // " uniform sampler2D u_texture;\r\n" + //

View File

@ -11,10 +11,12 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
@ -73,6 +75,7 @@ import com.etheller.warsmash.viewer5.handlers.AbstractMdxModelViewer;
import com.etheller.warsmash.viewer5.handlers.mdx.Attachment; import com.etheller.warsmash.viewer5.handlers.mdx.Attachment;
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.MdxHandler.ShaderEnvironmentType;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel; import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxNode; import com.etheller.warsmash.viewer5.handlers.mdx.MdxNode;
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode; import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
@ -188,6 +191,8 @@ public class War3MapViewer extends AbstractMdxModelViewer {
public List<SplatModel> selModels = new ArrayList<>(); public List<SplatModel> selModels = new ArrayList<>();
public List<RenderWidget> selected = new ArrayList<>(); public List<RenderWidget> selected = new ArrayList<>();
private final Set<String> mouseHighlightSplatModelKeys = new HashSet<>();
private final List<RenderWidget> mouseHighlightWidgets = new ArrayList<>();
private DataTable unitAckSoundsTable; private DataTable unitAckSoundsTable;
private DataTable unitCombatSoundsTable; private DataTable unitCombatSoundsTable;
public DataTable miscData; public DataTable miscData;
@ -234,6 +239,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
public War3MapViewer(final DataSource dataSource, final CanvasProvider canvas, final War3MapConfig mapConfig) { public War3MapViewer(final DataSource dataSource, final CanvasProvider canvas, final War3MapConfig mapConfig) {
super(dataSource, canvas); super(dataSource, canvas);
MdxHandler.CURRENT_SHADER_TYPE = ShaderEnvironmentType.GAME;
this.gameDataSource = dataSource; this.gameDataSource = dataSource;
final WebGL webGL = this.webGL; final WebGL webGL = this.webGL;
@ -369,6 +375,9 @@ public class War3MapViewer extends AbstractMdxModelViewer {
} }
this.selectionCircleScaleFactor = selectionCircleData.getFieldFloatValue("ScaleFactor"); this.selectionCircleScaleFactor = selectionCircleData.getFieldFloatValue("ScaleFactor");
this.imageWalkableZOffset = selectionCircleData.getFieldValue("ImageWalkableZOffset"); this.imageWalkableZOffset = selectionCircleData.getFieldValue("ImageWalkableZOffset");
this.selectionCircleColorFriend = parseColor(selectionCircleData, "ColorFriend");
this.selectionCircleColorNeutral = parseColor(selectionCircleData, "ColorNeutral");
this.selectionCircleColorEnemy = parseColor(selectionCircleData, "ColorEnemy");
this.uiSoundsTable = new DataTable(worldEditStrings); this.uiSoundsTable = new DataTable(worldEditStrings);
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("UI\\SoundInfo\\UISounds.slk")) { try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("UI\\SoundInfo\\UISounds.slk")) {
@ -379,6 +388,13 @@ public class War3MapViewer extends AbstractMdxModelViewer {
} }
} }
private Color parseColor(final Element selectionCircleData, final String field) {
return new Color(selectionCircleData.getFieldFloatValue(field, 1) / 255f,
selectionCircleData.getFieldFloatValue(field, 2) / 255f,
selectionCircleData.getFieldFloatValue(field, 3) / 255f,
selectionCircleData.getFieldFloatValue(field, 0) / 255f);
}
public GenericResource loadMapGeneric(final String path, final FetchDataTypeName dataType, public GenericResource loadMapGeneric(final String path, final FetchDataTypeName dataType,
final LoadGenericCallback callback) { final LoadGenericCallback callback) {
if (this.mapMpq == null) { if (this.mapMpq == null) {
@ -1583,22 +1599,22 @@ public class War3MapViewer extends AbstractMdxModelViewer {
locations.locations, this.terrain.centerOffset, locations.unitMapping, true, false, true); locations.locations, this.terrain.centerOffset, locations.unitMapping, true, false, true);
switch (allyKey) { switch (allyKey) {
case "e:": case "e:":
model.color[0] = 1; model.color[0] = this.selectionCircleColorEnemy.r;
model.color[1] = 0; model.color[1] = this.selectionCircleColorEnemy.g;
model.color[2] = 0; model.color[2] = this.selectionCircleColorEnemy.b;
model.color[3] = 1; model.color[3] = this.selectionCircleColorEnemy.a;
break; break;
case "f:": case "f:":
model.color[0] = 0; model.color[0] = this.selectionCircleColorFriend.r;
model.color[1] = 1; model.color[1] = this.selectionCircleColorFriend.g;
model.color[2] = 0; model.color[2] = this.selectionCircleColorFriend.b;
model.color[3] = 1; model.color[3] = this.selectionCircleColorFriend.a;
break; break;
default: default:
model.color[0] = 1; model.color[0] = this.selectionCircleColorNeutral.r;
model.color[1] = 1; model.color[1] = this.selectionCircleColorNeutral.g;
model.color[2] = 0; model.color[2] = this.selectionCircleColorNeutral.b;
model.color[3] = 1; model.color[3] = this.selectionCircleColorNeutral.a;
break; break;
} }
this.selModels.add(model); this.selModels.add(model);
@ -1606,6 +1622,113 @@ public class War3MapViewer extends AbstractMdxModelViewer {
} }
} }
public void clearUnitMouseOverHighlight(final RenderWidget unit) {
this.mouseHighlightWidgets.remove(unit);
unit.getSelectionPreviewHighlight().destroy(Gdx.gl30, this.terrain.centerOffset);
unit.unassignSelectionPreviewHighlight();
}
public void clearUnitMouseOverHighlight() {
for (final String modelKey : this.mouseHighlightSplatModelKeys) {
this.terrain.removeSplatBatchModel(modelKey);
}
for (final RenderWidget widget : this.mouseHighlightWidgets) {
widget.unassignSelectionPreviewHighlight();
}
this.mouseHighlightSplatModelKeys.clear();
this.mouseHighlightWidgets.clear();
}
public void showUnitMouseOverHighlight(final RenderWidget unit) {
final Map<String, Terrain.Splat> splats = new HashMap<String, Terrain.Splat>();
if (unit.getSelectionScale() > 0) {
String allyKey = "n:";
final float selectionSize = unit.getSelectionScale();
String path = null;
for (int i = 0; i < this.selectionCircleSizes.size(); i++) {
final SelectionCircleSize selectionCircleSize = this.selectionCircleSizes.get(i);
if ((selectionSize < selectionCircleSize.size) || (i == (this.selectionCircleSizes.size() - 1))) {
path = selectionCircleSize.texture;
break;
}
}
if (!path.toLowerCase().endsWith(".blp")) {
path += ".blp";
}
if (unit instanceof RenderUnit) {
final int selectedUnitPlayerIndex = ((RenderUnit) unit).getSimulationUnit().getPlayerIndex();
final CPlayer localPlayer = this.simulation.getPlayer(this.localPlayerIndex);
if (!localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.PASSIVE)) {
allyKey = "e:";
}
else if (localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.HELP_REQUEST)) {
allyKey = "f:";
}
}
path = allyKey + path;
final SplatModel splatModel = this.terrain.getSplatModel("mouseover:" + path);
if (splatModel != null) {
final float x = unit.getX();
final float y = unit.getY();
final SplatMover splatInstance = splatModel.add(x - (selectionSize / 2), y - (selectionSize / 2),
x + (selectionSize / 2), y + (selectionSize / 2), 4, this.terrain.centerOffset);
unit.assignSelectionPreviewHighlight(splatInstance);
if (unit.getInstance().hidden()) {
splatInstance.hide();
}
}
else {
if (!splats.containsKey(path)) {
splats.put(path, new Splat());
}
final float x = unit.getX();
final float y = unit.getY();
splats.get(path).locations.add(new float[] { x - (selectionSize / 2), y - (selectionSize / 2),
x + (selectionSize / 2), y + (selectionSize / 2), 4 });
splats.get(path).unitMapping.add(new Consumer<SplatModel.SplatMover>() {
@Override
public void accept(final SplatMover t) {
unit.assignSelectionPreviewHighlight(t);
if (unit.getInstance().hidden()) {
t.hide();
}
}
});
}
}
this.mouseHighlightWidgets.add(unit);
for (final Map.Entry<String, Terrain.Splat> entry : splats.entrySet()) {
final String path = entry.getKey();
final String filePath = path.substring(2);
final String allyKey = path.substring(0, 2);
final Splat locations = entry.getValue();
final SplatModel model = new SplatModel(Gdx.gl30, (Texture) load(filePath, PathSolver.DEFAULT, null),
locations.locations, this.terrain.centerOffset, locations.unitMapping, true, false, true);
switch (allyKey) {
case "e:":
model.color[0] = this.selectionCircleColorEnemy.r;
model.color[1] = this.selectionCircleColorEnemy.g;
model.color[2] = this.selectionCircleColorEnemy.b;
model.color[3] = this.selectionCircleColorEnemy.a * 0.5f;
break;
case "f:":
model.color[0] = this.selectionCircleColorFriend.r;
model.color[1] = this.selectionCircleColorFriend.g;
model.color[2] = this.selectionCircleColorFriend.b;
model.color[3] = this.selectionCircleColorFriend.a * 0.5f;
break;
default:
model.color[0] = this.selectionCircleColorNeutral.r;
model.color[1] = this.selectionCircleColorNeutral.g;
model.color[2] = this.selectionCircleColorNeutral.b;
model.color[3] = this.selectionCircleColorNeutral.a * 0.5f;
break;
}
this.mouseHighlightSplatModelKeys.add("mouseover:" + path);
this.terrain.addSplatBatchModel("mouseover:" + path, model);
}
}
public void getClickLocation(final Vector3 out, final int screenX, final int screenY) { public void getClickLocation(final Vector3 out, final int screenX, final int screenY) {
final float[] ray = rayHeap; final float[] ray = rayHeap;
mousePosHeap.set(screenX, screenY); mousePosHeap.set(screenX, screenY);
@ -1678,19 +1801,22 @@ public class War3MapViewer extends AbstractMdxModelViewer {
final MdxComplexInstance instance = unit.getInstance(); final MdxComplexInstance instance = unit.getInstance();
if (instance.shown() && instance.isVisible(this.worldScene.camera) if (instance.shown() && instance.isVisible(this.worldScene.camera)
&& instance.intersectRayWithCollisionSimple(gdxRayHeap, intersectionHeap)) { && instance.intersectRayWithCollisionSimple(gdxRayHeap, intersectionHeap)) {
if (filter.call(unit.getSimulationWidget()) && (intersectionHeap.z > this.terrain if (filter.call(unit.getSimulationWidget())) {
.getGroundHeight(intersectionHeap.x, intersectionHeap.y))) { final float groundHeight = this.terrain.getGroundHeight(intersectionHeap.x, intersectionHeap.y);
if (((entity == null) && !unit.isIntersectedOnMeshAlways())) { if (intersectionHeap.z > groundHeight) {
entity = unit; if (((entity == null) && !unit.isIntersectedOnMeshAlways())) {
} entity = unit;
else { }
if (instance.intersectRayWithMeshSlow(gdxRayHeap, intersectionHeap) else {
&& (intersectionHeap.z > this.terrain.getGroundHeight(intersectionHeap.x, if (instance.intersectRayWithMeshSlow(gdxRayHeap, intersectionHeap)) {
intersectionHeap.y))) { if (intersectionHeap.z > this.terrain.getGroundHeight(intersectionHeap.x,
this.worldScene.camera.worldToCamera(intersectionHeap, intersectionHeap); intersectionHeap.y)) {
if ((entity == null) || (intersectionHeap.z > intersectionHeap2.z)) { this.worldScene.camera.worldToCamera(intersectionHeap, intersectionHeap);
entity = unit; if ((entity == null) || (intersectionHeap.z > intersectionHeap2.z)) {
intersectionHeap2.set(intersectionHeap); entity = unit;
intersectionHeap2.set(intersectionHeap);
}
}
} }
} }
} }
@ -1773,6 +1899,12 @@ public class War3MapViewer extends AbstractMdxModelViewer {
public int imageWalkableZOffset; public int imageWalkableZOffset;
private WTS preloadedWTS; private WTS preloadedWTS;
private Color selectionCircleColorFriend;
private Color selectionCircleColorNeutral;
private Color selectionCircleColorEnemy;
/** /**
* Returns a power of two size for the given target capacity. * Returns a power of two size for the given target capacity.
*/ */
@ -1921,7 +2053,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
return this.itemToRenderPeer.get(item); return this.itemToRenderPeer.get(item);
} }
private RenderWidget getRenderPeer(final CWidget damagedDestructable) { public RenderWidget getRenderPeer(final CWidget damagedDestructable) {
RenderWidget damagedWidget = War3MapViewer.this.unitToRenderPeer.get(damagedDestructable); RenderWidget damagedWidget = War3MapViewer.this.unitToRenderPeer.get(damagedDestructable);
if (damagedWidget == null) { if (damagedWidget == null) {
damagedWidget = War3MapViewer.this.destructableToRenderPeer.get(damagedDestructable); damagedWidget = War3MapViewer.this.destructableToRenderPeer.get(damagedDestructable);

View File

@ -1,13 +1,18 @@
package com.etheller.warsmash.viewer5.handlers.w3x.camera; package com.etheller.warsmash.viewer5.handlers.w3x.camera;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input; import com.badlogic.gdx.Input;
import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Rectangle;
public final class GameCameraManager extends CameraManager { public final class GameCameraManager extends CameraManager {
private static final CameraRates INFINITE_CAMERA_RATES = new CameraRates(Float.POSITIVE_INFINITY,
Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY,
Float.POSITIVE_INFINITY);
private final CameraPreset[] presets; private final CameraPreset[] presets;
private final CameraRates cameraRates; private final CameraRates cameraRates;
public final CameraPanControls cameraPanControls; public final CameraPanControls cameraPanControls;
private int currentPreset = 0; private int currentPreset = 0;
private float fov;
public GameCameraManager(final CameraPreset[] presets, final CameraRates cameraRates) { public GameCameraManager(final CameraPreset[] presets, final CameraRates cameraRates) {
this.presets = presets; this.presets = presets;
@ -17,14 +22,22 @@ public final class GameCameraManager extends CameraManager {
@Override @Override
public void updateCamera() { public void updateCamera() {
this.quatHeap2.idt();
final CameraPreset cameraPreset = this.presets[this.currentPreset]; final CameraPreset cameraPreset = this.presets[this.currentPreset];
final CameraRates cameraRate = this.cameraRates;
updateCamera(cameraPreset, cameraRate);
}
private void updateCamera(final CameraPreset cameraPreset, final CameraRates cameraRate) {
this.quatHeap2.idt();
this.quatHeap.idt(); this.quatHeap.idt();
this.horizontalAngle = (float) Math.toRadians( this.horizontalAngle = applyAtRate(this.horizontalAngle, (float) Math.toRadians(
cameraPreset.getRotation(this.cameraPanControls.insertDown, this.cameraPanControls.deleteDown) - 90); cameraPreset.getRotation(this.cameraPanControls.insertDown, this.cameraPanControls.deleteDown) - 90),
(float) Math.toRadians(cameraRate.rotation * 3));
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle); this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
this.distance = Math.max(1200, cameraPreset.getDistance()); this.distance = applyAtRate(this.distance, Math.max(1200, cameraPreset.getDistance()), cameraRate.distance);
this.verticalAngle = (float) Math.toRadians(Math.min(335, cameraPreset.getAoa()) - 270); this.verticalAngle = applyAtRate(this.verticalAngle,
(float) Math.toRadians(Math.min(335, cameraPreset.getAoa()) - 270),
(float) Math.toRadians(cameraRate.aoa));
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);
@ -33,12 +46,24 @@ public final class GameCameraManager extends CameraManager {
this.position.nor(); this.position.nor();
this.position.scl(this.distance); this.position.scl(this.distance);
this.position = this.position.add(this.target); this.position = this.position.add(this.target);
this.camera.perspective((float) Math.toRadians(cameraPreset.getFov() / 2), this.camera.getAspect(), this.fov = applyAtRate(this.fov, (float) Math.toRadians(cameraPreset.getFov() / 2),
cameraPreset.getNearZ(), cameraPreset.getFarZ()); (float) Math.toRadians(cameraRate.fov));
this.camera.perspective(this.fov, this.camera.getAspect(), cameraPreset.getNearZ(), cameraPreset.getFarZ());
this.camera.moveToAndFace(this.position, this.target, this.worldUp); this.camera.moveToAndFace(this.position, this.target, this.worldUp);
} }
private static float applyAtRate(final float oldValue, final float newValue, float rate) {
rate *= Gdx.graphics.getDeltaTime();
final float deltaDistance = newValue - oldValue;
if (Math.abs(deltaDistance) < rate) {
return newValue;
}
else {
return oldValue + (Math.signum(deltaDistance) * rate);
}
}
public void resize(final Rectangle viewport) { public void resize(final Rectangle viewport) {
this.camera.viewport(viewport); this.camera.viewport(viewport);
} }

View File

@ -391,11 +391,11 @@ public class Terrain {
updateGroundHeights(new Rectangle(0, 0, width - 1, height - 1)); updateGroundHeights(new Rectangle(0, 0, width - 1, height - 1));
this.groundShader = webGL.createShaderProgram(TerrainShaders.Terrain.vert, TerrainShaders.Terrain.frag); this.groundShader = webGL.createShaderProgram(TerrainShaders.Terrain.vert(), TerrainShaders.Terrain.frag);
this.cliffShader = webGL.createShaderProgram(TerrainShaders.Cliffs.vert, TerrainShaders.Cliffs.frag); this.cliffShader = webGL.createShaderProgram(TerrainShaders.Cliffs.vert(), TerrainShaders.Cliffs.frag);
this.waterShader = webGL.createShaderProgram(TerrainShaders.Water.vert, TerrainShaders.Water.frag); this.waterShader = webGL.createShaderProgram(TerrainShaders.Water.vert(), TerrainShaders.Water.frag);
this.uberSplatShader = webGL.createShaderProgram(W3xShaders.UberSplat.vert, W3xShaders.UberSplat.frag); this.uberSplatShader = webGL.createShaderProgram(W3xShaders.UberSplat.vert(), W3xShaders.UberSplat.frag);
// TODO collision bodies (?) // TODO collision bodies (?)
@ -1443,6 +1443,10 @@ public class Terrain {
Collections.sort(this.uberSplatModelsList); Collections.sort(this.uberSplatModelsList);
} }
public SplatModel getSplatModel(final String pathKey) {
return this.uberSplatModels.get(pathKey);
}
public SplatMover addUberSplat(final String path, final float x, final float y, final float z, final float scale, public SplatMover addUberSplat(final String path, final float x, final float y, final float z, final float scale,
final boolean unshaded, final boolean noDepthTest, final boolean highPriority) { final boolean unshaded, final boolean noDepthTest, final boolean highPriority) {
SplatModel splatModel = this.uberSplatModels.get(path); SplatModel splatModel = this.uberSplatModels.get(path);

View File

@ -10,76 +10,78 @@ public class TerrainShaders {
private Cliffs() { private Cliffs() {
} }
public static final String vert = "#version 330 core\r\n" + // public static final String vert() {
"\r\n" + // return "#version 330 core\r\n" + //
"in vec3 vPosition;\r\n" + // "\r\n" + //
"in vec2 vUV;\r\n" + // "in vec3 vPosition;\r\n" + //
"in vec3 vNormal;\r\n" + // "in vec2 vUV;\r\n" + //
"in vec4 vOffset;\r\n" + // "in vec3 vNormal;\r\n" + //
"\r\n" + // "in vec4 vOffset;\r\n" + //
"uniform mat4 MVP;\r\n" + // "\r\n" + //
"\r\n" + // "uniform mat4 MVP;\r\n" + //
"uniform sampler2D height_texture;\r\n" + // "\r\n" + //
"uniform sampler2D shadowMap;\r\n" + // "uniform sampler2D height_texture;\r\n" + //
"uniform float centerOffsetX;\r\n" + // "uniform sampler2D shadowMap;\r\n" + //
"uniform float centerOffsetY;\r\n" + // "uniform float centerOffsetX;\r\n" + //
"uniform sampler2D lightTexture;\r\n" + // "uniform float centerOffsetY;\r\n" + //
"uniform float lightCount;\r\n" + // "uniform sampler2D lightTexture;\r\n" + //
"uniform float lightTextureHeight;\r\n" + // "uniform float lightCount;\r\n" + //
"\r\n" + // "uniform float lightTextureHeight;\r\n" + //
"out vec3 UV;\r\n" + // "\r\n" + //
"out vec3 Normal;\r\n" + // "out vec3 UV;\r\n" + //
"out vec2 pathing_map_uv;\r\n" + // "out vec3 Normal;\r\n" + //
"out vec3 position;\r\n" + // "out vec2 pathing_map_uv;\r\n" + //
"out vec2 v_suv;\r\n" + // "out vec3 position;\r\n" + //
"out vec3 shadeColor;\r\n" + // "out vec2 v_suv;\r\n" + //
"\r\n" + // "out vec3 shadeColor;\r\n" + //
"void main() {\r\n" + // "\r\n" + //
" pathing_map_uv = (vec2(vPosition.y, -vPosition.x) / 128 + vOffset.xy) * 4;\r\n" + // "void main() {\r\n" + //
" \r\n" + // " pathing_map_uv = (vec2(vPosition.y, -vPosition.x) / 128 + vOffset.xy) * 4;\r\n" + //
" ivec2 size = textureSize(height_texture, 0);\r\n" + // " \r\n" + //
" ivec2 shadowSize = textureSize(shadowMap, 0);\r\n" + // " ivec2 size = textureSize(height_texture, 0);\r\n" + //
" v_suv = pathing_map_uv / shadowSize;\r\n" + // " ivec2 shadowSize = textureSize(shadowMap, 0);\r\n" + //
" float value = texture(height_texture, (vOffset.xy + vec2(vPosition.y + 64, -vPosition.x + 64) / 128.0) / vec2(size)).r;\r\n" " v_suv = pathing_map_uv / shadowSize;\r\n" + //
+ // " float value = texture(height_texture, (vOffset.xy + vec2(vPosition.y + 64, -vPosition.x + 64) / 128.0) / vec2(size)).r;\r\n"
"\r\n" + // + //
" position = (vec3(vPosition.y, -vPosition.x, vPosition.z) + vec3(vOffset.xy, vOffset.z + value) * 128 );\r\n" "\r\n" + //
+ // " position = (vec3(vPosition.y, -vPosition.x, vPosition.z) + vec3(vOffset.xy, vOffset.z + value) * 128 );\r\n"
" vec4 myposition = vec4(position, 1);\r\n" + // + //
" myposition.x += centerOffsetX;\r\n" + // " vec4 myposition = vec4(position, 1);\r\n" + //
" myposition.y += centerOffsetY;\r\n" + // " myposition.x += centerOffsetX;\r\n" + //
" position.x /= (size.x * 128.0);\r\n" + // " myposition.y += centerOffsetY;\r\n" + //
" position.y /= (size.y * 128.0);\r\n" + // " position.x /= (size.x * 128.0);\r\n" + //
" gl_Position = MVP * myposition;\r\n" + // " position.y /= (size.y * 128.0);\r\n" + //
" UV = vec3(vUV, vOffset.a);\r\n" + // " gl_Position = MVP * myposition;\r\n" + //
"\r\n" + // " UV = vec3(vUV, vOffset.a);\r\n" + //
" ivec2 height_pos = ivec2(vOffset.xy + vec2(vPosition.y, -vPosition.x) / 128);\r\n" + // "\r\n" + //
" ivec3 off = ivec3(1, 1, 0);\r\n" + // " ivec2 height_pos = ivec2(vOffset.xy + vec2(vPosition.y, -vPosition.x) / 128);\r\n" + //
" float hL = texelFetch(height_texture, height_pos - off.xz, 0).r;\r\n" + // " ivec3 off = ivec3(1, 1, 0);\r\n" + //
" float hR = texelFetch(height_texture, height_pos + off.xz, 0).r;\r\n" + // " float hL = texelFetch(height_texture, height_pos - off.xz, 0).r;\r\n" + //
" float hD = texelFetch(height_texture, height_pos - off.zy, 0).r;\r\n" + // " float hR = texelFetch(height_texture, height_pos + off.xz, 0).r;\r\n" + //
" float hU = texelFetch(height_texture, height_pos + off.zy, 0).r;\r\n" + // " float hD = texelFetch(height_texture, height_pos - off.zy, 0).r;\r\n" + //
" bool edgeX = (vPosition.y) == float((int(vPosition.y))/128*128);\r\n" + // " float hU = texelFetch(height_texture, height_pos + off.zy, 0).r;\r\n" + //
" bool edgeY = (vPosition.x) == float((int(vPosition.x))/128*128);\r\n" + // " bool edgeX = (vPosition.y) == float((int(vPosition.y))/128*128);\r\n" + //
" bool edgeZ = (vPosition.z) == float((int(vPosition.z))/128*128);\r\n" + // " bool edgeY = (vPosition.x) == float((int(vPosition.x))/128*128);\r\n" + //
" vec3 terrain_normal = vec3(vNormal.y, -vNormal.x, vNormal.z);\r\n" + // " bool edgeZ = (vPosition.z) == float((int(vPosition.z))/128*128);\r\n" + //
" if(edgeX) {\r\n" + // " vec3 terrain_normal = vec3(vNormal.y, -vNormal.x, vNormal.z);\r\n" + //
" terrain_normal.x = hL - hR;\r\n" + // " if(edgeX) {\r\n" + //
" }\r\n" + // " terrain_normal.x = hL - hR;\r\n" + //
" if(edgeY) {\r\n" + // " }\r\n" + //
" terrain_normal.y = hD - hU;\r\n" + // " if(edgeY) {\r\n" + //
" }\r\n" + // " terrain_normal.y = hD - hU;\r\n" + //
" if(edgeZ) {\r\n" + // " }\r\n" + //
" terrain_normal.z = 2.0;\r\n" + // " if(edgeZ) {\r\n" + //
" }\r\n" + // " terrain_normal.z = 2.0;\r\n" + //
" terrain_normal = normalize(terrain_normal);\r\n" + // " }\r\n" + //
"\r\n" + // " terrain_normal = normalize(terrain_normal);\r\n" + //
" Normal = terrain_normal;\r\n" + // "\r\n" + //
Shaders.lightSystem("terrain_normal", "myposition.xyz", "lightTexture", "lightTextureHeight", " Normal = terrain_normal;\r\n" + //
"lightCount", true) Shaders.lightSystem("terrain_normal", "myposition.xyz", "lightTexture", "lightTextureHeight",
+ "\r\n" + // "lightCount", true)
" shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + // + "\r\n" + //
"}"; " shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + //
"}";
}
public static final String frag = "#version 330 core\r\n" + // public static final String frag = "#version 330 core\r\n" + //
"\r\n" + // "\r\n" + //
@ -113,62 +115,65 @@ public class TerrainShaders {
private Terrain() { private Terrain() {
} }
public static final String vert = "#version 330 core\r\n" + // public static final String vert() {
"\r\n" + // return "#version 330 core\r\n" + //
"in vec2 vPosition;\r\n" + // "\r\n" + //
"uniform mat4 MVP;\r\n" + // "in vec2 vPosition;\r\n" + //
"uniform mat4 DepthBiasMVP;\r\n" + // "uniform mat4 MVP;\r\n" + //
"\r\n" + // "uniform mat4 DepthBiasMVP;\r\n" + //
"uniform sampler2D height_texture;\r\n" + // "\r\n" + //
"uniform sampler2D height_cliff_texture;\r\n" + // "uniform sampler2D height_texture;\r\n" + //
"uniform usampler2D terrain_texture_list;\r\n" + // "uniform sampler2D height_cliff_texture;\r\n" + //
"uniform float centerOffsetX;\r\n" + // "uniform usampler2D terrain_texture_list;\r\n" + //
"uniform float centerOffsetY;\r\n" + // "uniform float centerOffsetX;\r\n" + //
"uniform sampler2D lightTexture;\r\n" + // "uniform float centerOffsetY;\r\n" + //
"uniform float lightCount;\r\n" + // "uniform sampler2D lightTexture;\r\n" + //
"uniform float lightTextureHeight;\r\n" + // "uniform float lightCount;\r\n" + //
"\r\n" + // "uniform float lightTextureHeight;\r\n" + //
"out vec2 UV;\r\n" + // "\r\n" + //
"flat out uvec4 texture_indices;\r\n" + // "out vec2 UV;\r\n" + //
"out vec2 pathing_map_uv;\r\n" + // "flat out uvec4 texture_indices;\r\n" + //
"out vec3 position;\r\n" + // "out vec2 pathing_map_uv;\r\n" + //
"out vec3 ShadowCoord;\r\n" + // "out vec3 position;\r\n" + //
"out vec2 v_suv;\r\n" + // "out vec3 ShadowCoord;\r\n" + //
"out vec3 shadeColor;\r\n" + // "out vec2 v_suv;\r\n" + //
"\r\n" + // "out vec3 shadeColor;\r\n" + //
"void main() { \r\n" + // "\r\n" + //
" ivec2 size = textureSize(terrain_texture_list, 0);\r\n" + // "void main() { \r\n" + //
" ivec2 pos = ivec2(gl_InstanceID % size.x, gl_InstanceID / size.x);\r\n" + // " ivec2 size = textureSize(terrain_texture_list, 0);\r\n" + //
"\r\n" + // " ivec2 pos = ivec2(gl_InstanceID % size.x, gl_InstanceID / size.x);\r\n" + //
" ivec2 height_pos = ivec2(vPosition + pos);\r\n" + // "\r\n" + //
" vec4 height = texelFetch(height_cliff_texture, height_pos, 0);\r\n" + // " ivec2 height_pos = ivec2(vPosition + pos);\r\n" + //
"\r\n" + // " vec4 height = texelFetch(height_cliff_texture, height_pos, 0);\r\n" + //
" ivec3 off = ivec3(1, 1, 0);\r\n" + // "\r\n" + //
" float hL = texelFetch(height_texture, height_pos - off.xz, 0).r;\r\n" + // " ivec3 off = ivec3(1, 1, 0);\r\n" + //
" float hR = texelFetch(height_texture, height_pos + off.xz, 0).r;\r\n" + // " float hL = texelFetch(height_texture, height_pos - off.xz, 0).r;\r\n" + //
" float hD = texelFetch(height_texture, height_pos - off.zy, 0).r;\r\n" + // " float hR = texelFetch(height_texture, height_pos + off.xz, 0).r;\r\n" + //
" float hU = texelFetch(height_texture, height_pos + off.zy, 0).r;\r\n" + // " float hD = texelFetch(height_texture, height_pos - off.zy, 0).r;\r\n" + //
" vec3 normal = normalize(vec3(hL - hR, hD - hU, 2.0));\r\n" + // " float hU = texelFetch(height_texture, height_pos + off.zy, 0).r;\r\n" + //
"\r\n" + // " vec3 normal = normalize(vec3(hL - hR, hD - hU, 2.0));\r\n" + //
" UV = vec2(vPosition.x, 1 - vPosition.y);\r\n" + // "\r\n" + //
" texture_indices = texelFetch(terrain_texture_list, pos, 0);\r\n" + // " UV = vec2(vPosition.x, 1 - vPosition.y);\r\n" + //
" pathing_map_uv = (vPosition + pos) * 4; \r\n" + // " texture_indices = texelFetch(terrain_texture_list, pos, 0);\r\n" + //
"\r\n" + // " pathing_map_uv = (vPosition + pos) * 4; \r\n" + //
" // Cliff culling\r\n" + // "\r\n" + //
" vec3 positionWorld = vec3((vPosition.x + pos.x)*128.0 + centerOffsetX, (vPosition.y + pos.y)*128.0 + centerOffsetY, height.r*128.0);\r\n" " // Cliff culling\r\n" + //
+ // " vec3 positionWorld = vec3((vPosition.x + pos.x)*128.0 + centerOffsetX, (vPosition.y + pos.y)*128.0 + centerOffsetY, height.r*128.0);\r\n"
" position = positionWorld;\r\n" + // + //
" gl_Position = ((texture_indices.a & 32768u) == 0u) ? MVP * vec4(position.xyz, 1) : vec4(2.0, 0.0, 0.0, 1.0);\r\n" " position = positionWorld;\r\n" + //
+ // " gl_Position = ((texture_indices.a & 32768u) == 0u) ? MVP * vec4(position.xyz, 1) : vec4(2.0, 0.0, 0.0, 1.0);\r\n"
" ShadowCoord = (((texture_indices.a & 32768u) == 0u) ? DepthBiasMVP * vec4(position.xyz, 1) : vec4(2.0, 0.0, 0.0, 1.0)).xyz;\r\n" + //
+ // " ShadowCoord = (((texture_indices.a & 32768u) == 0u) ? DepthBiasMVP * vec4(position.xyz, 1) : vec4(2.0, 0.0, 0.0, 1.0)).xyz;\r\n"
" v_suv = (vPosition + pos) / size;\r\n" + // + //
" position.x = (position.x - centerOffsetX) / (size.x * 128.0);\r\n" + // " v_suv = (vPosition + pos) / size;\r\n" + //
" position.y = (position.y - centerOffsetY) / (size.y * 128.0);\r\n" + // " position.x = (position.x - centerOffsetX) / (size.x * 128.0);\r\n" + //
Shaders.lightSystem("normal", "positionWorld", "lightTexture", "lightTextureHeight", "lightCount", true) " position.y = (position.y - centerOffsetY) / (size.y * 128.0);\r\n" + //
+ "\r\n" + // Shaders.lightSystem("normal", "positionWorld", "lightTexture", "lightTextureHeight", "lightCount",
" shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + // true)
"}"; + "\r\n" + //
" shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + //
"}";
}
public static final String frag = "#version 330 core\r\n" + // public static final String frag = "#version 330 core\r\n" + //
"\r\n" + // "\r\n" + //
@ -291,68 +296,70 @@ public class TerrainShaders {
private Water() { private Water() {
} }
public static final String vert = "#version 330 core\r\n" + // public static final String vert() {
"\r\n" + // return "#version 330 core\r\n" + //
"in vec2 vPosition;\r\n" + // "\r\n" + //
"\r\n" + // "in vec2 vPosition;\r\n" + //
"uniform sampler2D water_height_texture;\r\n" + // "\r\n" + //
"uniform sampler2D ground_height_texture;\r\n" + // "uniform sampler2D water_height_texture;\r\n" + //
"uniform sampler2D water_exists_texture;\r\n" + // "uniform sampler2D ground_height_texture;\r\n" + //
"uniform float centerOffsetX;\r\n" + // "uniform sampler2D water_exists_texture;\r\n" + //
"uniform float centerOffsetY;\r\n" + // "uniform float centerOffsetX;\r\n" + //
"\r\n" + // "uniform float centerOffsetY;\r\n" + //
"uniform mat4 MVP;\r\n" + // "\r\n" + //
"uniform vec4 shallow_color_min;\r\n" + // "uniform mat4 MVP;\r\n" + //
"uniform vec4 shallow_color_max;\r\n" + // "uniform vec4 shallow_color_min;\r\n" + //
"uniform vec4 deep_color_min;\r\n" + // "uniform vec4 shallow_color_max;\r\n" + //
"uniform vec4 deep_color_max;\r\n" + // "uniform vec4 deep_color_min;\r\n" + //
"uniform float water_offset;\r\n" + // "uniform vec4 deep_color_max;\r\n" + //
"uniform sampler2D lightTexture;\r\n" + // "uniform float water_offset;\r\n" + //
"uniform float lightCount;\r\n" + // "uniform sampler2D lightTexture;\r\n" + //
"uniform float lightTextureHeight;\r\n" + // "uniform float lightCount;\r\n" + //
"\r\n" + // "uniform float lightTextureHeight;\r\n" + //
"out vec2 UV;\r\n" + // "\r\n" + //
"out vec4 Color;\r\n" + // "out vec2 UV;\r\n" + //
"out vec2 position;\r\n" + // "out vec4 Color;\r\n" + //
"out vec3 shadeColor;\r\n" + // "out vec2 position;\r\n" + //
"\r\n" + // "out vec3 shadeColor;\r\n" + //
"const float min_depth = 10.f / 128;\r\n" + // "\r\n" + //
"const float deeplevel = 64.f / 128;\r\n" + // "const float min_depth = 10.f / 128;\r\n" + //
"const float maxdepth = 72.f / 128;\r\n" + // "const float deeplevel = 64.f / 128;\r\n" + //
"\r\n" + // "const float maxdepth = 72.f / 128;\r\n" + //
"void main() { \r\n" + // "\r\n" + //
" ivec2 size = textureSize(water_height_texture, 0) - 1;\r\n" + // "void main() { \r\n" + //
" ivec2 pos = ivec2(gl_InstanceID % size.x, gl_InstanceID / size.x);\r\n" + // " ivec2 size = textureSize(water_height_texture, 0) - 1;\r\n" + //
" ivec2 height_pos = ivec2(vPosition + pos);\r\n" + // " ivec2 pos = ivec2(gl_InstanceID % size.x, gl_InstanceID / size.x);\r\n" + //
" float water_height = texelFetch(water_height_texture, height_pos, 0).r + water_offset;\r\n" + // " ivec2 height_pos = ivec2(vPosition + pos);\r\n" + //
"\r\n" + // " float water_height = texelFetch(water_height_texture, height_pos, 0).r + water_offset;\r\n" + //
" bool is_water = texelFetch(water_exists_texture, pos, 0).r > 0\r\n" + // "\r\n" + //
" || texelFetch(water_exists_texture, pos + ivec2(1, 0), 0).r > 0\r\n" + // " bool is_water = texelFetch(water_exists_texture, pos, 0).r > 0\r\n" + //
" || texelFetch(water_exists_texture, pos + ivec2(1, 1), 0).r > 0\r\n" + // " || texelFetch(water_exists_texture, pos + ivec2(1, 0), 0).r > 0\r\n" + //
" || texelFetch(water_exists_texture, pos + ivec2(0, 1), 0).r > 0;\r\n" + // " || texelFetch(water_exists_texture, pos + ivec2(1, 1), 0).r > 0\r\n" + //
"\r\n" + // " || texelFetch(water_exists_texture, pos + ivec2(0, 1), 0).r > 0;\r\n" + //
" position = vec2((vPosition.x + pos.x)*128.0 + centerOffsetX, (vPosition.y + pos.y)*128.0 + centerOffsetY);\r\n" "\r\n" + //
+ // " position = vec2((vPosition.x + pos.x)*128.0 + centerOffsetX, (vPosition.y + pos.y)*128.0 + centerOffsetY);\r\n"
" vec4 myposition = vec4(position.xy, water_height*128.0, 1);\r\n" + // + //
" vec3 Normal = vec3(0,0,1);\r\n" + // " vec4 myposition = vec4(position.xy, water_height*128.0, 1);\r\n" + //
" gl_Position = is_water ? MVP * myposition : vec4(2.0, 0.0, 0.0, 1.0);\r\n" + // " vec3 Normal = vec3(0,0,1);\r\n" + //
"\r\n" + // " gl_Position = is_water ? MVP * myposition : vec4(2.0, 0.0, 0.0, 1.0);\r\n" + //
" UV = vec2((vPosition.x + pos.x%2)/2.0, (vPosition.y + pos.y%2)/2.0);\r\n" + // "\r\n" + //
"\r\n" + // " UV = vec2((vPosition.x + pos.x%2)/2.0, (vPosition.y + pos.y%2)/2.0);\r\n" + //
" float ground_height = texelFetch(ground_height_texture, height_pos, 0).r;\r\n" + // "\r\n" + //
" float value = clamp(water_height - ground_height, 0.f, 1.f);\r\n" + // " float ground_height = texelFetch(ground_height_texture, height_pos, 0).r;\r\n" + //
" if (value <= deeplevel) {\r\n" + // " float value = clamp(water_height - ground_height, 0.f, 1.f);\r\n" + //
" value = max(0.f, value - min_depth) / (deeplevel - min_depth);\r\n" + // " if (value <= deeplevel) {\r\n" + //
" Color = shallow_color_min * (1.f - value) + shallow_color_max * value;\r\n" + // " value = max(0.f, value - min_depth) / (deeplevel - min_depth);\r\n" + //
" } else {\r\n" + // " Color = shallow_color_min * (1.f - value) + shallow_color_max * value;\r\n" + //
" value = clamp(value - deeplevel, 0.f, maxdepth - deeplevel) / (maxdepth - deeplevel);\r\n" + // " } else {\r\n" + //
" Color = deep_color_min * (1.f - value) + deep_color_max * value;\r\n" + // " value = clamp(value - deeplevel, 0.f, maxdepth - deeplevel) / (maxdepth - deeplevel);\r\n" + //
" }\r\n" + // " Color = deep_color_min * (1.f - value) + deep_color_max * value;\r\n" + //
Shaders.lightSystem("Normal", "myposition.xyz", "lightTexture", "lightTextureHeight", "lightCount", " }\r\n" + //
true) Shaders.lightSystem("Normal", "myposition.xyz", "lightTexture", "lightTextureHeight", "lightCount",
+ "\r\n" + // true)
" shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + // + "\r\n" + //
" }"; " shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + //
" }";
}
public static final String frag = "#version 330 core\r\n" + // public static final String frag = "#version 330 core\r\n" + //
"\r\n" + // "\r\n" + //

View File

@ -24,9 +24,11 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
public Rectangle walkableBounds; public Rectangle walkableBounds;
private final CDestructable simulationDestructable; private final CDestructable simulationDestructable;
private SplatMover selectionCircle; private SplatMover selectionCircle;
private SplatMover selectionPreviewHighlight;
private final UnitAnimationListenerImpl unitAnimationListenerImpl; private final UnitAnimationListenerImpl unitAnimationListenerImpl;
private boolean dead; private boolean dead;
private BuildingShadow destructableShadow; private BuildingShadow destructableShadow;
private final boolean selectable;
public RenderDestructable(final War3MapViewer map, final MdxModel model, final MutableGameObject row, public RenderDestructable(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad, final WorldEditorDataType type, final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad, final WorldEditorDataType type,
@ -50,6 +52,7 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
this.unitAnimationListenerImpl = new UnitAnimationListenerImpl((MdxComplexInstance) this.instance); this.unitAnimationListenerImpl = new UnitAnimationListenerImpl((MdxComplexInstance) this.instance);
simulationDestructable.setUnitAnimationListener(this.unitAnimationListenerImpl); simulationDestructable.setUnitAnimationListener(this.unitAnimationListenerImpl);
this.unitAnimationListenerImpl.playAnimation(true, getAnimation(), SequenceUtils.EMPTY, 1.0f, true); this.unitAnimationListenerImpl.playAnimation(true, getAnimation(), SequenceUtils.EMPTY, 1.0f, true);
this.selectable = row.readSLKTagBoolean("selectable");
} }
@Override @Override
@ -86,6 +89,10 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
this.selectionCircle.destroy(Gdx.gl30, war3MapViewer.terrain.centerOffset); this.selectionCircle.destroy(Gdx.gl30, war3MapViewer.terrain.centerOffset);
this.selectionCircle = null; this.selectionCircle = null;
} }
if (this.selectionPreviewHighlight != null) {
this.selectionPreviewHighlight.destroy(Gdx.gl30, war3MapViewer.terrain.centerOffset);
this.selectionPreviewHighlight = null;
}
} }
else if (!dead) { else if (!dead) {
if (this.dead) { if (this.dead) {
@ -140,6 +147,25 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
@Override @Override
public void assignSelectionCircle(final SplatMover selectionCircle) { public void assignSelectionCircle(final SplatMover selectionCircle) {
this.selectionCircle = selectionCircle; this.selectionCircle = selectionCircle;
}
@Override
public void unassignSelectionPreviewHighlight() {
this.selectionPreviewHighlight = null;
}
@Override
public void assignSelectionPreviewHighlight(final SplatMover t) {
this.selectionPreviewHighlight = t;
}
@Override
public boolean isSelectable() {
return this.selectable;
}
@Override
public SplatMover getSelectionPreviewHighlight() {
return this.selectionPreviewHighlight;
} }
} }

View File

@ -27,6 +27,7 @@ public class RenderItem implements RenderWidget {
public final MdxModel portraitModel; public final MdxModel portraitModel;
public SplatMover shadow; public SplatMover shadow;
public SplatMover selectionCircle; public SplatMover selectionCircle;
public SplatMover selectionPreviewHighlight;
private boolean hidden; private boolean hidden;
private boolean dead; private boolean dead;
@ -176,4 +177,24 @@ public class RenderItem implements RenderWidget {
public void assignSelectionCircle(final SplatMover t) { public void assignSelectionCircle(final SplatMover t) {
this.selectionCircle = t; this.selectionCircle = t;
} }
@Override
public void unassignSelectionPreviewHighlight() {
this.selectionPreviewHighlight = null;
}
@Override
public void assignSelectionPreviewHighlight(final SplatMover t) {
this.selectionPreviewHighlight = t;
}
@Override
public boolean isSelectable() {
return true;
}
@Override
public SplatMover getSelectionPreviewHighlight() {
return this.selectionPreviewHighlight;
}
} }

View File

@ -52,6 +52,7 @@ public class RenderUnit implements RenderWidget {
public SplatMover shadow; public SplatMover shadow;
private BuildingShadow buildingShadowInstance; private BuildingShadow buildingShadowInstance;
public SplatMover selectionCircle; public SplatMover selectionCircle;
public SplatMover selectionPreviewHighlight;
private float facing; private float facing;
@ -161,6 +162,9 @@ public class RenderUnit implements RenderWidget {
if (this.selectionCircle != null) { if (this.selectionCircle != null) {
this.selectionCircle.hide(); this.selectionCircle.hide();
} }
if (this.selectionPreviewHighlight != null) {
this.selectionPreviewHighlight.hide();
}
if (this.shadow != null) { if (this.shadow != null) {
this.shadow.hide(); this.shadow.hide();
} }
@ -174,6 +178,9 @@ public class RenderUnit implements RenderWidget {
if (this.selectionCircle != null) { if (this.selectionCircle != null) {
this.selectionCircle.show(map.terrain.centerOffset); this.selectionCircle.show(map.terrain.centerOffset);
} }
if (this.selectionPreviewHighlight != null) {
this.selectionPreviewHighlight.show(map.terrain.centerOffset);
}
if (this.shadow != null) { if (this.shadow != null) {
this.shadow.show(map.terrain.centerOffset); this.shadow.show(map.terrain.centerOffset);
} }
@ -276,6 +283,10 @@ public class RenderUnit implements RenderWidget {
this.selectionCircle.destroy(Gdx.gl30, map.terrain.centerOffset); this.selectionCircle.destroy(Gdx.gl30, map.terrain.centerOffset);
this.selectionCircle = null; this.selectionCircle = null;
} }
if (this.selectionPreviewHighlight != null) {
this.selectionPreviewHighlight.destroy(Gdx.gl30, map.terrain.centerOffset);
this.selectionPreviewHighlight = null;
}
} }
if (boneCorpse && !this.boneCorpse) { if (boneCorpse && !this.boneCorpse) {
this.unitAnimationListenerImpl.playAnimationWithDuration(true, PrimaryTag.DECAY, SequenceUtils.BONE, this.unitAnimationListenerImpl.playAnimationWithDuration(true, PrimaryTag.DECAY, SequenceUtils.BONE,
@ -404,6 +415,13 @@ public class RenderUnit implements RenderWidget {
|| ((movementType == MovementType.FLY) || (movementType == MovementType.HOVER)), || ((movementType == MovementType.FLY) || (movementType == MovementType.HOVER)),
selectionCircleHeight + map.imageWalkableZOffset); selectionCircleHeight + map.imageWalkableZOffset);
} }
if (this.selectionPreviewHighlight != null) {
this.selectionPreviewHighlight.move(dx, dy, map.terrain.centerOffset);
this.selectionPreviewHighlight.setHeightAbsolute(
(currentWalkableUnder != null)
|| ((movementType == MovementType.FLY) || (movementType == MovementType.HOVER)),
selectionCircleHeight + map.imageWalkableZOffset);
}
this.unitAnimationListenerImpl.update(); this.unitAnimationListenerImpl.update();
if (!dead && this.simulationUnit.isConstructing()) { if (!dead && this.simulationUnit.isConstructing()) {
this.instance.setFrameByRatio( this.instance.setFrameByRatio(
@ -447,6 +465,9 @@ public class RenderUnit implements RenderWidget {
if (this.selectionCircle != null) { if (this.selectionCircle != null) {
this.selectionCircle.move(dx, dy, map.terrain.centerOffset); this.selectionCircle.move(dx, dy, map.terrain.centerOffset);
} }
if (this.selectionPreviewHighlight != null) {
this.selectionPreviewHighlight.move(dx, dy, map.terrain.centerOffset);
}
this.location[0] = this.simulationUnit.getX(); this.location[0] = this.simulationUnit.getX();
this.location[1] = this.simulationUnit.getY(); this.location[1] = this.simulationUnit.getY();
} }
@ -463,7 +484,7 @@ public class RenderUnit implements RenderWidget {
@Override @Override
public boolean isIntersectedOnMeshAlways() { public boolean isIntersectedOnMeshAlways() {
return this.simulationUnit.getUnitType().isBuilding(); return this.simulationUnit.isBuilding();
} }
@Override @Override
@ -495,4 +516,24 @@ public class RenderUnit implements RenderWidget {
public void assignSelectionCircle(final SplatMover t) { public void assignSelectionCircle(final SplatMover t) {
this.selectionCircle = t; this.selectionCircle = t;
} }
@Override
public void unassignSelectionPreviewHighlight() {
this.selectionPreviewHighlight = null;
}
@Override
public void assignSelectionPreviewHighlight(final SplatMover t) {
this.selectionPreviewHighlight = t;
}
@Override
public boolean isSelectable() {
return true; // later needs locust
}
@Override
public SplatMover getSelectionPreviewHighlight() {
return this.selectionPreviewHighlight;
}
} }

View File

@ -37,6 +37,12 @@ public interface RenderWidget {
void assignSelectionCircle(SplatMover t); void assignSelectionCircle(SplatMover t);
void unassignSelectionPreviewHighlight();
void assignSelectionPreviewHighlight(SplatMover t);
boolean isSelectable();
public static final class UnitAnimationListenerImpl implements CUnitAnimationListener { public static final class UnitAnimationListenerImpl implements CUnitAnimationListener {
private final MdxComplexInstance instance; private final MdxComplexInstance instance;
protected final EnumSet<AnimationTokens.SecondaryTag> secondaryAnimationTags = EnumSet protected final EnumSet<AnimationTokens.SecondaryTag> secondaryAnimationTags = EnumSet
@ -159,4 +165,6 @@ public interface RenderWidget {
this.allowRarityVariations = allowRarityVariations; this.allowRarityVariations = allowRarityVariations;
} }
} }
SplatMover getSelectionPreviewHighlight();
} }

View File

@ -14,6 +14,7 @@ public class CDestructable extends CWidget {
private final RemovablePathingMapInstance pathingInstance; private final RemovablePathingMapInstance pathingInstance;
private final RemovablePathingMapInstance pathingInstanceDeath; private final RemovablePathingMapInstance pathingInstanceDeath;
private UnitAnimationListenerImpl unitAnimationListenerImpl; private UnitAnimationListenerImpl unitAnimationListenerImpl;
private boolean invulnerable;
public CDestructable(final int handleId, final float x, final float y, final float life, public CDestructable(final int handleId, final float x, final float y, final float life,
final CDestructableType destTypeInstance, final RemovablePathingMapInstance pathingInstance, final CDestructableType destTypeInstance, final RemovablePathingMapInstance pathingInstance,
@ -80,4 +81,18 @@ public class CDestructable extends CWidget {
public void setUnitAnimationListener(final UnitAnimationListenerImpl unitAnimationListenerImpl) { public void setUnitAnimationListener(final UnitAnimationListenerImpl unitAnimationListenerImpl) {
this.unitAnimationListenerImpl = unitAnimationListenerImpl; this.unitAnimationListenerImpl = unitAnimationListenerImpl;
} }
@Override
public float getMaxLife() {
return this.destType.getLife();
}
public void setInvulnerable(final boolean invulnerable) {
this.invulnerable = invulnerable;
}
@Override
public boolean isInvulnerable() {
return this.invulnerable;
}
} }

View File

@ -73,6 +73,11 @@ public class CItem extends CWidget {
return this.hidden; return this.hidden;
} }
@Override
public float getMaxLife() {
return this.itemType.getHitPoints();
}
public void setPointAndCheckUnstuck(final float newX, final float newY, final CSimulation game) { public void setPointAndCheckUnstuck(final float newX, final float newY, final CSimulation game) {
final CWorldCollision collision = game.getWorldCollision(); final CWorldCollision collision = game.getWorldCollision();
final PathingGrid pathingGrid = game.getPathingGrid(); final PathingGrid pathingGrid = game.getPathingGrid();
@ -100,4 +105,9 @@ public class CItem extends CWidget {
setY(outputY); setY(outputY);
} }
@Override
public boolean isInvulnerable() {
return false;
}
} }

View File

@ -201,14 +201,14 @@ public class CUnit extends CWidget {
return this.mana; return this.mana;
} }
public int getMaximumLife() {
return this.maximumLife;
}
public int getMaximumMana() { public int getMaximumMana() {
return this.maximumMana; return this.maximumMana;
} }
public int getMaximumLife() {
return this.maximumLife;
}
public void setTypeId(final War3ID typeId) { public void setTypeId(final War3ID typeId) {
this.typeId = typeId; this.typeId = typeId;
} }
@ -430,7 +430,7 @@ public class CUnit extends CWidget {
} }
public float getEndingDecayTime(final CSimulation game) { public float getEndingDecayTime(final CSimulation game) {
if (this.unitType.isBuilding()) { if (this.isBuilding()) {
return game.getGameplayConstants().getStructureDecayTime(); return game.getGameplayConstants().getStructureDecayTime();
} }
return game.getGameplayConstants().getBoneDecayTime(); return game.getGameplayConstants().getBoneDecayTime();
@ -630,7 +630,7 @@ public class CUnit extends CWidget {
public void setX(final float newX, final CWorldCollision collision, final CRegionManager regionManager) { public void setX(final float newX, final CWorldCollision collision, final CRegionManager regionManager) {
final float prevX = getX(); final float prevX = getX();
if (!this.unitType.isBuilding()) { if (!this.isBuilding()) {
setX(newX); setX(newX);
collision.translate(this, newX - prevX, 0); collision.translate(this, newX - prevX, 0);
} }
@ -639,7 +639,7 @@ public class CUnit extends CWidget {
public void setY(final float newY, final CWorldCollision collision, final CRegionManager regionManager) { public void setY(final float newY, final CWorldCollision collision, final CRegionManager regionManager) {
final float prevY = getY(); final float prevY = getY();
if (!this.unitType.isBuilding()) { if (!this.isBuilding()) {
setY(newY); setY(newY);
collision.translate(this, 0, newY - prevY); collision.translate(this, 0, newY - prevY);
} }
@ -692,7 +692,7 @@ public class CUnit extends CWidget {
final float prevY = getY(); final float prevY = getY();
setX(newX); setX(newX);
setY(newY); setY(newY);
if (!this.unitType.isBuilding()) { if (!this.isBuilding()) {
collision.translate(this, newX - prevX, newY - prevY); collision.translate(this, newX - prevX, newY - prevY);
} }
checkRegionEvents(regionManager); checkRegionEvents(regionManager);
@ -867,7 +867,7 @@ public class CUnit extends CWidget {
final CPlayer sourcePlayer = simulation.getPlayer(source.getPlayerIndex()); final CPlayer sourcePlayer = simulation.getPlayer(source.getPlayerIndex());
if (!sourcePlayer.hasAlliance(this.playerIndex, CAllianceType.PASSIVE)) { if (!sourcePlayer.hasAlliance(this.playerIndex, CAllianceType.PASSIVE)) {
final CGameplayConstants gameplayConstants = simulation.getGameplayConstants(); final CGameplayConstants gameplayConstants = simulation.getGameplayConstants();
if (gameplayConstants.isBuildingKillsGiveExp() || !source.getUnitType().isBuilding()) { if (gameplayConstants.isBuildingKillsGiveExp() || !source.isBuilding()) {
final CUnit killedUnit = this; final CUnit killedUnit = this;
final CAbilityHero killedUnitHeroData = getHeroData(); final CAbilityHero killedUnitHeroData = getHeroData();
final boolean killedUnitIsAHero = killedUnitHeroData != null; final boolean killedUnitIsAHero = killedUnitHeroData != null;
@ -917,7 +917,7 @@ public class CUnit extends CWidget {
if (target instanceof CUnit) { if (target instanceof CUnit) {
final CUnit targetUnit = (CUnit) target; final CUnit targetUnit = (CUnit) target;
final CUnitType targetUnitType = targetUnit.getUnitType(); final CUnitType targetUnitType = targetUnit.getUnitType();
if (targetUnitType.isBuilding() && (targetUnitType.getBuildingPathingPixelMap() != null)) { if (targetUnit.isBuilding() && (targetUnitType.getBuildingPathingPixelMap() != null)) {
final BufferedImage buildingPathingPixelMap = targetUnitType.getBuildingPathingPixelMap(); final BufferedImage buildingPathingPixelMap = targetUnitType.getBuildingPathingPixelMap();
final float targetX = target.getX(); final float targetX = target.getX();
final float targetY = target.getY(); final float targetY = target.getY();
@ -1061,7 +1061,7 @@ public class CUnit extends CWidget {
} }
public boolean isMovementDisabled() { public boolean isMovementDisabled() {
return this.unitType.isBuilding(); return this.isBuilding();
} }
public float getAcquisitionRange() { public float getAcquisitionRange() {
@ -1205,6 +1205,7 @@ public class CUnit extends CWidget {
this.invulnerable = invulnerable; this.invulnerable = invulnerable;
} }
@Override
public boolean isInvulnerable() { public boolean isInvulnerable() {
return this.invulnerable; return this.invulnerable;
} }
@ -1537,6 +1538,11 @@ public class CUnit extends CWidget {
return this.containingRegions.contains(region); return this.containingRegions.contains(region);
} }
@Override
public float getMaxLife() {
return this.maximumLife;
}
private static final class RegionCheckerImpl implements CRegionEnumFunction { private static final class RegionCheckerImpl implements CRegionEnumFunction {
private CUnit unit; private CUnit unit;
@ -1556,4 +1562,8 @@ public class CUnit extends CWidget {
} }
} }
public boolean isBuilding() {
return this.unitType.isBuilding();
}
} }

View File

@ -74,6 +74,7 @@ public class CUnitType {
private final List<String> heroProperNames; private final List<String> heroProperNames;
private final int properNamesCount; private final int properNamesCount;
private final boolean canFlee; private final boolean canFlee;
private final int priority;
public CUnitType(final String name, final String legacyName, final War3ID typeId, final int life, public CUnitType(final String name, final String legacyName, final War3ID typeId, final int life,
final int manaInitial, final int manaMaximum, final int speed, final int defense, final String abilityList, final int manaInitial, final int manaMaximum, final int speed, final int defense, final String abilityList,
@ -91,7 +92,7 @@ public class CUnitType {
final float strengthPerLevel, final int agility, final float agilityPerLevel, final int intelligence, final float strengthPerLevel, final int agility, final float agilityPerLevel, final int intelligence,
final float intelligencePerLevel, final CPrimaryAttribute primaryAttribute, final float intelligencePerLevel, final CPrimaryAttribute primaryAttribute,
final List<War3ID> heroAbilityList, final List<String> heroProperNames, final int properNamesCount, final List<War3ID> heroAbilityList, final List<String> heroProperNames, final int properNamesCount,
final boolean canFlee) { final boolean canFlee, final int priority) {
this.name = name; this.name = name;
this.legacyName = legacyName; this.legacyName = legacyName;
this.typeId = typeId; this.typeId = typeId;
@ -144,6 +145,7 @@ public class CUnitType {
this.heroProperNames = heroProperNames; this.heroProperNames = heroProperNames;
this.properNamesCount = properNamesCount; this.properNamesCount = properNamesCount;
this.canFlee = canFlee; this.canFlee = canFlee;
this.priority = priority;
} }
public String getName() { public String getName() {
@ -353,4 +355,8 @@ public class CUnitType {
public boolean isCanFlee() { public boolean isCanFlee() {
return this.canFlee; return this.canFlee;
} }
public int getPriority() {
return this.priority;
}
} }

View File

@ -39,6 +39,8 @@ public abstract class CWidget implements AbilityTarget {
return this.life; return this.life;
} }
public abstract float getMaxLife();
protected void setX(final float x) { protected void setX(final float x) {
this.x = x; this.x = x;
} }
@ -70,4 +72,6 @@ public abstract class CWidget implements AbilityTarget {
final double dy = Math.abs(target.getY() - getY()); final double dy = Math.abs(target.getY() - getY());
return (dx * dx) + (dy * dy); return (dx * dx) + (dy * dy);
} }
public abstract boolean isInvulnerable();
} }

View File

@ -37,7 +37,7 @@ public class CWorldCollision {
collisionSize * 2); collisionSize * 2);
unit.setCollisionRectangle(bounds); unit.setCollisionRectangle(bounds);
} }
if (unit.getUnitType().isBuilding()) { if (unit.isBuilding()) {
// buildings are here so that we can include them when enumerating all units in // buildings are here so that we can include them when enumerating all units in
// a rect, but they don't really move dynamically, this is kind of pointless // a rect, but they don't really move dynamically, this is kind of pointless
this.buildingUnitCollision.add(unit, bounds); this.buildingUnitCollision.add(unit, bounds);
@ -73,7 +73,7 @@ public class CWorldCollision {
public void removeUnit(final CUnit unit) { public void removeUnit(final CUnit unit) {
final Rectangle bounds = unit.getCollisionRectangle(); final Rectangle bounds = unit.getCollisionRectangle();
if (bounds != null) { if (bounds != null) {
if (unit.getUnitType().isBuilding()) { if (unit.isBuilding()) {
this.buildingUnitCollision.remove(unit, bounds); this.buildingUnitCollision.remove(unit, bounds);
} }
else { else {
@ -154,7 +154,7 @@ public class CWorldCollision {
} }
public void translate(final CUnit unit, final float xShift, final float yShift) { public void translate(final CUnit unit, final float xShift, final float yShift) {
if (unit.getUnitType().isBuilding()) { if (unit.isBuilding()) {
throw new IllegalArgumentException("Cannot add building to the CWorldCollision"); throw new IllegalArgumentException("Cannot add building to the CWorldCollision");
} }
final MovementType movementType = unit.getUnitType().getMovementType(); final MovementType movementType = unit.getUnitType().getMovementType();

View File

@ -0,0 +1,77 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.combat;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.generic.AbstractGenericNoIconAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
public class CAbilityInvulnerable extends AbstractGenericNoIconAbility {
public CAbilityInvulnerable(final int handleId, final War3ID alias) {
super(handleId, alias);
}
@Override
public void onAdd(final CSimulation game, final CUnit unit) {
unit.setInvulnerable(true);
}
@Override
public void onRemove(final CSimulation game, final CUnit unit) {
unit.setInvulnerable(false);
}
@Override
public void onTick(final CSimulation game, final CUnit unit) {
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
return null;
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId,
final AbilityPointTarget point) {
return null;
}
@Override
public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) {
return null;
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final CWidget target,
final AbilityTargetCheckReceiver<CWidget> receiver) {
receiver.orderIdNotAccepted();
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityPointTarget target, final AbilityTargetCheckReceiver<AbilityPointTarget> receiver) {
receiver.orderIdNotAccepted();
}
@Override
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityTargetCheckReceiver<Void> receiver) {
receiver.orderIdNotAccepted();
}
@Override
protected void innerCheckCanUse(final CSimulation game, final CUnit unit, final int orderId,
final AbilityActivationReceiver receiver) {
receiver.notAnActiveAbility();
}
@Override
public void onCancelFromQueue(final CSimulation game, final CUnit unit, final int orderId) {
}
}

View File

@ -78,7 +78,8 @@ public class CAbilityHero extends AbstractCAbility {
} }
@Override @Override
public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId, AbilityTarget target) { public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId,
final AbilityTarget target) {
return true; return true;
} }

View File

@ -0,0 +1,30 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl;
import java.util.EnumSet;
import java.util.List;
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityTypeLevelData;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.CAbilityTypeDefinition;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.impl.CAbilityTypeInvulnerable;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
public class CAbilityTypeDefinitionInvulnerable extends AbstractCAbilityTypeDefinition<CAbilityTypeLevelData>
implements CAbilityTypeDefinition {
@Override
protected CAbilityTypeLevelData createLevelData(final MutableGameObject abilityEditorData, final int level) {
final String targetsAllowedAtLevelString = abilityEditorData.getFieldAsString(TARGETS_ALLOWED, level);
final EnumSet<CTargetType> targetsAllowedAtLevel = CTargetType.parseTargetTypeSet(targetsAllowedAtLevelString);
return new CAbilityTypeLevelData(targetsAllowedAtLevel);
}
@Override
protected CAbilityType<?> innerCreateAbilityType(final War3ID alias, final MutableGameObject abilityEditorData,
final List<CAbilityTypeLevelData> levelData) {
return new CAbilityTypeInvulnerable(alias, abilityEditorData.getCode(), levelData);
}
}

View File

@ -0,0 +1,24 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.impl;
import java.util.List;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.combat.CAbilityInvulnerable;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityTypeLevelData;
public class CAbilityTypeInvulnerable extends CAbilityType<CAbilityTypeLevelData> {
public CAbilityTypeInvulnerable(final War3ID alias, final War3ID code,
final List<CAbilityTypeLevelData> levelData) {
super(alias, code, levelData);
}
@Override
public CAbility createAbility(final int handleId) {
final CAbilityTypeLevelData levelData = getLevelData(0);
return new CAbilityInvulnerable(handleId, getAlias());
}
}

View File

@ -108,8 +108,11 @@ public class CUnitAttackMissileSplash extends CUnitAttackMissile {
final CUnitAttackListener attackListener) { final CUnitAttackListener attackListener) {
SplashDamageConsumer.INSTANCE.doDamage(cSimulation, source, target, this, x, y, damage, attackListener); SplashDamageConsumer.INSTANCE.doDamage(cSimulation, source, target, this, x, y, damage, attackListener);
if ((getWeaponType() != CWeaponType.ARTILLERY) && !SplashDamageConsumer.INSTANCE.hitTarget) { if ((getWeaponType() != CWeaponType.ARTILLERY) && !SplashDamageConsumer.INSTANCE.hitTarget) {
super.doDamage(cSimulation, source, target, damage * this.damageFactorSmall, x, y, bounceIndex, float originalTargetDamage = damage;
attackListener); if (Math.abs(this.damageFactorSmall) > 0.0001) {
originalTargetDamage *= this.damageFactorSmall;
}
super.doDamage(cSimulation, source, target, originalTargetDamage, x, y, bounceIndex, attackListener);
} }
} }

View File

@ -15,6 +15,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.def
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionGoldMine; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionGoldMine;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionHarvest; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionHarvest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionInventory; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionInventory;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionInvulnerable;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionReturnResources; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionReturnResources;
public class CAbilityData { public class CAbilityData {
@ -36,6 +37,7 @@ public class CAbilityData {
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Ahar"), new CAbilityTypeDefinitionHarvest()); this.codeToAbilityTypeDefinition.put(War3ID.fromString("Ahar"), new CAbilityTypeDefinitionHarvest());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("ANcl"), new CAbilityTypeDefinitionChannelTest()); this.codeToAbilityTypeDefinition.put(War3ID.fromString("ANcl"), new CAbilityTypeDefinitionChannelTest());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("AInv"), new CAbilityTypeDefinitionInventory()); this.codeToAbilityTypeDefinition.put(War3ID.fromString("AInv"), new CAbilityTypeDefinitionInventory());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Avul"), new CAbilityTypeDefinitionInvulnerable());
} }
public CAbilityType<?> getAbilityType(final War3ID alias) { public CAbilityType<?> getAbilityType(final War3ID alias) {

View File

@ -168,6 +168,7 @@ public class CUnitData {
private static final War3ID PRIMARY_ATTRIBUTE = War3ID.fromString("upra"); private static final War3ID PRIMARY_ATTRIBUTE = War3ID.fromString("upra");
private static final War3ID CAN_FLEE = War3ID.fromString("ufle"); private static final War3ID CAN_FLEE = War3ID.fromString("ufle");
private static final War3ID PRIORITY = War3ID.fromString("upri");
private final CGameplayConstants gameplayConstants; private final CGameplayConstants gameplayConstants;
private final MutableObjectData unitData; private final MutableObjectData unitData;
@ -275,6 +276,7 @@ public class CUnitData {
final String abilityList = unitType.getFieldAsString(ABILITIES_NORMAL, 0); final String abilityList = unitType.getFieldAsString(ABILITIES_NORMAL, 0);
final String heroAbilityListString = unitType.getFieldAsString(ABILITIES_HERO, 0); final String heroAbilityListString = unitType.getFieldAsString(ABILITIES_HERO, 0);
final int unitLevel = unitType.getFieldAsInteger(UNIT_LEVEL, 0); final int unitLevel = unitType.getFieldAsInteger(UNIT_LEVEL, 0);
final int priority = unitType.getFieldAsInteger(PRIORITY, 0);
final float moveHeight = unitType.getFieldAsFloat(MOVE_HEIGHT, 0); final float moveHeight = unitType.getFieldAsFloat(MOVE_HEIGHT, 0);
final String movetp = unitType.getFieldAsString(MOVE_TYPE, 0); final String movetp = unitType.getFieldAsString(MOVE_TYPE, 0);
@ -536,7 +538,7 @@ public class CUnitData {
goldCost, lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes, requiredPathingTypes, goldCost, lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes, requiredPathingTypes,
propWindow, turnRate, requirements, unitLevel, hero, strength, strPlus, agility, agiPlus, propWindow, turnRate, requirements, unitLevel, hero, strength, strPlus, agility, agiPlus,
intelligence, intPlus, primaryAttribute, heroAbilityList, heroProperNames, properNamesCount, intelligence, intPlus, primaryAttribute, heroAbilityList, heroProperNames, properNamesCount,
canFlee); canFlee, priority);
this.unitIdToUnitType.put(typeId, unitTypeInstance); this.unitIdToUnitType.put(typeId, unitTypeInstance);
this.jassLegacyNameToUnitId.put(legacyName, typeId); this.jassLegacyNameToUnitId.put(legacyName, typeId);
} }

View File

@ -429,7 +429,10 @@ public class CPathfindingProcessor {
} }
workIterations++; workIterations++;
this.totalIterations++; this.totalIterations++;
if (workIterations >= 7500) { if (this.totalIterations > 20000) {
break;
}
if (workIterations >= 500) {
// breaking jobs loop will implicitly exit without calling pathFound() below // breaking jobs loop will implicitly exit without calling pathFound() below
break JobsLoop; break JobsLoop;
} }

View File

@ -5,10 +5,13 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
@ -23,9 +26,12 @@ import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter; import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.PixmapTextureData; import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.BoundingBox;
import com.badlogic.gdx.utils.TimeUtils; import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.viewport.ExtendViewport; import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.etheller.warsmash.datasources.DataSource; import com.etheller.warsmash.datasources.DataSource;
@ -53,6 +59,7 @@ 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;
import com.etheller.warsmash.util.WarsmashConstants; import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.Bounds;
import com.etheller.warsmash.viewer5.Scene; import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.ViewerTextureRenderable; import com.etheller.warsmash.viewer5.ViewerTextureRenderable;
import com.etheller.warsmash.viewer5.handlers.mdx.Attachment; import com.etheller.warsmash.viewer5.handlers.mdx.Attachment;
@ -91,6 +98,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CPlayerStateListene
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit.QueueItemType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit.QueueItemType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitEnumFunction;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitStateListener; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitStateListener;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
@ -245,6 +253,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private long lastErrorMessageExpireTime; private long lastErrorMessageExpireTime;
private long lastErrorMessageFadeTime; private long lastErrorMessageFadeTime;
private MenuCursorState cursorState;
private CAbilityView activeCommand; private CAbilityView activeCommand;
private int activeCommandOrderId; private int activeCommandOrderId;
private RenderUnit activeCommandUnit; private RenderUnit activeCommandUnit;
@ -278,6 +287,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private MdxModel waypointModel; private MdxModel waypointModel;
private final List<MdxComplexInstance> waypointModelInstances = new ArrayList<>(); private final List<MdxComplexInstance> waypointModelInstances = new ArrayList<>();
private List<RenderUnit> selectedUnits; private List<RenderUnit> selectedUnits;
private Set<RenderUnit> dragSelectPreviewUnits = new HashSet<>();
private Set<RenderUnit> dragSelectPreviewUnitsUpcoming = new HashSet<>();
private BitmapFont textTagFont; private BitmapFont textTagFont;
private SetPoint uberTipNoResourcesSetPoint; private SetPoint uberTipNoResourcesSetPoint;
private SetPoint uberTipWithResourcesSetPoint; private SetPoint uberTipWithResourcesSetPoint;
@ -296,6 +307,15 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private SimpleButtonFrame chatButton; private SimpleButtonFrame chatButton;
private final Runnable exitGameRunnable; private final Runnable exitGameRunnable;
private SimpleFrame smashEscMenu; private SimpleFrame smashEscMenu;
private RenderWidget mouseOverUnit;
private final Vector3 lastMouseDragStart = new Vector3();
private final Vector3 lastMouseClickLocation = new Vector3();
private final List<SimpleStatusBarFrame> hpBarFrames = new ArrayList<>();
private int hpBarFrameIndex = 0;
private boolean allowDrag;
private int currentlyDraggingPointer;
private final ShapeRenderer shapeRenderer = new ShapeRenderer();
public MeleeUI(final DataSource dataSource, final ExtendViewport uiViewport, final Scene uiScene, public MeleeUI(final DataSource dataSource, final ExtendViewport uiViewport, final Scene uiScene,
final Scene portraitScene, final CameraPreset[] cameraPresets, final CameraRates cameraRates, final Scene portraitScene, final CameraPreset[] cameraPresets, final CameraRates cameraRates,
@ -939,13 +959,13 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
@Override @Override
public void onClick(final int abilityHandleId, final int orderId, final boolean rightClick) { public void onClick(final int abilityHandleId, final int orderId, final boolean rightClick) {
// TODO not O(N)
if (this.selectedUnit == null) { if (this.selectedUnit == null) {
return; return;
} }
if (orderId == 0) { if (orderId == 0) {
return; return;
} }
// TODO not O(N)
CAbilityView abilityToUse = null; CAbilityView abilityToUse = null;
for (final CAbility ability : this.selectedUnit.getSimulationUnit().getAbilities()) { for (final CAbility ability : this.selectedUnit.getSimulationUnit().getAbilities()) {
if (ability.getHandleId() == abilityHandleId) { if (ability.getHandleId() == abilityHandleId) {
@ -1050,6 +1070,53 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
if (Gdx.input.isCursorCatched()) { if (Gdx.input.isCursorCatched()) {
Gdx.input.setCursorPosition(mouseX, mouseY); Gdx.input.setCursorPosition(mouseX, mouseY);
} }
this.hpBarFrameIndex = 0;
if (this.currentlyDraggingPointer == -1) {
if ((this.mouseOverUnit != null) && !this.mouseOverUnit.getSimulationWidget().isInvulnerable()) {
final SimpleStatusBarFrame simpleStatusBarFrame = getHpBar();
positionHealthBar(simpleStatusBarFrame, this.mouseOverUnit, 1.0f);
}
}
else if (this.currentlyDraggingPointer == Input.Buttons.LEFT) {
final float minDragX = Math.min(this.lastMouseClickLocation.x, this.lastMouseDragStart.x);
final float minDragY = Math.min(this.lastMouseClickLocation.y, this.lastMouseDragStart.y);
final float maxDragX = Math.max(this.lastMouseClickLocation.x, this.lastMouseDragStart.x);
final float maxDragY = Math.max(this.lastMouseClickLocation.y, this.lastMouseDragStart.y);
this.tempRect.set(minDragX, minDragY, maxDragX - minDragX, maxDragY - minDragY);
this.dragSelectPreviewUnitsUpcoming.clear();
this.war3MapViewer.simulation.getWorldCollision().enumUnitsInRect(this.tempRect, new CUnitEnumFunction() {
@Override
public boolean call(final CUnit unit) {
final RenderUnit renderUnit = MeleeUI.this.war3MapViewer.getRenderPeer(unit);
if (!unit.isInvulnerable() && !unit.isDead() && renderUnit.isSelectable()
&& MeleeUI.this.dragSelectPreviewUnitsUpcoming.add(renderUnit)) {
final SimpleStatusBarFrame simpleStatusBarFrame = getHpBar();
positionHealthBar(simpleStatusBarFrame, renderUnit, 1.0f);
if (!MeleeUI.this.dragSelectPreviewUnits.contains(renderUnit)) {
MeleeUI.this.war3MapViewer.showUnitMouseOverHighlight(renderUnit);
}
}
return false;
}
});
for (final RenderUnit unit : this.dragSelectPreviewUnits) {
if (!this.dragSelectPreviewUnitsUpcoming.contains(unit)) {
this.war3MapViewer.clearUnitMouseOverHighlight(unit);
}
}
final Set<RenderUnit> temp = this.dragSelectPreviewUnits;
this.dragSelectPreviewUnits = this.dragSelectPreviewUnitsUpcoming;
this.dragSelectPreviewUnitsUpcoming = temp;
}
if ((this.selectedUnits != null) && false) {
for (final RenderUnit unit : this.selectedUnits) {
final SimpleStatusBarFrame simpleStatusBarFrame = getHpBar();
positionHealthBar(simpleStatusBarFrame, unit, 1.0f);
}
}
for (int i = this.hpBarFrameIndex; i < this.hpBarFrames.size(); i++) {
this.hpBarFrames.get(i).setVisible(false);
}
screenCoordsVector.set(mouseX, mouseY); screenCoordsVector.set(mouseX, mouseY);
this.uiViewport.unproject(screenCoordsVector); this.uiViewport.unproject(screenCoordsVector);
@ -1058,9 +1125,10 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
if (this.activeCommand != null) { if (this.activeCommand != null) {
if (this.draggingItem != null) { if (this.draggingItem != null) {
this.cursorFrame.setSequence("HoldItem"); setCursorState(MenuCursorState.HOLD_ITEM);
} }
else { else {
setCursorState(MenuCursorState.TARGET_CURSOR);
this.activeCommand.visit(this.cursorTargetSetupVisitor.reset(baseMouseX, baseMouseY)); this.activeCommand.visit(this.cursorTargetSetupVisitor.reset(baseMouseX, baseMouseY));
} }
} }
@ -1081,34 +1149,34 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
if (down) { if (down) {
if (left) { if (left) {
this.cursorFrame.setSequence("Scroll Down Left"); setCursorState(MenuCursorState.SCROLL_DOWN_LEFT);
} }
else if (right) { else if (right) {
this.cursorFrame.setSequence("Scroll Down Right"); setCursorState(MenuCursorState.SCROLL_DOWN_RIGHT);
} }
else { else {
this.cursorFrame.setSequence("Scroll Down"); setCursorState(MenuCursorState.SCROLL_DOWN);
} }
} }
else if (up) { else if (up) {
if (left) { if (left) {
this.cursorFrame.setSequence("Scroll Up Left"); setCursorState(MenuCursorState.SCROLL_UP_LEFT);
} }
else if (right) { else if (right) {
this.cursorFrame.setSequence("Scroll Up Right"); setCursorState(MenuCursorState.SCROLL_UP_RIGHT);
} }
else { else {
this.cursorFrame.setSequence("Scroll Up"); setCursorState(MenuCursorState.SCROLL_UP);
} }
} }
else if (left) { else if (left) {
this.cursorFrame.setSequence("Scroll Left"); setCursorState(MenuCursorState.SCROLL_LEFT);
} }
else if (right) { else if (right) {
this.cursorFrame.setSequence("Scroll Right"); setCursorState(MenuCursorState.SCROLL_RIGHT);
} }
else { else {
this.cursorFrame.setSequence("Normal"); setCursorState(MenuCursorState.NORMAL);
} }
} }
if (this.selectedUnit != null) { if (this.selectedUnit != null) {
@ -1142,6 +1210,59 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
} }
private void positionHealthBar(final SimpleStatusBarFrame simpleStatusBarFrame, final RenderWidget unit,
final float alpha) {
simpleStatusBarFrame.setVisible(true);
clickLocationTemp.x = unit.getX();
clickLocationTemp.y = unit.getY();
clickLocationTemp.z = unit.getZ();
final Bounds unitBounds = unit.getInstance().getBounds();
if (unitBounds != null) {
final BoundingBox unitBoundsBox = unitBounds.getBoundingBox();
if (unitBoundsBox != null) {
clickLocationTemp.z += unitBoundsBox.max.z;
}
}
this.war3MapViewer.worldScene.camera.worldToScreen(screenCoordsVector, clickLocationTemp);
simpleStatusBarFrame.getBarFrame().setTexture("SimpleHpBarConsole", this.rootFrame);
simpleStatusBarFrame.getBorderFrame().setTexture("Textures\\Black32.blp", this.rootFrame);
simpleStatusBarFrame.getBorderFrame().setColor(0f, 0f, 0f, alpha);
final float lifeRatioRemaining = unit.getSimulationWidget().getLife() / unit.getSimulationWidget().getMaxLife();
simpleStatusBarFrame.getBarFrame().setColor(Math.min(1.0f, 2.0f - (lifeRatioRemaining * 2)),
Math.min(1.0f, lifeRatioRemaining * 2), 0, alpha);
final Vector2 unprojected = this.uiViewport.unproject(screenCoordsVector);
simpleStatusBarFrame.setWidth(unit.getSelectionScale() * 1.5f);
simpleStatusBarFrame.setHeight(16);
simpleStatusBarFrame.addSetPoint(
new SetPoint(FramePoint.CENTER, this.rootFrame, FramePoint.BOTTOMLEFT, unprojected.x, unprojected.y));
simpleStatusBarFrame.setValue(lifeRatioRemaining);
simpleStatusBarFrame.positionBounds(this.rootFrame, this.uiViewport);
}
private SimpleStatusBarFrame getHpBar() {
final SimpleStatusBarFrame simpleStatusBarFrame;
if (this.hpBarFrameIndex >= this.hpBarFrames.size()) {
simpleStatusBarFrame = new SimpleStatusBarFrame("SmashHpBar" + this.hpBarFrameIndex, this.rootFrame, true,
true, 3.0f);
this.rootFrame.add(simpleStatusBarFrame);
this.hpBarFrames.add(simpleStatusBarFrame);
}
else {
simpleStatusBarFrame = this.hpBarFrames.get(this.hpBarFrameIndex);
}
this.hpBarFrameIndex++;
return simpleStatusBarFrame;
}
private void setCursorState(final MenuCursorState state) {
if (state != this.cursorState) {
if (state.getAnimationName() != null) {
this.cursorFrame.setSequence(state.getAnimationName());
}
}
this.cursorState = state;
}
public void render(final SpriteBatch batch, final GlyphLayout glyphLayout) { public void render(final SpriteBatch batch, final GlyphLayout glyphLayout) {
final BitmapFont font = this.rootFrame.getFont(); final BitmapFont font = this.rootFrame.getFont();
font.setColor(Color.YELLOW); font.setColor(Color.YELLOW);
@ -1172,6 +1293,26 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
(unprojected.y - (glyphLayout.height / 2)) + textTag.getScreenCoordsZHeight()); (unprojected.y - (glyphLayout.height / 2)) + textTag.getScreenCoordsZHeight());
} }
} }
if (this.currentlyDraggingPointer == Input.Buttons.LEFT) {
batch.end();
this.shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
this.shapeRenderer.setColor(Color.GREEN);
Gdx.gl.glLineWidth(2);
this.shapeRenderer.begin(ShapeType.Line);
this.cameraManager.camera.worldToScreen(screenCoordsVector, this.lastMouseDragStart);
final Vector2 unprojected = this.uiViewport.unproject(screenCoordsVector);
final float x = unprojected.x;
final float y = unprojected.y;
this.cameraManager.camera.worldToScreen(screenCoordsVector, this.lastMouseClickLocation);
final Vector2 unprojectedEnd = this.uiViewport.unproject(screenCoordsVector);
final float minX = Math.min(x, unprojectedEnd.x);
final float minY = Math.min(y, unprojectedEnd.y);
this.shapeRenderer.rect(minX, minY, Math.max(x, unprojectedEnd.x) - minX,
Math.max(y, unprojectedEnd.y) - minY);
this.shapeRenderer.end();
Gdx.gl.glLineWidth(1);
batch.begin();
}
} }
public void portraitTalk() { public void portraitTalk() {
@ -1783,8 +1924,11 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private void reloadSelectedUnitUI(final RenderUnit unit) { private void reloadSelectedUnitUI(final RenderUnit unit) {
final CUnit simulationUnit = unit.getSimulationUnit(); final CUnit simulationUnit = unit.getSimulationUnit();
this.rootFrame.setText(this.unitLifeText, final float lifeRatioRemaining = simulationUnit.getLife() / simulationUnit.getMaxLife();
FastNumberFormat.formatWholeNumber(simulationUnit.getLife()) + " / " + simulationUnit.getMaximumLife()); this.rootFrame.setText(this.unitLifeText, FastNumberFormat.formatWholeNumber(simulationUnit.getLife()) + " / "
+ FastNumberFormat.formatWholeNumber(simulationUnit.getMaxLife()));
this.unitLifeText.setColor(new Color(Math.min(1.0f, 2.0f - (lifeRatioRemaining * 2)),
Math.min(1.0f, lifeRatioRemaining * 2), 0, 1.0f));
final int maximumMana = simulationUnit.getMaximumMana(); final int maximumMana = simulationUnit.getMaximumMana();
if (maximumMana > 0) { if (maximumMana > 0) {
this.rootFrame.setText(this.unitManaText, this.rootFrame.setText(this.unitManaText,
@ -1940,8 +2084,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.rootFrame.setText(this.simpleNameValue, unitTypeName); this.rootFrame.setText(this.simpleNameValue, unitTypeName);
String classText = null; String classText = null;
for (final CUnitClassification classification : simulationUnit.getClassifications()) { for (final CUnitClassification classification : simulationUnit.getClassifications()) {
if ((classification == CUnitClassification.MECHANICAL) if ((classification == CUnitClassification.MECHANICAL) && simulationUnit.isBuilding()) {
&& simulationUnit.getUnitType().isBuilding()) {
// buildings dont display MECHANICAL // buildings dont display MECHANICAL
continue; continue;
} }
@ -2041,14 +2184,20 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
localArmorIconBackdrop.setTexture(defenseTexture); localArmorIconBackdrop.setTexture(defenseTexture);
String defenseDisplayString = Integer.toString(simulationUnit.getCurrentDefenseDisplay()); String defenseDisplayString;
final int temporaryDefenseBonus = simulationUnit.getTemporaryDefenseBonus(); if (simulationUnit.isInvulnerable()) {
if (temporaryDefenseBonus != 0) { defenseDisplayString = this.rootFrame.getTemplates().getDecoratedString("INVULNERABLE");
if (temporaryDefenseBonus > 0) { }
defenseDisplayString += "|cFF00FF00 (+" + temporaryDefenseBonus + ")"; else {
} defenseDisplayString = Integer.toString(simulationUnit.getCurrentDefenseDisplay());
else { final int temporaryDefenseBonus = simulationUnit.getTemporaryDefenseBonus();
defenseDisplayString += "|cFFFF0000 (+" + temporaryDefenseBonus + ")"; if (temporaryDefenseBonus != 0) {
if (temporaryDefenseBonus > 0) {
defenseDisplayString += "|cFF00FF00 (+" + temporaryDefenseBonus + ")";
}
else {
defenseDisplayString += "|cFFFF0000 (+" + temporaryDefenseBonus + ")";
}
} }
} }
this.rootFrame.setText(localArmorInfoPanelIconValue, defenseDisplayString); this.rootFrame.setText(localArmorInfoPanelIconValue, defenseDisplayString);
@ -2165,9 +2314,13 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
selectUnit(null); selectUnit(null);
} }
else { else {
final float lifeRatioRemaining = this.selectedUnit.getSimulationUnit().getLife()
/ this.selectedUnit.getSimulationUnit().getMaxLife();
this.rootFrame.setText(this.unitLifeText, this.rootFrame.setText(this.unitLifeText,
FastNumberFormat.formatWholeNumber(this.selectedUnit.getSimulationUnit().getLife()) + " / " FastNumberFormat.formatWholeNumber(this.selectedUnit.getSimulationUnit().getLife()) + " / "
+ this.selectedUnit.getSimulationUnit().getMaximumLife()); + FastNumberFormat.formatWholeNumber(this.selectedUnit.getSimulationUnit().getMaxLife()));
this.unitLifeText.setColor(new Color(Math.min(1.0f, 2.0f - (lifeRatioRemaining * 2)),
Math.min(1.0f, lifeRatioRemaining * 2), 0, 1.0f));
} }
} }
@ -2277,6 +2430,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
public boolean touchDown(final int screenX, final int screenY, final float worldScreenY, final int button) { public boolean touchDown(final int screenX, final int screenY, final float worldScreenY, final int button) {
this.allowDrag = false;
screenCoordsVector.set(screenX, screenY); screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector); this.uiViewport.unproject(screenCoordsVector);
if (this.meleeUIMinimap.containsMouse(screenCoordsVector.x, screenCoordsVector.y)) { if (this.meleeUIMinimap.containsMouse(screenCoordsVector.x, screenCoordsVector.y)) {
@ -2300,9 +2454,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
clearAndRepopulateCommandCard(); clearAndRepopulateCommandCard();
} }
else { else {
final boolean shiftDown = isShiftDown();
final RenderWidget rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY, final RenderWidget rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY,
this.activeCommandUnitTargetFilter); this.activeCommandUnitTargetFilter);
final boolean shiftDown = isShiftDown();
if (rayPickUnit != null) { if (rayPickUnit != null) {
this.unitOrderListener.issueTargetOrder( this.unitOrderListener.issueTargetOrder(
this.activeCommandUnit.getSimulationUnit().getHandleId(), this.activeCommandUnit.getSimulationUnit().getHandleId(),
@ -2442,11 +2596,14 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
} }
else { else {
final List<RenderWidget> selectedUnits = this.war3MapViewer.selectUnit(screenX, worldScreenY, if (this.mouseOverUnit != null) {
false); final List<RenderWidget> unitList = Arrays.asList(this.mouseOverUnit);
if (!selectedUnits.isEmpty()) { this.war3MapViewer.doSelectUnit(unitList);
selectWidgets(selectedUnits); selectWidgets(unitList);
} }
this.war3MapViewer.getClickLocation(this.lastMouseClickLocation, screenX, (int) worldScreenY);
this.lastMouseDragStart.set(this.lastMouseClickLocation);
this.allowDrag = true;
} }
} }
} }
@ -2564,6 +2721,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
public boolean touchUp(final int screenX, final int screenY, final float worldScreenY, final int button) { public boolean touchUp(final int screenX, final int screenY, final float worldScreenY, final int button) {
this.currentlyDraggingPointer = -1;
screenCoordsVector.set(screenX, screenY); screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector); this.uiViewport.unproject(screenCoordsVector);
final UIFrame clickedUIFrame = this.rootFrame.touchUp(screenCoordsVector.x, screenCoordsVector.y, button); final UIFrame clickedUIFrame = this.rootFrame.touchUp(screenCoordsVector.x, screenCoordsVector.y, button);
@ -2581,6 +2739,34 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
this.mouseDownUIFrame.mouseUp(this.rootFrame, this.uiViewport); this.mouseDownUIFrame.mouseUp(this.rootFrame, this.uiViewport);
} }
else {
if (!this.dragSelectPreviewUnits.isEmpty()) {
final List<RenderWidget> selectedWidgets = new ArrayList<>();
boolean foundGoal = false;
for (final RenderUnit unit : this.dragSelectPreviewUnits) {
if ((unit.getSimulationUnit().getPlayerIndex() == this.war3MapViewer.getLocalPlayerIndex())
&& !unit.getSimulationUnit().isBuilding()) {
foundGoal = true;
selectedWidgets.add(unit);
}
}
if (!foundGoal) {
selectedWidgets.addAll(this.dragSelectPreviewUnits);
}
Collections.sort(selectedWidgets, new Comparator<RenderWidget>() {
@Override
public int compare(final RenderWidget widget1, final RenderWidget widget2) {
return ((RenderUnit) widget1).getSimulationUnit().getUnitType().getPriority()
- ((RenderUnit) widget2).getSimulationUnit().getUnitType().getPriority();
}
});
this.war3MapViewer.clearUnitMouseOverHighlight();
this.war3MapViewer.doSelectUnit(selectedWidgets);
selectWidgets(selectedWidgets);
this.dragSelectPreviewUnits.clear();
}
}
this.mouseDownUIFrame = null; this.mouseDownUIFrame = null;
return false; return false;
} }
@ -2599,6 +2785,25 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.cameraManager.target.x = worldPoint.x; this.cameraManager.target.x = worldPoint.x;
this.cameraManager.target.y = worldPoint.y; this.cameraManager.target.y = worldPoint.y;
} }
else {
if (this.allowDrag) {
if (null != this.mouseOverUnit) {
this.war3MapViewer.clearUnitMouseOverHighlight();
this.dragSelectPreviewUnits.clear();
this.mouseOverUnit = null;
}
this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY);
this.currentlyDraggingPointer = pointer;
if (pointer == Input.Buttons.MIDDLE) {
this.cameraManager.target.add(this.lastMouseClickLocation.sub(clickLocationTemp).scl(-1));
}
else if (pointer == Input.Buttons.LEFT) {
// update mouseover
}
this.lastMouseClickLocation.set(clickLocationTemp);
}
}
return false; return false;
} }
@ -2625,6 +2830,24 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.tooltipFrame.setVisible(false); this.tooltipFrame.setVisible(false);
} }
} }
if (mousedUIFrame == null) {
final RenderWidget newMouseOverUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY,
new CWidgetFilterFunction() {
@Override
public boolean call(final CWidget unit) {
final RenderWidget renderPeer = MeleeUI.this.war3MapViewer.getRenderPeer(unit);
return !unit.isDead() && renderPeer.isSelectable();
}
});
if (newMouseOverUnit != this.mouseOverUnit) {
this.war3MapViewer.clearUnitMouseOverHighlight();
this.dragSelectPreviewUnits.clear();
if (newMouseOverUnit != null) {
this.war3MapViewer.showUnitMouseOverHighlight(newMouseOverUnit);
}
this.mouseOverUnit = newMouseOverUnit;
}
}
return false; return false;
} }

View File

@ -0,0 +1,24 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui;
public enum MenuCursorState {
NORMAL("Normal"),
SCROLL_LEFT("Scroll Left"),
SCROLL_RIGHT("Scroll Right"),
SCROLL_DOWN("Scroll Down"),
SCROLL_UP("Scroll Up"),
SCROLL_DOWN_LEFT("Scroll Down Left"),
SCROLL_DOWN_RIGHT("Scroll Down Right"),
SCROLL_UP_LEFT("Scroll Up Left"),
SCROLL_UP_RIGHT("Scroll Up Right"),
TARGET_CURSOR(null), // handled specially
HOLD_ITEM("HoldItem");
private String animationName;
private MenuCursorState(final String animationName) {
this.animationName = animationName;
}
public String getAnimationName() {
return this.animationName;
}
}