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 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 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);
}
@ -329,7 +329,7 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
|| ((parentDefinitionIfAvailable != null)
&& parentDefinitionIfAvailable.has("DecorateFileNames"));
final SimpleStatusBarFrame simpleStatusBarFrame = new SimpleStatusBarFrame(frameDefinition.getName(),
parent, decorateFileNames);
parent, decorateFileNames, false, 0.0f);
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
simpleStatusBarFrame.add(inflate(childDefinition, simpleStatusBarFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames")));

View File

@ -7,19 +7,28 @@ public class SimpleStatusBarFrame extends AbstractUIFrame {
private final boolean decorateFileNames;
private final TextureFrame barFrame;
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);
this.decorateFileNames = decorateFileNames;
this.barInset = barInset;
this.barFrame = new TextureFrame(name + "Bar", this, decorateFileNames, new Vector4Definition(0, 1, 0, 1));
this.borderFrame = new TextureFrame(name + "Border", this, decorateFileNames,
new Vector4Definition(0, 1, 0, 1));
this.borderFrame.setSetAllPoints(true);
this.barFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this, FramePoint.TOPLEFT, 0, 0));
this.barFrame.addSetPoint(new SetPoint(FramePoint.BOTTOMLEFT, this, FramePoint.BOTTOMLEFT, 0, 0));
this.barFrame.setSetAllPoints(true);
add(this.barFrame);
add(this.borderFrame);
this.barFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this, FramePoint.TOPLEFT, barInset, -barInset));
this.barFrame.addSetPoint(new SetPoint(FramePoint.BOTTOMLEFT, this, FramePoint.BOTTOMLEFT, barInset, barInset));
this.barFrame.setSetAllPoints(true, barInset);
if (borderBelow) {
add(this.borderFrame);
add(this.barFrame);
}
else {
add(this.barFrame);
add(this.borderFrame);
}
}
public boolean isDecorateFileNames() {
@ -28,7 +37,7 @@ public class SimpleStatusBarFrame extends AbstractUIFrame {
public void setValue(final float value) {
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() {

View File

@ -46,6 +46,17 @@ public class TextureFrame extends AbstractRenderableFrame {
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) {
if (this.decorateFileNames) {
file = gameUI.trySkinField(file);

View File

@ -9,7 +9,6 @@ public class WarsmashConstants {
public static int GAME_VERSION = 1;
public static final int REPLACEABLE_TEXTURE_LIMIT = 64;
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 float BUILDING_CONSTRUCT_START_LIFE = 0.1f;
public static final int BUILD_QUEUE_SIZE = 7;

View File

@ -1,5 +1,8 @@
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 static final String boneTexture = ""//
+ " 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,
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" + //
" for(float lightIndex = 0.5; lightIndex < " + lightCount + "; lightIndex += 1.0) {\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"
+ //
" }\r\n" + //
" }\r\n";// + //
// " vec4 sRGB = vec4(lightFactor, 1.0);" + //
// " bvec4 cutoff = lessThan(sRGB, vec4(0.04045));" + //
// " vec4 higher = pow((sRGB + vec4(0.055))/vec4(1.055), vec4(2.4));" + //
// " vec4 lower = sRGB/vec4(12.92);" + //
// "" + //
// " lightFactor = (higher * (vec4(1.0) - vec4(cutoff)) + lower * vec4(cutoff)).xyz;";
" }\r\n" + //
(MdxHandler.CURRENT_SHADER_TYPE == ShaderEnvironmentType.MENU
? " vec4 sRGB = vec4(lightFactor, 1.0);" + //
" bvec4 cutoff = lessThan(sRGB, vec4(0.04045));" + //
" vec4 higher = pow((sRGB + vec4(0.055))/vec4(1.055), vec4(2.4));" + //
" vec4 lower = sRGB/vec4(12.92);" + //
"" + //
" 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 (DynamicShadowManager.IS_SHADOW_MAPPING) {
shader = MdxHandler.Shaders.extendedShadowMap;
shader = handler.shaders.extendedShadowMap;
}
else {
shader = MdxHandler.Shaders.extended;
shader = handler.shaders.extended;
}
}
else {
if (DynamicShadowManager.IS_SHADOW_MAPPING) {
shader = MdxHandler.Shaders.complexShadowMap;
shader = handler.shaders.complexShadowMap;
}
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) {
intersectHeap.set(this.center);
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.sub(intersectHeap);
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 GL20 gl = viewer.gl;
final ANGLEInstancedArrays instancedArrays = viewer.webGL.instancedArrays;
final ShaderProgram shader = MdxHandler.Shaders.particles;
final ShaderProgram shader = ((MdxModel) model).handler.shaders.particles;
gl.glDepthMask(false);
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.gl.ANGLEInstancedArrays;
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.w3x.W3xSceneLightManager;
//The total storage that emitted objects can use.
//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_rows", emitterObject.rows);
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[1]", intervals[1], 0, 3);
@ -210,9 +221,7 @@ public class GeometryEmitterFuncs {
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) {

View File

@ -36,6 +36,7 @@ public class MdxComplexInstance extends ModelInstance {
private static final float[] colorHeap = new float[3];
private static final float[] alphaHeap = new float[1];
private static final long[] textureIdHeap = new long[1];
private static final Vector3 intersectionHeap = new Vector3();
public List<LightInstance> lights = 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) {
final MdxModel mdxModel = (MdxModel) this.model;
final List<CollisionShape> collisionShapes = mdxModel.collisionShapes;
boolean intersected = false;
ray.getEndPoint(intersection, 99999);
for (final CollisionShape collisionShape : collisionShapes) {
final MdxNode mdxNode = this.nodes[collisionShape.index];
if (collisionShape.checkIntersect(ray, mdxNode, intersection)) {
return true;
if (collisionShape.checkIntersect(ray, mdxNode, intersectionHeap)) {
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) {
final MdxModel mdxModel = (MdxModel) this.model;
boolean intersected = false;
ray.getEndPoint(intersection, 99999);
for (final Geoset geoset : mdxModel.geosets) {
if (!geoset.unselectable) {
geoset.getAlpha(alphaHeap, this.sequence, this.frame, this.counter);
if (alphaHeap[0] > 0) {
final MdlxGeoset mdlxGeoset = geoset.mdlxGeoset;
if (CollisionShape.intersectRayTriangles(ray, this, mdlxGeoset.getVertices(), mdlxGeoset.getFaces(),
3, intersection)) {
return true;
3, intersectionHeap)) {
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;
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() {
this.extensions = new ArrayList<>();
@ -26,14 +34,14 @@ public class MdxHandler extends ModelHandler {
viewer.addHandler(new DdsHandler());
viewer.addHandler(new TgaHandler());
Shaders.complex = viewer.webGL.createShaderProgram(MdxShaders.vsComplex, MdxShaders.fsComplex);
Shaders.extended = viewer.webGL.createShaderProgram("#define EXTENDED_BONES\r\n" + MdxShaders.vsComplex,
this.shaders.complex = viewer.webGL.createShaderProgram(MdxShaders.vsComplex(), MdxShaders.fsComplex);
this.shaders.extended = viewer.webGL.createShaderProgram("#define EXTENDED_BONES\r\n" + MdxShaders.vsComplex(),
MdxShaders.fsComplex);
Shaders.complexShadowMap = viewer.webGL.createShaderProgram(MdxShaders.vsComplex,
this.shaders.complexShadowMap = viewer.webGL.createShaderProgram(MdxShaders.vsComplex(),
MdxShaders.fsComplexShadowMap);
Shaders.extendedShadowMap = viewer.webGL.createShaderProgram(
"#define EXTENDED_BONES\r\n" + MdxShaders.vsComplex, MdxShaders.fsComplexShadowMap);
Shaders.particles = viewer.webGL.createShaderProgram(MdxShaders.vsParticles, MdxShaders.fsParticles);
this.shaders.extendedShadowMap = viewer.webGL.createShaderProgram(
"#define EXTENDED_BONES\r\n" + MdxShaders.vsComplex(), MdxShaders.fsComplexShadowMap);
this.shaders.particles = viewer.webGL.createShaderProgram(MdxShaders.vsParticles(), MdxShaders.fsParticles);
// Shaders.simple = viewer.webGL.createShaderProgram(MdxShaders.vsSimple,
// MdxShaders.fsSimple);
// 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
// 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() */;
}
@ -56,12 +65,12 @@ public class MdxHandler extends ModelHandler {
}
public static ShaderProgram complex;
public static ShaderProgram complexShadowMap;
public static ShaderProgram extended;
public static ShaderProgram extendedShadowMap;
public static ShaderProgram simple;
public static ShaderProgram particles;
public static ShaderProgram hd;
public ShaderProgram complex;
public ShaderProgram complexShadowMap;
public ShaderProgram extended;
public ShaderProgram extendedShadowMap;
public ShaderProgram simple;
public ShaderProgram particles;
public ShaderProgram hd;
}
}

View File

@ -73,7 +73,7 @@ public class MdxRenderBatch extends RenderBatch {
final GL20 gl = viewer.gl;
final WebGL webGL = viewer.webGL;
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 m1 = shader.getAttributeLocation("a_m1");
final int m2 = shader.getAttributeLocation("a_m2");

View File

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

View File

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

View File

@ -11,10 +11,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.function.Consumer;
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.MdxComplexInstance;
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.MdxNode;
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<RenderWidget> selected = new ArrayList<>();
private final Set<String> mouseHighlightSplatModelKeys = new HashSet<>();
private final List<RenderWidget> mouseHighlightWidgets = new ArrayList<>();
private DataTable unitAckSoundsTable;
private DataTable unitCombatSoundsTable;
public DataTable miscData;
@ -234,6 +239,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
public War3MapViewer(final DataSource dataSource, final CanvasProvider canvas, final War3MapConfig mapConfig) {
super(dataSource, canvas);
MdxHandler.CURRENT_SHADER_TYPE = ShaderEnvironmentType.GAME;
this.gameDataSource = dataSource;
final WebGL webGL = this.webGL;
@ -369,6 +375,9 @@ public class War3MapViewer extends AbstractMdxModelViewer {
}
this.selectionCircleScaleFactor = selectionCircleData.getFieldFloatValue("ScaleFactor");
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);
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,
final LoadGenericCallback callback) {
if (this.mapMpq == null) {
@ -1583,22 +1599,22 @@ public class War3MapViewer extends AbstractMdxModelViewer {
locations.locations, this.terrain.centerOffset, locations.unitMapping, true, false, true);
switch (allyKey) {
case "e:":
model.color[0] = 1;
model.color[1] = 0;
model.color[2] = 0;
model.color[3] = 1;
model.color[0] = this.selectionCircleColorEnemy.r;
model.color[1] = this.selectionCircleColorEnemy.g;
model.color[2] = this.selectionCircleColorEnemy.b;
model.color[3] = this.selectionCircleColorEnemy.a;
break;
case "f:":
model.color[0] = 0;
model.color[1] = 1;
model.color[2] = 0;
model.color[3] = 1;
model.color[0] = this.selectionCircleColorFriend.r;
model.color[1] = this.selectionCircleColorFriend.g;
model.color[2] = this.selectionCircleColorFriend.b;
model.color[3] = this.selectionCircleColorFriend.a;
break;
default:
model.color[0] = 1;
model.color[1] = 1;
model.color[2] = 0;
model.color[3] = 1;
model.color[0] = this.selectionCircleColorNeutral.r;
model.color[1] = this.selectionCircleColorNeutral.g;
model.color[2] = this.selectionCircleColorNeutral.b;
model.color[3] = this.selectionCircleColorNeutral.a;
break;
}
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) {
final float[] ray = rayHeap;
mousePosHeap.set(screenX, screenY);
@ -1678,19 +1801,22 @@ public class War3MapViewer extends AbstractMdxModelViewer {
final MdxComplexInstance instance = unit.getInstance();
if (instance.shown() && instance.isVisible(this.worldScene.camera)
&& instance.intersectRayWithCollisionSimple(gdxRayHeap, intersectionHeap)) {
if (filter.call(unit.getSimulationWidget()) && (intersectionHeap.z > this.terrain
.getGroundHeight(intersectionHeap.x, intersectionHeap.y))) {
if (((entity == null) && !unit.isIntersectedOnMeshAlways())) {
entity = unit;
}
else {
if (instance.intersectRayWithMeshSlow(gdxRayHeap, intersectionHeap)
&& (intersectionHeap.z > this.terrain.getGroundHeight(intersectionHeap.x,
intersectionHeap.y))) {
this.worldScene.camera.worldToCamera(intersectionHeap, intersectionHeap);
if ((entity == null) || (intersectionHeap.z > intersectionHeap2.z)) {
entity = unit;
intersectionHeap2.set(intersectionHeap);
if (filter.call(unit.getSimulationWidget())) {
final float groundHeight = this.terrain.getGroundHeight(intersectionHeap.x, intersectionHeap.y);
if (intersectionHeap.z > groundHeight) {
if (((entity == null) && !unit.isIntersectedOnMeshAlways())) {
entity = unit;
}
else {
if (instance.intersectRayWithMeshSlow(gdxRayHeap, intersectionHeap)) {
if (intersectionHeap.z > this.terrain.getGroundHeight(intersectionHeap.x,
intersectionHeap.y)) {
this.worldScene.camera.worldToCamera(intersectionHeap, intersectionHeap);
if ((entity == null) || (intersectionHeap.z > intersectionHeap2.z)) {
entity = unit;
intersectionHeap2.set(intersectionHeap);
}
}
}
}
}
@ -1773,6 +1899,12 @@ public class War3MapViewer extends AbstractMdxModelViewer {
public int imageWalkableZOffset;
private WTS preloadedWTS;
private Color selectionCircleColorFriend;
private Color selectionCircleColorNeutral;
private Color selectionCircleColorEnemy;
/**
* 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);
}
private RenderWidget getRenderPeer(final CWidget damagedDestructable) {
public RenderWidget getRenderPeer(final CWidget damagedDestructable) {
RenderWidget damagedWidget = War3MapViewer.this.unitToRenderPeer.get(damagedDestructable);
if (damagedWidget == null) {
damagedWidget = War3MapViewer.this.destructableToRenderPeer.get(damagedDestructable);

View File

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

View File

@ -391,11 +391,11 @@ public class Terrain {
updateGroundHeights(new Rectangle(0, 0, width - 1, height - 1));
this.groundShader = webGL.createShaderProgram(TerrainShaders.Terrain.vert, TerrainShaders.Terrain.frag);
this.cliffShader = webGL.createShaderProgram(TerrainShaders.Cliffs.vert, TerrainShaders.Cliffs.frag);
this.waterShader = webGL.createShaderProgram(TerrainShaders.Water.vert, TerrainShaders.Water.frag);
this.groundShader = webGL.createShaderProgram(TerrainShaders.Terrain.vert(), TerrainShaders.Terrain.frag);
this.cliffShader = webGL.createShaderProgram(TerrainShaders.Cliffs.vert(), TerrainShaders.Cliffs.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 (?)
@ -1443,6 +1443,10 @@ public class Terrain {
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,
final boolean unshaded, final boolean noDepthTest, final boolean highPriority) {
SplatModel splatModel = this.uberSplatModels.get(path);

View File

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

View File

@ -24,9 +24,11 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
public Rectangle walkableBounds;
private final CDestructable simulationDestructable;
private SplatMover selectionCircle;
private SplatMover selectionPreviewHighlight;
private final UnitAnimationListenerImpl unitAnimationListenerImpl;
private boolean dead;
private BuildingShadow destructableShadow;
private final boolean selectable;
public RenderDestructable(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
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);
simulationDestructable.setUnitAnimationListener(this.unitAnimationListenerImpl);
this.unitAnimationListenerImpl.playAnimation(true, getAnimation(), SequenceUtils.EMPTY, 1.0f, true);
this.selectable = row.readSLKTagBoolean("selectable");
}
@Override
@ -86,6 +89,10 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
this.selectionCircle.destroy(Gdx.gl30, war3MapViewer.terrain.centerOffset);
this.selectionCircle = null;
}
if (this.selectionPreviewHighlight != null) {
this.selectionPreviewHighlight.destroy(Gdx.gl30, war3MapViewer.terrain.centerOffset);
this.selectionPreviewHighlight = null;
}
}
else if (!dead) {
if (this.dead) {
@ -140,6 +147,25 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
@Override
public void assignSelectionCircle(final SplatMover 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 SplatMover shadow;
public SplatMover selectionCircle;
public SplatMover selectionPreviewHighlight;
private boolean hidden;
private boolean dead;
@ -176,4 +177,24 @@ public class RenderItem implements RenderWidget {
public void assignSelectionCircle(final SplatMover 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;
private BuildingShadow buildingShadowInstance;
public SplatMover selectionCircle;
public SplatMover selectionPreviewHighlight;
private float facing;
@ -161,6 +162,9 @@ public class RenderUnit implements RenderWidget {
if (this.selectionCircle != null) {
this.selectionCircle.hide();
}
if (this.selectionPreviewHighlight != null) {
this.selectionPreviewHighlight.hide();
}
if (this.shadow != null) {
this.shadow.hide();
}
@ -174,6 +178,9 @@ public class RenderUnit implements RenderWidget {
if (this.selectionCircle != null) {
this.selectionCircle.show(map.terrain.centerOffset);
}
if (this.selectionPreviewHighlight != null) {
this.selectionPreviewHighlight.show(map.terrain.centerOffset);
}
if (this.shadow != null) {
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 = null;
}
if (this.selectionPreviewHighlight != null) {
this.selectionPreviewHighlight.destroy(Gdx.gl30, map.terrain.centerOffset);
this.selectionPreviewHighlight = null;
}
}
if (boneCorpse && !this.boneCorpse) {
this.unitAnimationListenerImpl.playAnimationWithDuration(true, PrimaryTag.DECAY, SequenceUtils.BONE,
@ -404,6 +415,13 @@ public class RenderUnit implements RenderWidget {
|| ((movementType == MovementType.FLY) || (movementType == MovementType.HOVER)),
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();
if (!dead && this.simulationUnit.isConstructing()) {
this.instance.setFrameByRatio(
@ -447,6 +465,9 @@ public class RenderUnit implements RenderWidget {
if (this.selectionCircle != null) {
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[1] = this.simulationUnit.getY();
}
@ -463,7 +484,7 @@ public class RenderUnit implements RenderWidget {
@Override
public boolean isIntersectedOnMeshAlways() {
return this.simulationUnit.getUnitType().isBuilding();
return this.simulationUnit.isBuilding();
}
@Override
@ -495,4 +516,24 @@ public class RenderUnit implements RenderWidget {
public void assignSelectionCircle(final SplatMover 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 unassignSelectionPreviewHighlight();
void assignSelectionPreviewHighlight(SplatMover t);
boolean isSelectable();
public static final class UnitAnimationListenerImpl implements CUnitAnimationListener {
private final MdxComplexInstance instance;
protected final EnumSet<AnimationTokens.SecondaryTag> secondaryAnimationTags = EnumSet
@ -159,4 +165,6 @@ public interface RenderWidget {
this.allowRarityVariations = allowRarityVariations;
}
}
SplatMover getSelectionPreviewHighlight();
}

View File

@ -14,6 +14,7 @@ public class CDestructable extends CWidget {
private final RemovablePathingMapInstance pathingInstance;
private final RemovablePathingMapInstance pathingInstanceDeath;
private UnitAnimationListenerImpl unitAnimationListenerImpl;
private boolean invulnerable;
public CDestructable(final int handleId, final float x, final float y, final float life,
final CDestructableType destTypeInstance, final RemovablePathingMapInstance pathingInstance,
@ -80,4 +81,18 @@ public class CDestructable extends CWidget {
public void setUnitAnimationListener(final 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;
}
@Override
public float getMaxLife() {
return this.itemType.getHitPoints();
}
public void setPointAndCheckUnstuck(final float newX, final float newY, final CSimulation game) {
final CWorldCollision collision = game.getWorldCollision();
final PathingGrid pathingGrid = game.getPathingGrid();
@ -100,4 +105,9 @@ public class CItem extends CWidget {
setY(outputY);
}
@Override
public boolean isInvulnerable() {
return false;
}
}

View File

@ -201,14 +201,14 @@ public class CUnit extends CWidget {
return this.mana;
}
public int getMaximumLife() {
return this.maximumLife;
}
public int getMaximumMana() {
return this.maximumMana;
}
public int getMaximumLife() {
return this.maximumLife;
}
public void setTypeId(final War3ID typeId) {
this.typeId = typeId;
}
@ -430,7 +430,7 @@ public class CUnit extends CWidget {
}
public float getEndingDecayTime(final CSimulation game) {
if (this.unitType.isBuilding()) {
if (this.isBuilding()) {
return game.getGameplayConstants().getStructureDecayTime();
}
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) {
final float prevX = getX();
if (!this.unitType.isBuilding()) {
if (!this.isBuilding()) {
setX(newX);
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) {
final float prevY = getY();
if (!this.unitType.isBuilding()) {
if (!this.isBuilding()) {
setY(newY);
collision.translate(this, 0, newY - prevY);
}
@ -692,7 +692,7 @@ public class CUnit extends CWidget {
final float prevY = getY();
setX(newX);
setY(newY);
if (!this.unitType.isBuilding()) {
if (!this.isBuilding()) {
collision.translate(this, newX - prevX, newY - prevY);
}
checkRegionEvents(regionManager);
@ -867,7 +867,7 @@ public class CUnit extends CWidget {
final CPlayer sourcePlayer = simulation.getPlayer(source.getPlayerIndex());
if (!sourcePlayer.hasAlliance(this.playerIndex, CAllianceType.PASSIVE)) {
final CGameplayConstants gameplayConstants = simulation.getGameplayConstants();
if (gameplayConstants.isBuildingKillsGiveExp() || !source.getUnitType().isBuilding()) {
if (gameplayConstants.isBuildingKillsGiveExp() || !source.isBuilding()) {
final CUnit killedUnit = this;
final CAbilityHero killedUnitHeroData = getHeroData();
final boolean killedUnitIsAHero = killedUnitHeroData != null;
@ -917,7 +917,7 @@ public class CUnit extends CWidget {
if (target instanceof CUnit) {
final CUnit targetUnit = (CUnit) target;
final CUnitType targetUnitType = targetUnit.getUnitType();
if (targetUnitType.isBuilding() && (targetUnitType.getBuildingPathingPixelMap() != null)) {
if (targetUnit.isBuilding() && (targetUnitType.getBuildingPathingPixelMap() != null)) {
final BufferedImage buildingPathingPixelMap = targetUnitType.getBuildingPathingPixelMap();
final float targetX = target.getX();
final float targetY = target.getY();
@ -1061,7 +1061,7 @@ public class CUnit extends CWidget {
}
public boolean isMovementDisabled() {
return this.unitType.isBuilding();
return this.isBuilding();
}
public float getAcquisitionRange() {
@ -1205,6 +1205,7 @@ public class CUnit extends CWidget {
this.invulnerable = invulnerable;
}
@Override
public boolean isInvulnerable() {
return this.invulnerable;
}
@ -1537,6 +1538,11 @@ public class CUnit extends CWidget {
return this.containingRegions.contains(region);
}
@Override
public float getMaxLife() {
return this.maximumLife;
}
private static final class RegionCheckerImpl implements CRegionEnumFunction {
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 int properNamesCount;
private final boolean canFlee;
private final int priority;
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,
@ -91,7 +92,7 @@ public class CUnitType {
final float strengthPerLevel, final int agility, final float agilityPerLevel, final int intelligence,
final float intelligencePerLevel, final CPrimaryAttribute primaryAttribute,
final List<War3ID> heroAbilityList, final List<String> heroProperNames, final int properNamesCount,
final boolean canFlee) {
final boolean canFlee, final int priority) {
this.name = name;
this.legacyName = legacyName;
this.typeId = typeId;
@ -144,6 +145,7 @@ public class CUnitType {
this.heroProperNames = heroProperNames;
this.properNamesCount = properNamesCount;
this.canFlee = canFlee;
this.priority = priority;
}
public String getName() {
@ -353,4 +355,8 @@ public class CUnitType {
public boolean isCanFlee() {
return this.canFlee;
}
public int getPriority() {
return this.priority;
}
}

View File

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

View File

@ -37,7 +37,7 @@ public class CWorldCollision {
collisionSize * 2);
unit.setCollisionRectangle(bounds);
}
if (unit.getUnitType().isBuilding()) {
if (unit.isBuilding()) {
// 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
this.buildingUnitCollision.add(unit, bounds);
@ -73,7 +73,7 @@ public class CWorldCollision {
public void removeUnit(final CUnit unit) {
final Rectangle bounds = unit.getCollisionRectangle();
if (bounds != null) {
if (unit.getUnitType().isBuilding()) {
if (unit.isBuilding()) {
this.buildingUnitCollision.remove(unit, bounds);
}
else {
@ -154,7 +154,7 @@ public class CWorldCollision {
}
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");
}
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
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;
}

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) {
SplashDamageConsumer.INSTANCE.doDamage(cSimulation, source, target, this, x, y, damage, attackListener);
if ((getWeaponType() != CWeaponType.ARTILLERY) && !SplashDamageConsumer.INSTANCE.hitTarget) {
super.doDamage(cSimulation, source, target, damage * this.damageFactorSmall, x, y, bounceIndex,
attackListener);
float originalTargetDamage = damage;
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.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.CAbilityTypeDefinitionInvulnerable;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionReturnResources;
public class CAbilityData {
@ -36,6 +37,7 @@ public class CAbilityData {
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Ahar"), new CAbilityTypeDefinitionHarvest());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("ANcl"), new CAbilityTypeDefinitionChannelTest());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("AInv"), new CAbilityTypeDefinitionInventory());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Avul"), new CAbilityTypeDefinitionInvulnerable());
}
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 CAN_FLEE = War3ID.fromString("ufle");
private static final War3ID PRIORITY = War3ID.fromString("upri");
private final CGameplayConstants gameplayConstants;
private final MutableObjectData unitData;
@ -275,6 +276,7 @@ public class CUnitData {
final String abilityList = unitType.getFieldAsString(ABILITIES_NORMAL, 0);
final String heroAbilityListString = unitType.getFieldAsString(ABILITIES_HERO, 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 String movetp = unitType.getFieldAsString(MOVE_TYPE, 0);
@ -536,7 +538,7 @@ public class CUnitData {
goldCost, lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes, requiredPathingTypes,
propWindow, turnRate, requirements, unitLevel, hero, strength, strPlus, agility, agiPlus,
intelligence, intPlus, primaryAttribute, heroAbilityList, heroProperNames, properNamesCount,
canFlee);
canFlee, priority);
this.unitIdToUnitType.put(typeId, unitTypeInstance);
this.jassLegacyNameToUnitId.put(legacyName, typeId);
}

View File

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

View File

@ -5,10 +5,13 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.TimeUnit;
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.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
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.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.BoundingBox;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
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.War3ID;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.Bounds;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.ViewerTextureRenderable;
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.QueueItemType;
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.CUnitType;
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 lastErrorMessageFadeTime;
private MenuCursorState cursorState;
private CAbilityView activeCommand;
private int activeCommandOrderId;
private RenderUnit activeCommandUnit;
@ -278,6 +287,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private MdxModel waypointModel;
private final List<MdxComplexInstance> waypointModelInstances = new ArrayList<>();
private List<RenderUnit> selectedUnits;
private Set<RenderUnit> dragSelectPreviewUnits = new HashSet<>();
private Set<RenderUnit> dragSelectPreviewUnitsUpcoming = new HashSet<>();
private BitmapFont textTagFont;
private SetPoint uberTipNoResourcesSetPoint;
private SetPoint uberTipWithResourcesSetPoint;
@ -296,6 +307,15 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private SimpleButtonFrame chatButton;
private final Runnable exitGameRunnable;
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,
final Scene portraitScene, final CameraPreset[] cameraPresets, final CameraRates cameraRates,
@ -939,13 +959,13 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
@Override
public void onClick(final int abilityHandleId, final int orderId, final boolean rightClick) {
// TODO not O(N)
if (this.selectedUnit == null) {
return;
}
if (orderId == 0) {
return;
}
// TODO not O(N)
CAbilityView abilityToUse = null;
for (final CAbility ability : this.selectedUnit.getSimulationUnit().getAbilities()) {
if (ability.getHandleId() == abilityHandleId) {
@ -1050,6 +1070,53 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
if (Gdx.input.isCursorCatched()) {
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);
this.uiViewport.unproject(screenCoordsVector);
@ -1058,9 +1125,10 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
if (this.activeCommand != null) {
if (this.draggingItem != null) {
this.cursorFrame.setSequence("HoldItem");
setCursorState(MenuCursorState.HOLD_ITEM);
}
else {
setCursorState(MenuCursorState.TARGET_CURSOR);
this.activeCommand.visit(this.cursorTargetSetupVisitor.reset(baseMouseX, baseMouseY));
}
}
@ -1081,34 +1149,34 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
if (down) {
if (left) {
this.cursorFrame.setSequence("Scroll Down Left");
setCursorState(MenuCursorState.SCROLL_DOWN_LEFT);
}
else if (right) {
this.cursorFrame.setSequence("Scroll Down Right");
setCursorState(MenuCursorState.SCROLL_DOWN_RIGHT);
}
else {
this.cursorFrame.setSequence("Scroll Down");
setCursorState(MenuCursorState.SCROLL_DOWN);
}
}
else if (up) {
if (left) {
this.cursorFrame.setSequence("Scroll Up Left");
setCursorState(MenuCursorState.SCROLL_UP_LEFT);
}
else if (right) {
this.cursorFrame.setSequence("Scroll Up Right");
setCursorState(MenuCursorState.SCROLL_UP_RIGHT);
}
else {
this.cursorFrame.setSequence("Scroll Up");
setCursorState(MenuCursorState.SCROLL_UP);
}
}
else if (left) {
this.cursorFrame.setSequence("Scroll Left");
setCursorState(MenuCursorState.SCROLL_LEFT);
}
else if (right) {
this.cursorFrame.setSequence("Scroll Right");
setCursorState(MenuCursorState.SCROLL_RIGHT);
}
else {
this.cursorFrame.setSequence("Normal");
setCursorState(MenuCursorState.NORMAL);
}
}
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) {
final BitmapFont font = this.rootFrame.getFont();
font.setColor(Color.YELLOW);
@ -1172,6 +1293,26 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
(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() {
@ -1783,8 +1924,11 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private void reloadSelectedUnitUI(final RenderUnit unit) {
final CUnit simulationUnit = unit.getSimulationUnit();
this.rootFrame.setText(this.unitLifeText,
FastNumberFormat.formatWholeNumber(simulationUnit.getLife()) + " / " + simulationUnit.getMaximumLife());
final float lifeRatioRemaining = simulationUnit.getLife() / simulationUnit.getMaxLife();
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();
if (maximumMana > 0) {
this.rootFrame.setText(this.unitManaText,
@ -1940,8 +2084,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.rootFrame.setText(this.simpleNameValue, unitTypeName);
String classText = null;
for (final CUnitClassification classification : simulationUnit.getClassifications()) {
if ((classification == CUnitClassification.MECHANICAL)
&& simulationUnit.getUnitType().isBuilding()) {
if ((classification == CUnitClassification.MECHANICAL) && simulationUnit.isBuilding()) {
// buildings dont display MECHANICAL
continue;
}
@ -2041,14 +2184,20 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
localArmorIconBackdrop.setTexture(defenseTexture);
String defenseDisplayString = Integer.toString(simulationUnit.getCurrentDefenseDisplay());
final int temporaryDefenseBonus = simulationUnit.getTemporaryDefenseBonus();
if (temporaryDefenseBonus != 0) {
if (temporaryDefenseBonus > 0) {
defenseDisplayString += "|cFF00FF00 (+" + temporaryDefenseBonus + ")";
}
else {
defenseDisplayString += "|cFFFF0000 (+" + temporaryDefenseBonus + ")";
String defenseDisplayString;
if (simulationUnit.isInvulnerable()) {
defenseDisplayString = this.rootFrame.getTemplates().getDecoratedString("INVULNERABLE");
}
else {
defenseDisplayString = Integer.toString(simulationUnit.getCurrentDefenseDisplay());
final int temporaryDefenseBonus = simulationUnit.getTemporaryDefenseBonus();
if (temporaryDefenseBonus != 0) {
if (temporaryDefenseBonus > 0) {
defenseDisplayString += "|cFF00FF00 (+" + temporaryDefenseBonus + ")";
}
else {
defenseDisplayString += "|cFFFF0000 (+" + temporaryDefenseBonus + ")";
}
}
}
this.rootFrame.setText(localArmorInfoPanelIconValue, defenseDisplayString);
@ -2165,9 +2314,13 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
selectUnit(null);
}
else {
final float lifeRatioRemaining = this.selectedUnit.getSimulationUnit().getLife()
/ this.selectedUnit.getSimulationUnit().getMaxLife();
this.rootFrame.setText(this.unitLifeText,
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) {
this.allowDrag = false;
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
if (this.meleeUIMinimap.containsMouse(screenCoordsVector.x, screenCoordsVector.y)) {
@ -2300,9 +2454,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
clearAndRepopulateCommandCard();
}
else {
final boolean shiftDown = isShiftDown();
final RenderWidget rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY,
this.activeCommandUnitTargetFilter);
final boolean shiftDown = isShiftDown();
if (rayPickUnit != null) {
this.unitOrderListener.issueTargetOrder(
this.activeCommandUnit.getSimulationUnit().getHandleId(),
@ -2442,11 +2596,14 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
}
else {
final List<RenderWidget> selectedUnits = this.war3MapViewer.selectUnit(screenX, worldScreenY,
false);
if (!selectedUnits.isEmpty()) {
selectWidgets(selectedUnits);
if (this.mouseOverUnit != null) {
final List<RenderWidget> unitList = Arrays.asList(this.mouseOverUnit);
this.war3MapViewer.doSelectUnit(unitList);
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) {
this.currentlyDraggingPointer = -1;
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
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);
}
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;
return false;
}
@ -2599,6 +2785,25 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.cameraManager.target.x = worldPoint.x;
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;
}
@ -2625,6 +2830,24 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
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;
}

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;
}
}