mirror of
https://github.com/Retera/WarsmashModEngine.git
synced 2022-07-31 17:38:59 +02:00
Update with waves
This commit is contained in:
parent
fabc3f4e61
commit
2ac6a5fa1d
@ -24,7 +24,6 @@ import com.etheller.warsmash.viewer5.ModelViewer;
|
||||
import com.etheller.warsmash.viewer5.PathSolver;
|
||||
import com.etheller.warsmash.viewer5.Scene;
|
||||
import com.etheller.warsmash.viewer5.SolvedPath;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.EventObjectEmitterObject;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||
@ -58,8 +57,7 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
|
||||
System.err.println("Renderer: " + renderer);
|
||||
|
||||
final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor("E:\\Backups\\Warcraft\\Data\\127");
|
||||
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor(
|
||||
"D:\\NEEDS_ORGANIZING\\MPQBuild\\Test");
|
||||
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor("E:\\Backups\\Warsmash\\Data");
|
||||
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
|
||||
this.codebase = new CompoundDataSourceDescriptor(
|
||||
Arrays.<DataSourceDescriptor>asList(war3mpq, testingFolder, currentFolder)).createDataSource();
|
||||
@ -74,8 +72,8 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
|
||||
this.cameraManager = new CameraManager();
|
||||
this.cameraManager.setupCamera(scene);
|
||||
|
||||
// this.mainModel = (MdxModel) this.viewer.load("UI\\Glues\\MainMenu\\MainMenu3D_exp\\MainMenu3D_exp.mdx",
|
||||
this.mainModel = (MdxModel) this.viewer.load("Units\\Human\\HeroPaladinBoss\\HeroPaladinBoss.mdx",
|
||||
this.mainModel = (MdxModel) this.viewer.load("Buildings\\Other\\TempArtB\\TempArtB.mdx",
|
||||
// this.mainModel = (MdxModel) this.viewer.load("Abilities\\Spells\\Orc\\FeralSpirit\\feralspirittarget.mdx",
|
||||
new PathSolver() {
|
||||
@Override
|
||||
public SolvedPath solve(final String src, final Object solverParams) {
|
||||
@ -83,12 +81,12 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
|
||||
}
|
||||
}, null);
|
||||
|
||||
final EventObjectEmitterObject evt = this.mainModel.getEventObjects().get(1);
|
||||
for (final Sequence seq : this.mainModel.getSequences()) {
|
||||
System.out.println(seq.getName() + ": " + Arrays.toString(seq.getInterval()));
|
||||
}
|
||||
System.out.println(Arrays.toString(evt.keyFrames));
|
||||
System.out.println(evt.name);
|
||||
// final EventObjectEmitterObject evt = this.mainModel.getEventObjects().get(1);
|
||||
// for (final Sequence seq : this.mainModel.getSequences()) {
|
||||
// System.out.println(seq.getName() + ": " + Arrays.toString(seq.getInterval()));
|
||||
// }
|
||||
// System.out.println(Arrays.toString(evt.keyFrames));
|
||||
// System.out.println(evt.name);
|
||||
|
||||
// this.modelCamera = this.mainModel.cameras.get(0);
|
||||
|
||||
|
@ -5,6 +5,7 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
@ -13,6 +14,7 @@ import com.badlogic.gdx.ApplicationAdapter;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.InputProcessor;
|
||||
import com.badlogic.gdx.audio.Music;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.GL30;
|
||||
@ -23,6 +25,8 @@ import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
|
||||
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
|
||||
import com.badlogic.gdx.math.Quaternion;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
@ -85,6 +89,11 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
private final Texture[] teamColors = new Texture[WarsmashConstants.MAX_PLAYERS];
|
||||
private Texture solidGreenTexture;
|
||||
|
||||
private ShapeRenderer shapeRenderer;
|
||||
private boolean showTalentTree;
|
||||
|
||||
private final List<Message> messages = new LinkedList<>();
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
|
||||
@ -107,8 +116,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
// "D:\\NEEDS_ORGANIZING\\MPQBuild\\War3xLocal.mpq\\enus-war3local.mpq");
|
||||
// final FolderDataSourceDescriptor rebirth = new FolderDataSourceDescriptor(
|
||||
// "E:\\Games\\Warcraft III Patch 1.31 Rebirth");
|
||||
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor(
|
||||
"D:\\NEEDS_ORGANIZING\\MPQBuild\\Test");
|
||||
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor("E:\\Backups\\Warsmash\\Data");
|
||||
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
|
||||
this.codebase = new CompoundDataSourceDescriptor(
|
||||
Arrays.<DataSourceDescriptor>asList(war3mpq, /* war3xLocalmpq, */ testingFolder, currentFolder))
|
||||
@ -118,8 +126,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
this.viewer.worldScene.enableAudio();
|
||||
this.viewer.enableAudio();
|
||||
try {
|
||||
// "Maps\\Campaign\\NightElf03.w3m"
|
||||
this.viewer.loadMap("ProjectileTest.w3x");
|
||||
this.viewer.loadMap("ReforgedGeorgeVacation.w3x");
|
||||
}
|
||||
catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@ -170,7 +177,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
|
||||
this.batch = new SpriteBatch();
|
||||
|
||||
this.consoleUITexture = new Texture(new DataSourceFileHandle(this.viewer.dataSource, "AlphaUi.png"));
|
||||
// this.consoleUITexture = new Texture(new DataSourceFileHandle(this.viewer.dataSource, "AlphaUi.png"));
|
||||
if (this.viewer.dataSource.has("war3mapMap.tga")) {
|
||||
try {
|
||||
this.minimapTexture = ImageUtils.getTextureNoColorCorrection(TgaFile.readTGA("war3mapMap.tga",
|
||||
@ -204,12 +211,12 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
"ReplaceableTextures\\TeamColor\\TeamColor06.blp");
|
||||
|
||||
Gdx.input.setInputProcessor(this);
|
||||
//
|
||||
// final Music music = Gdx.audio
|
||||
// .newMusic(new DataSourceFileHandle(this.viewer.dataSource, "Sound\\Music\\mp3Music\\OrcTheme.mp3"));
|
||||
// music.setVolume(0.2f);
|
||||
// music.setLooping(true);
|
||||
// music.play();
|
||||
|
||||
final Music music = Gdx.audio
|
||||
.newMusic(new DataSourceFileHandle(this.viewer.dataSource, "Sound\\Music\\mp3Music\\DarkAgents.mp3"));
|
||||
music.setVolume(0.2f);
|
||||
music.setLooping(true);
|
||||
music.play();
|
||||
|
||||
this.minimap = new Rectangle(35, 7, 305, 272);
|
||||
final float worldWidth = (this.viewer.terrain.columns - 1);
|
||||
@ -224,6 +231,9 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
|
||||
this.cameraManager.target.x = this.viewer.startLocations[0].x;
|
||||
this.cameraManager.target.y = this.viewer.startLocations[0].y;
|
||||
|
||||
this.shapeRenderer = new ShapeRenderer();
|
||||
this.talentTreeWindow = new Rectangle(100, 300, 1400, 800);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -265,7 +275,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
this.glyphLayout.setText(this.font, fpsString);
|
||||
this.font.draw(this.batch, fpsString, (this.uiViewport.getWorldWidth() - this.glyphLayout.width) / 2, 1100);
|
||||
|
||||
this.batch.draw(this.consoleUITexture, 0, 0, this.uiViewport.getWorldWidth(), 320);
|
||||
// this.batch.draw(this.consoleUITexture, 0, 0, this.uiViewport.getWorldWidth(), 320);
|
||||
this.batch.draw(this.minimapTexture, 35, 7, 305, 272);
|
||||
|
||||
if (this.selectedUnit != null) {
|
||||
@ -281,6 +291,11 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
this.font20.draw(this.batch, "Defense:", 600, 98);
|
||||
this.font20.draw(this.batch, "Speed:", 600, 76);
|
||||
this.font20.setColor(Color.WHITE);
|
||||
int messageIndex = 0;
|
||||
for (final Message message : this.messages) {
|
||||
this.font20.draw(this.batch, message.text, 100, 400 + (25 * (messageIndex++)));
|
||||
}
|
||||
this.font20.setColor(Color.WHITE);
|
||||
final int dmgMin = this.viewer.simulation.getUnitData()
|
||||
.getA1MinDamage(this.selectedUnit.getSimulationUnit().getTypeId());
|
||||
final int dmgMax = this.viewer.simulation.getUnitData()
|
||||
@ -325,6 +340,33 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
4, 4);
|
||||
}
|
||||
this.batch.end();
|
||||
|
||||
if (this.showTalentTree) {
|
||||
this.shapeRenderer.setProjectionMatrix(this.uiCamera.combined);
|
||||
|
||||
this.shapeRenderer.setColor(Color.BLACK);
|
||||
this.shapeRenderer.begin(ShapeType.Filled);
|
||||
this.shapeRenderer.rect(this.talentTreeWindow.x, this.talentTreeWindow.y, this.talentTreeWindow.width,
|
||||
this.talentTreeWindow.height);
|
||||
this.shapeRenderer.end();
|
||||
|
||||
this.shapeRenderer.setColor(Color.YELLOW);
|
||||
this.shapeRenderer.begin(ShapeType.Line);
|
||||
this.shapeRenderer.rect(100, 300, 1400, 800);
|
||||
this.shapeRenderer.end();
|
||||
|
||||
this.batch.begin();
|
||||
|
||||
this.font.setColor(Color.YELLOW);
|
||||
final String title = "Mage Talent Tree";
|
||||
this.glyphLayout.setText(this.font, title);
|
||||
this.font.draw(this.batch, title,
|
||||
this.talentTreeWindow.x + ((this.talentTreeWindow.width - this.glyphLayout.width) / 2),
|
||||
(this.talentTreeWindow.y + this.talentTreeWindow.height) - 45);
|
||||
|
||||
this.batch.end();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -466,6 +508,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
private final Vector2 cameraVelocity = new Vector2();
|
||||
private Scene portraitScene;
|
||||
private Texture minimapTexture;
|
||||
private Rectangle talentTreeWindow;
|
||||
|
||||
@Override
|
||||
public boolean keyDown(final int keycode) {
|
||||
@ -509,9 +552,25 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
@Override
|
||||
public boolean touchDown(final int screenX, final int screenY, final int pointer, final int button) {
|
||||
System.out.println(screenX + "," + screenY);
|
||||
|
||||
clickLocationTemp2.x = screenX;
|
||||
clickLocationTemp2.y = screenY;
|
||||
this.uiViewport.unproject(clickLocationTemp2);
|
||||
|
||||
if (this.selectedUnit != null) {
|
||||
for (final CommandCardIcon commandCardIcon : this.selectedUnit.getCommandCardIcons()) {
|
||||
if (new Rectangle(1225 + (70 * commandCardIcon.getX()), 160 - (70 * commandCardIcon.getY()), 64, 64)
|
||||
.contains(clickLocationTemp2)) {
|
||||
if (button == Input.Buttons.RIGHT) {
|
||||
this.messages.add(new Message(Gdx.input.getCurrentEventTime(), "Right mouse click"));
|
||||
}
|
||||
else {
|
||||
this.messages.add(new Message(Gdx.input.getCurrentEventTime(), "Left mouse click"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.minimapFilledArea.contains(clickLocationTemp2.x, clickLocationTemp2.y)) {
|
||||
final float clickX = (clickLocationTemp2.x - this.minimapFilledArea.x) / this.minimapFilledArea.width;
|
||||
final float clickY = (clickLocationTemp2.y - this.minimapFilledArea.y) / this.minimapFilledArea.height;
|
||||
@ -604,4 +663,14 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class Message {
|
||||
private final float time;
|
||||
private final String text;
|
||||
|
||||
public Message(final float time, final String text) {
|
||||
this.time = time;
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ import com.google.common.io.LittleEndianDataOutputStream;
|
||||
|
||||
public class CollisionShape extends GenericObject {
|
||||
public static enum Type {
|
||||
PLANE,
|
||||
BOX,
|
||||
PLANE,
|
||||
SPHERE,
|
||||
CYLINDER;
|
||||
|
||||
@ -77,12 +77,12 @@ public class CollisionShape extends GenericObject {
|
||||
public void readMdl(final MdlTokenInputStream stream) {
|
||||
for (final String token : super.readMdlGeneric(stream)) {
|
||||
switch (token) {
|
||||
case MdlUtils.TOKEN_PLANE:
|
||||
this.type = Type.PLANE;
|
||||
break;
|
||||
case MdlUtils.TOKEN_BOX:
|
||||
this.type = Type.BOX;
|
||||
break;
|
||||
case MdlUtils.TOKEN_PLANE:
|
||||
this.type = Type.PLANE;
|
||||
break;
|
||||
case MdlUtils.TOKEN_SPHERE:
|
||||
this.type = Type.SPHERE;
|
||||
break;
|
||||
@ -116,12 +116,12 @@ public class CollisionShape extends GenericObject {
|
||||
String type;
|
||||
int vertices = 2;
|
||||
switch (this.type) {
|
||||
case PLANE:
|
||||
type = MdlUtils.TOKEN_PLANE;
|
||||
break;
|
||||
case BOX:
|
||||
type = MdlUtils.TOKEN_BOX;
|
||||
break;
|
||||
case PLANE:
|
||||
type = MdlUtils.TOKEN_PLANE;
|
||||
break;
|
||||
case SPHERE:
|
||||
type = MdlUtils.TOKEN_SPHERE;
|
||||
vertices = 1;
|
||||
@ -164,4 +164,16 @@ public class CollisionShape extends GenericObject {
|
||||
return size;
|
||||
}
|
||||
|
||||
public float[][] getVertices() {
|
||||
return this.vertices;
|
||||
}
|
||||
|
||||
public CollisionShape.Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public float getBoundsRadius() {
|
||||
return this.boundsRadius;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,13 @@
|
||||
package com.etheller.warsmash.viewer5;
|
||||
|
||||
import com.badlogic.gdx.math.Intersector;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.math.collision.BoundingBox;
|
||||
import com.badlogic.gdx.math.collision.Ray;
|
||||
|
||||
public class Bounds {
|
||||
public float x, y, z, r;
|
||||
private BoundingBox boundingBox;
|
||||
|
||||
public void fromExtents(final float[] min, final float[] max) {
|
||||
final float x = min[0];
|
||||
@ -15,5 +21,14 @@ public class Bounds {
|
||||
this.y = y + (d / 2f);
|
||||
this.z = z + (h / 2f);
|
||||
this.r = (float) (Math.max(Math.max(w, d), h) / 2.);
|
||||
this.boundingBox = new BoundingBox(new Vector3(min), new Vector3(max));
|
||||
}
|
||||
|
||||
public void intersectRay(final Ray ray, final Vector3 intersection) {
|
||||
Intersector.intersectRayBounds(ray, this.boundingBox, intersection);
|
||||
}
|
||||
|
||||
public boolean intersectRayFast(final Ray ray) {
|
||||
return Intersector.intersectRayBoundsFast(ray, this.boundingBox);
|
||||
}
|
||||
}
|
||||
|
@ -4,4 +4,9 @@ public class Extensions {
|
||||
public static ANGLEInstancedArrays angleInstancedArrays;
|
||||
|
||||
public static DynamicShadowExtension dynamicShadowExtension;
|
||||
|
||||
public static WireframeExtension wireframeExtension;
|
||||
|
||||
public static int GL_LINE = 0;
|
||||
public static int GL_FILL = 0;
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
package com.etheller.warsmash.viewer5.gl;
|
||||
|
||||
public interface WireframeExtension {
|
||||
void glPolygonMode(int face, int mode);
|
||||
}
|
@ -1,10 +1,90 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.mdx;
|
||||
|
||||
import com.badlogic.gdx.math.Intersector;
|
||||
import com.badlogic.gdx.math.Matrix4;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.math.collision.BoundingBox;
|
||||
import com.badlogic.gdx.math.collision.Ray;
|
||||
|
||||
public class CollisionShape extends GenericObject {
|
||||
private static Vector3 intersectHeap = new Vector3();
|
||||
private static Vector3 intersectHeap2 = new Vector3();
|
||||
private static Matrix4 intersectMatrixHeap = new Matrix4();
|
||||
private static Ray intersectRayHeap = new Ray();
|
||||
private Intersectable intersectable;
|
||||
|
||||
public CollisionShape(final MdxModel model, final com.etheller.warsmash.parsers.mdlx.CollisionShape object,
|
||||
final int index) {
|
||||
super(model, object, index);
|
||||
final float[][] vertices = object.getVertices();
|
||||
|
||||
switch (object.getType()) {
|
||||
case BOX:
|
||||
this.intersectable = new IntersectableBox(vertices[0], vertices[1]);
|
||||
break;
|
||||
case CYLINDER:
|
||||
this.intersectable = null; // TODO
|
||||
break;
|
||||
case PLANE:
|
||||
this.intersectable = null; // TODO
|
||||
break;
|
||||
case SPHERE:
|
||||
this.intersectable = new IntersectableSphere(vertices[0], object.getBoundsRadius());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkIntersect(final Ray ray, final MdxNode mdxNode, final Vector3 intersection) {
|
||||
if (this.intersectable != null) {
|
||||
return this.intersectable.checkIntersect(ray, mdxNode, intersection);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static interface Intersectable {
|
||||
boolean checkIntersect(final Ray ray, final MdxNode mdxNode, final Vector3 intersection);
|
||||
}
|
||||
|
||||
private static final class IntersectableBox implements Intersectable {
|
||||
private final BoundingBox boundingBox;
|
||||
|
||||
public IntersectableBox(final float[] vertex1, final float[] vertex2) {
|
||||
this.boundingBox = new BoundingBox(new Vector3(vertex1), new Vector3(vertex2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkIntersect(final Ray ray, final MdxNode mdxNode, final Vector3 intersection) {
|
||||
intersectMatrixHeap.set(mdxNode.worldMatrix);
|
||||
Matrix4.inv(intersectMatrixHeap.val);
|
||||
intersectHeap.set(ray.origin);
|
||||
intersectHeap2.set(ray.direction);
|
||||
intersectHeap2.add(ray.origin);
|
||||
intersectHeap.prj(intersectMatrixHeap);
|
||||
intersectHeap2.prj(intersectMatrixHeap);
|
||||
intersectHeap2.sub(intersectHeap);
|
||||
intersectRayHeap.set(intersectHeap, intersectHeap2);
|
||||
if (Intersector.intersectRayBounds(intersectRayHeap, this.boundingBox, intersection)) {
|
||||
intersection.prj(mdxNode.worldMatrix);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class IntersectableSphere implements Intersectable {
|
||||
private final Vector3 center;
|
||||
private final float radius;
|
||||
|
||||
public IntersectableSphere(final float[] center, final float radius) {
|
||||
this.center = new Vector3(center);
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,31 @@ import com.etheller.warsmash.viewer5.Texture;
|
||||
import com.etheller.warsmash.viewer5.handlers.EmitterObject;
|
||||
|
||||
public class EventObjectEmitterObject extends GenericObject implements EmitterObject {
|
||||
private static final class LoadGenericSoundCallback implements LoadGenericCallback {
|
||||
private final String filename;
|
||||
|
||||
public LoadGenericSoundCallback(final String filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object call(final InputStream data) {
|
||||
final FileHandle temp = new FileHandle(this.filename) {
|
||||
@Override
|
||||
public InputStream read() {
|
||||
return data;
|
||||
};
|
||||
};
|
||||
if (data != null) {
|
||||
return Gdx.audio.newSound(temp);
|
||||
}
|
||||
else {
|
||||
System.err.println("Warning: missing sound file: " + this.filename);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final LoadGenericCallback mappedDataCallback = new LoadGenericCallback() {
|
||||
|
||||
@Override
|
||||
@ -43,18 +68,6 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
return new MappedData(stringBuilder.toString());
|
||||
}
|
||||
};
|
||||
private static final LoadGenericCallback decodedDataCallback = new LoadGenericCallback() {
|
||||
@Override
|
||||
public Object call(final InputStream data) {
|
||||
final FileHandle temp = new FileHandle("sound.wav") {
|
||||
@Override
|
||||
public InputStream read() {
|
||||
return data;
|
||||
};
|
||||
};
|
||||
return Gdx.audio.newSound(temp);
|
||||
}
|
||||
};
|
||||
|
||||
private int geometryEmitterType = -1;
|
||||
public final String type;
|
||||
@ -266,10 +279,11 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
final String[] fileNames = ((String) animSoundsRow.get("FileNames")).split(",");
|
||||
final GenericResource[] resources = new GenericResource[fileNames.length];
|
||||
for (int i = 0; i < fileNames.length; i++) {
|
||||
final GenericResource genericResource = viewer.loadGeneric(
|
||||
pathSolver.solve(((String) animSoundsRow.get("DirectoryBase")) + fileNames[i],
|
||||
model.solverParams).finalSrc,
|
||||
FetchDataTypeName.ARRAY_BUFFER, decodedDataCallback);
|
||||
final String pathString = pathSolver.solve(
|
||||
((String) animSoundsRow.get("DirectoryBase")) + fileNames[i],
|
||||
model.solverParams).finalSrc;
|
||||
final GenericResource genericResource = viewer.loadGeneric(pathString,
|
||||
FetchDataTypeName.ARRAY_BUFFER, new LoadGenericSoundCallback(pathString));
|
||||
if (genericResource == null) {
|
||||
throw new IllegalStateException("Null sound: " + fileNames[i]);
|
||||
}
|
||||
|
@ -69,6 +69,8 @@ public class GeometryEmitterFuncs {
|
||||
private static final Vector3 startHeap = new Vector3();
|
||||
private static final Vector3 endHeap = new Vector3();
|
||||
private static final float[] vectorTemp = new float[3];
|
||||
private static final Vector3[] vector3Heap = { new Vector3(), new Vector3(), new Vector3(), new Vector3(),
|
||||
new Vector3(), new Vector3() };
|
||||
|
||||
public static void bindParticleEmitter2Buffer(final ParticleEmitter2 emitter, final ClientBuffer buffer) {
|
||||
final MdxComplexInstance instance = emitter.instance;
|
||||
@ -99,6 +101,16 @@ public class GeometryEmitterFuncs {
|
||||
floatView.put(p0Offset + 0, location.x);
|
||||
floatView.put(p0Offset + 1, location.y);
|
||||
floatView.put(p0Offset + 2, location.z);
|
||||
if (emitterObject.xYQuad != 0) {
|
||||
final Vector3 velocity = object.velocity;
|
||||
floatView.put(p0Offset + 3, velocity.x);
|
||||
floatView.put(p0Offset + 4, velocity.y);
|
||||
floatView.put(p0Offset + 5, velocity.z);
|
||||
}
|
||||
else {
|
||||
floatView.put(p0Offset + 3, 0);
|
||||
floatView.put(p0Offset + 4, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
final Vector3 velocity = object.velocity;
|
||||
|
@ -9,6 +9,7 @@ import java.util.List;
|
||||
import com.badlogic.gdx.math.Matrix4;
|
||||
import com.badlogic.gdx.math.Quaternion;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.math.collision.Ray;
|
||||
import com.etheller.warsmash.parsers.mdlx.Sequence;
|
||||
import com.etheller.warsmash.util.WarsmashConstants;
|
||||
import com.etheller.warsmash.viewer5.GenericNode;
|
||||
@ -681,4 +682,25 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
protected RenderBatch getBatch(final TextureMapper textureMapper2) {
|
||||
throw new UnsupportedOperationException("NOT API");
|
||||
}
|
||||
|
||||
public void intersectRayBounds(final Ray ray, final Vector3 intersection) {
|
||||
this.model.bounds.intersectRay(ray, intersection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Intersects a world ray with the model's CollisionShapes. Only ever call this
|
||||
* function on the Gdx thread because it uses static variables to hold state
|
||||
* while processing.
|
||||
*
|
||||
* @param ray
|
||||
*/
|
||||
public boolean intersectRayWithCollision(final Ray ray, final Vector3 intersection) {
|
||||
for (final CollisionShape collisionShape : ((MdxModel) this.model).collisionShapes) {
|
||||
final MdxNode mdxNode = this.nodes[collisionShape.index];
|
||||
if (collisionShape.checkIntersect(ray, mdxNode, intersection)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -363,7 +363,28 @@ public class MdxShaders {
|
||||
" v_color = color;\r\n" + //
|
||||
" \r\n" + //
|
||||
" if (a_tail == HEAD) {\r\n" + //
|
||||
" gl_Position = u_mvp * vec4(a_p0 + (u_vertices[int(a_position)] * scale), 1.0);\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" + //
|
||||
|
@ -0,0 +1,71 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x;
|
||||
|
||||
public class AnimationTokens {
|
||||
public static enum PrimaryTag {
|
||||
ATTACK,
|
||||
BIRTH,
|
||||
CINEMATIC,
|
||||
DEATH,
|
||||
DECAY,
|
||||
DISSIPATE,
|
||||
MORPH,
|
||||
PORTRAIT,
|
||||
SLEEP,
|
||||
SPELL,
|
||||
STAND,
|
||||
WALK;
|
||||
}
|
||||
|
||||
public static enum SecondaryTag {
|
||||
ALTERNATE,
|
||||
ALTERNATEEX,
|
||||
CHAIN,
|
||||
CHANNEL,
|
||||
COMPLETE,
|
||||
CRITICAL,
|
||||
DEFEND,
|
||||
DRAIN,
|
||||
EATTREE,
|
||||
FAST,
|
||||
FILL,
|
||||
FLAIL,
|
||||
FLESH,
|
||||
FIFTH,
|
||||
FIRE,
|
||||
FIRST,
|
||||
FIVE,
|
||||
FOUR,
|
||||
FOURTH,
|
||||
GOLD,
|
||||
HIT,
|
||||
LARGE,
|
||||
LEFT,
|
||||
LIGHT,
|
||||
LOOPING,
|
||||
LUMBER,
|
||||
MEDIUM,
|
||||
MODERATE,
|
||||
OFF,
|
||||
ONE,
|
||||
PUKE,
|
||||
READY,
|
||||
RIGHT,
|
||||
SECOND,
|
||||
SEVERE,
|
||||
SLAM,
|
||||
SMALL,
|
||||
SPIKED,
|
||||
SPIN,
|
||||
SWIM,
|
||||
TALK,
|
||||
THIRD,
|
||||
THREE,
|
||||
THROW,
|
||||
TWO,
|
||||
TURN,
|
||||
VICTORY,
|
||||
WORK,
|
||||
WOUNDED,
|
||||
UPGRADE;
|
||||
}
|
||||
}
|
@ -47,20 +47,29 @@ public class SplatModel {
|
||||
final float y1 = locs[3];
|
||||
final float zoffs = locs[4];
|
||||
|
||||
final int ix0 = (int) Math.floor((x0 - centerOffset[0]) / 128.0);
|
||||
final int ix1 = (int) Math.ceil((x1 - centerOffset[0]) / 128.0);
|
||||
final int iy0 = (int) Math.floor((y0 - centerOffset[1]) / 128.0);
|
||||
final int iy1 = (int) Math.ceil((y1 - centerOffset[1]) / 128.0);
|
||||
final float centerOffsetX = centerOffset[0];
|
||||
final float centerOffsetY = centerOffset[1];
|
||||
final int ix0 = (int) Math.floor((x0 - centerOffsetX) / 128.0);
|
||||
final int ix1 = (int) Math.ceil((x1 - centerOffsetX) / 128.0);
|
||||
final int iy0 = (int) Math.floor((y0 - centerOffsetY) / 128.0);
|
||||
final int iy1 = (int) Math.ceil((y1 - centerOffsetY) / 128.0);
|
||||
|
||||
final float newVerts = ((iy1 - iy0) + 1) * ((ix1 - ix0) + 1);
|
||||
if (newVerts > MAX_VERTICES) {
|
||||
final int newVerts = ((iy1 - iy0) + 1) * ((ix1 - ix0) + 1);
|
||||
final int maxPossibleVerts = ((int) Math.ceil((y1 - y0) / 128.0) + 2)
|
||||
* ((int) Math.ceil((x1 - x0) / 128.0) + 2);
|
||||
final int maxPossibleFaces = ((int) Math.ceil((y1 - y0) / 128.0) + 1)
|
||||
* ((int) Math.ceil((x1 - x0) / 128.0) + 1);
|
||||
|
||||
int start = vertices.size();
|
||||
final SplatMover splatMover = unit == null ? null : new SplatMover(start * 3 * 4, indices.size() * 6 * 2);
|
||||
|
||||
final int numVertsToCrate = splatMover == null ? newVerts : maxPossibleVerts;
|
||||
if (numVertsToCrate > MAX_VERTICES) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int start = vertices.size();
|
||||
final SplatMover splatMover = unit == null ? null : new SplatMover(start * 3 * 4);
|
||||
final int step = (ix1 - ix0) + 1;
|
||||
if ((start + newVerts) > MAX_VERTICES) {
|
||||
if ((start + numVertsToCrate) > MAX_VERTICES) {
|
||||
this.addBatch(gl, vertices, uvs, indices, batchRenderUnits);
|
||||
vertices.clear();
|
||||
uvs.clear();
|
||||
@ -69,27 +78,62 @@ public class SplatModel {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
final float uvXScale = x1 - x0;
|
||||
final float uvYScale = y1 - y0;
|
||||
for (int iy = iy0; iy <= iy1; ++iy) {
|
||||
final float y = (iy * 128.0f) + centerOffset[1];
|
||||
final float y = (iy * 128.0f) + centerOffsetY;
|
||||
for (int ix = ix0; ix <= ix1; ++ix) {
|
||||
final float x = (ix * 128.0f) + centerOffset[0];
|
||||
final float x = (ix * 128.0f) + centerOffsetX;
|
||||
final float[] vertex = new float[] { x, y, zoffs };
|
||||
vertices.add(vertex);
|
||||
uvs.add(new float[] { (x - x0) / (x1 - x0), 1.0f - ((y - y0) / (y1 - y0)) });
|
||||
final float[] uv = new float[] { (x - x0) / uvXScale, 1.0f - ((y - y0) / uvYScale) };
|
||||
uvs.add(uv);
|
||||
if (splatMover != null) {
|
||||
splatMover.vertices.add(vertex);
|
||||
splatMover.uvs.add(uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (splatMover != null) {
|
||||
splatMover.uvXScale = uvXScale;
|
||||
splatMover.uvYScale = uvYScale;
|
||||
splatMover.locs = locs;
|
||||
splatMover.ix0 = ix0;
|
||||
splatMover.iy0 = iy0;
|
||||
splatMover.ix1 = ix1;
|
||||
splatMover.iy1 = iy1;
|
||||
|
||||
final float y = (iy1 * 128.0f) + centerOffsetY;
|
||||
final float x = (ix1 * 128.0f) + centerOffsetX;
|
||||
while (splatMover.vertices.size() < maxPossibleVerts) {
|
||||
final float[] vertex = new float[] { x, y, zoffs };
|
||||
vertices.add(vertex);
|
||||
final float[] uv = new float[] { (x - x0) / uvXScale, 1.0f - ((y - y0) / uvYScale) };
|
||||
uvs.add(uv);
|
||||
splatMover.vertices.add(vertex);
|
||||
splatMover.uvs.add(uv);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < (iy1 - iy0); ++i) {
|
||||
for (int j = 0; j < (ix1 - ix0); ++j) {
|
||||
final int i0 = start + (i * step) + j;
|
||||
indices.add(new int[] { i0, i0 + 1, i0 + step, i0 + 1, i0 + step + 1, i0 + step });
|
||||
final int[] indexArray = new int[] { i0, i0 + 1, i0 + step, i0 + 1, i0 + step + 1, i0 + step };
|
||||
indices.add(indexArray);
|
||||
if (splatMover != null) {
|
||||
splatMover.indices.add(indexArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unit != null) {
|
||||
unit.accept(splatMover);
|
||||
batchRenderUnits.add(splatMover);
|
||||
|
||||
while (splatMover.indices.size() < maxPossibleFaces) {
|
||||
final int i0 = start;
|
||||
final int[] indexArray = new int[] { i0, i0, i0, i0, i0, i0 };
|
||||
indices.add(indexArray);
|
||||
splatMover.indices.add(indexArray);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -117,6 +161,8 @@ public class SplatModel {
|
||||
this.batches.add(new Batch(uvsOffset, vertexBuffer, faceBuffer, indices.size() * 6));
|
||||
for (final SplatMover mover : batchRenderUnits) {
|
||||
mover.vertexBuffer = vertexBuffer;
|
||||
mover.uvsOffset = uvsOffset;
|
||||
mover.faceBuffer = faceBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,24 +203,127 @@ public class SplatModel {
|
||||
}
|
||||
|
||||
public static final class SplatMover {
|
||||
public int faceBuffer;
|
||||
public int uvsOffset;
|
||||
public int iy1;
|
||||
public int ix1;
|
||||
public int iy0;
|
||||
public int ix0;
|
||||
public float[] locs;
|
||||
public float uvYScale;
|
||||
public float uvXScale;
|
||||
private int vertexBuffer;
|
||||
private final int startOffset;
|
||||
private final int start;
|
||||
private final List<float[]> vertices = new ArrayList<>();
|
||||
private final List<float[]> uvs = new ArrayList<>();
|
||||
private final List<int[]> indices = new ArrayList<>();
|
||||
private final int indicesStartOffset;
|
||||
|
||||
private SplatMover(final int i) {
|
||||
private SplatMover(final int i, final int indicesStartOffset) {
|
||||
this.startOffset = i;
|
||||
this.indicesStartOffset = indicesStartOffset;
|
||||
this.start = i / 12;
|
||||
}
|
||||
|
||||
public void move(final float deltaX, final float deltaY) {
|
||||
for (final float[] vertex : this.vertices) {
|
||||
vertex[0] += deltaX;
|
||||
vertex[1] += deltaY;
|
||||
}
|
||||
public void move(final float deltaX, final float deltaY, final float[] centerOffset) {
|
||||
this.locs[0] += deltaX;
|
||||
this.locs[2] += deltaX;
|
||||
this.locs[1] += deltaY;
|
||||
this.locs[3] += deltaY;
|
||||
final float x0 = this.locs[0];
|
||||
final float y0 = this.locs[1];
|
||||
final float x1 = this.locs[2];
|
||||
final float y1 = this.locs[3];
|
||||
|
||||
final float centerOffsetX = centerOffset[0];
|
||||
final float centerOffsetY = centerOffset[1];
|
||||
final int ix0 = (int) Math.floor((x0 - centerOffsetX) / 128.0);
|
||||
final int ix1 = (int) Math.ceil((x1 - centerOffsetX) / 128.0);
|
||||
final int iy0 = (int) Math.floor((y0 - centerOffsetY) / 128.0);
|
||||
final int iy1 = (int) Math.ceil((y1 - centerOffsetY) / 128.0);
|
||||
|
||||
final GL30 gl = Gdx.gl30;
|
||||
gl.glBindBuffer(GL30.GL_ARRAY_BUFFER, this.vertexBuffer);
|
||||
gl.glBufferSubData(GL30.GL_ARRAY_BUFFER, this.startOffset, 4 * 3 * this.vertices.size(),
|
||||
RenderMathUtils.wrap(this.vertices));
|
||||
if ((ix0 != this.ix0) || (iy0 != this.iy0) || (ix1 != this.ix1) || (iy1 != this.iy1)) {
|
||||
// splat geometry has moved, difficult case
|
||||
final float newVerts = ((iy1 - iy0) + 1) * ((ix1 - ix0) + 1);
|
||||
if (newVerts <= this.uvs.size()) {
|
||||
}
|
||||
int vertexIndex = 0;
|
||||
float y = 0;
|
||||
float x = 0;
|
||||
for (int iy = iy0; iy <= iy1; ++iy) {
|
||||
y = (iy * 128.0f) + centerOffsetY;
|
||||
for (int ix = ix0; ix <= ix1; ++ix) {
|
||||
x = (ix * 128.0f) + centerOffsetX;
|
||||
final float[] vertexToUpdate = this.vertices.get(vertexIndex);
|
||||
vertexToUpdate[0] = x;
|
||||
vertexToUpdate[1] = y;
|
||||
final float[] uvItem = this.uvs.get(vertexIndex);
|
||||
uvItem[0] = (x - x0) / this.uvXScale;
|
||||
uvItem[1] = 1.0f - ((y - y0) / this.uvYScale);
|
||||
vertexIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
for (; vertexIndex < this.vertices.size(); vertexIndex++) {
|
||||
final float[] vertexToUpdate = this.vertices.get(vertexIndex);
|
||||
vertexToUpdate[0] = x;
|
||||
vertexToUpdate[1] = y;
|
||||
final float[] uvItem = this.uvs.get(vertexIndex);
|
||||
uvItem[0] = (x - x0) / this.uvXScale;
|
||||
uvItem[1] = 1.0f - ((y - y0) / this.uvYScale);
|
||||
}
|
||||
gl.glBufferSubData(GL30.GL_ARRAY_BUFFER, this.startOffset, 4 * 3 * this.vertices.size(),
|
||||
RenderMathUtils.wrap(this.vertices));
|
||||
|
||||
final int step = (ix1 - ix0) + 1;
|
||||
int faceIndicesIndex = 0;
|
||||
for (int i = 0; i < (iy1 - iy0); ++i) {
|
||||
for (int j = 0; j < (ix1 - ix0); ++j) {
|
||||
final int i0 = this.start + (i * step) + j;
|
||||
final int[] indexArr = this.indices.get(faceIndicesIndex++);
|
||||
indexArr[0] = i0;
|
||||
indexArr[1] = i0 + 1;
|
||||
indexArr[2] = i0 + step;
|
||||
indexArr[3] = i0 + 1;
|
||||
indexArr[4] = i0 + step + 1;
|
||||
indexArr[5] = i0 + step;
|
||||
}
|
||||
}
|
||||
|
||||
for (; faceIndicesIndex < this.indices.size(); faceIndicesIndex++) {
|
||||
final int i0 = this.start;
|
||||
final int[] indexArr = this.indices.get(faceIndicesIndex);
|
||||
for (int i = 0; i < indexArr.length; i++) {
|
||||
indexArr[i] = i0;
|
||||
}
|
||||
}
|
||||
gl.glBindBuffer(GL30.GL_ELEMENT_ARRAY_BUFFER, this.faceBuffer);
|
||||
gl.glBufferSubData(GL30.GL_ELEMENT_ARRAY_BUFFER, this.indicesStartOffset, 6 * 2 * this.indices.size(),
|
||||
RenderMathUtils.wrapFaces(this.indices));
|
||||
this.ix0 = ix0;
|
||||
this.iy0 = iy0;
|
||||
this.ix1 = ix1;
|
||||
this.iy1 = iy1;
|
||||
}
|
||||
else {
|
||||
// splat will use same geometry, easy case, just update the UVs
|
||||
|
||||
int index = 0;
|
||||
for (int iy = iy0; iy <= iy1; ++iy) {
|
||||
final float y = (iy * 128.0f) + centerOffsetY;
|
||||
for (int ix = ix0; ix <= ix1; ++ix) {
|
||||
final float x = (ix * 128.0f) + centerOffsetX;
|
||||
final float[] uvItem = this.uvs.get(index++);
|
||||
uvItem[0] = (x - x0) / this.uvXScale;
|
||||
uvItem[1] = 1.0f - ((y - y0) / this.uvYScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
gl.glBufferSubData(GL30.GL_ARRAY_BUFFER, this.uvsOffset + ((this.startOffset / 3) * 2),
|
||||
4 * 2 * this.uvs.size(), RenderMathUtils.wrap(this.uvs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ public class War3MapViewer extends ModelViewer {
|
||||
private static final War3ID sloc = War3ID.fromString("sloc");
|
||||
private static final LoadGenericCallback stringDataCallback = new StringDataCallbackImplementation();
|
||||
private static final float[] rayHeap = new float[6];
|
||||
private static final Ray gdxRayHeap = new Ray();
|
||||
private static final Vector2 mousePosHeap = new Vector2();
|
||||
private static final Vector3 normalHeap = new Vector3();
|
||||
private static final Vector3 intersectionHeap = new Vector3();
|
||||
@ -370,6 +371,9 @@ public class War3MapViewer extends ModelViewer {
|
||||
else {
|
||||
throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises");
|
||||
}
|
||||
|
||||
this.terrain.initShadows();
|
||||
this.terrain.createWaves();
|
||||
}
|
||||
|
||||
private void loadTerrainCliffsAndWater(final War3MapW3e w3e) {
|
||||
@ -411,6 +415,13 @@ public class War3MapViewer extends ModelViewer {
|
||||
|
||||
fileVar += ".mdx";
|
||||
|
||||
if (type == WorldEditorDataType.DESTRUCTIBLES) {
|
||||
final String shadowString = row.readSLKTag("shadow");
|
||||
if ((shadowString != null) && (shadowString.length() > 0) && !"_".equals(shadowString)) {
|
||||
this.terrain.addShadow(shadowString, doodad.getLocation()[0], doodad.getLocation()[1]);
|
||||
}
|
||||
|
||||
}
|
||||
// First see if the model is local.
|
||||
// Doodads referring to local models may have invalid variations, so if the
|
||||
// variation doesn't exist, try without a variation.
|
||||
@ -750,9 +761,9 @@ public class War3MapViewer extends ModelViewer {
|
||||
final float[] ray = rayHeap;
|
||||
mousePosHeap.set(screenX, screenY);
|
||||
this.worldScene.camera.screenToWorldRay(ray, mousePosHeap);
|
||||
final Ray gdxRay = new Ray(new Vector3(ray[0], ray[1], ray[2]),
|
||||
new Vector3(ray[3] - ray[0], ray[4] - ray[1], ray[5] - ray[2]));
|
||||
Terrain.intersectRayTriangles(gdxRay, this.terrain.softwareGroundMesh.vertices,
|
||||
gdxRayHeap.set(ray[0], ray[1], ray[2], ray[3] - ray[0], ray[4] - ray[1], ray[5] - ray[2]);
|
||||
gdxRayHeap.direction.nor();// needed for libgdx
|
||||
Terrain.intersectRayTriangles(gdxRayHeap, this.terrain.softwareGroundMesh.vertices,
|
||||
this.terrain.softwareGroundMesh.indices, 3, out);
|
||||
}
|
||||
|
||||
@ -766,6 +777,43 @@ public class War3MapViewer extends ModelViewer {
|
||||
}
|
||||
|
||||
public List<RenderUnit> selectUnit(final float x, final float y, final boolean toggle) {
|
||||
final float[] ray = rayHeap;
|
||||
mousePosHeap.set(x, y);
|
||||
this.worldScene.camera.screenToWorldRay(ray, mousePosHeap);
|
||||
gdxRayHeap.set(ray[0], ray[1], ray[2], ray[3] - ray[0], ray[4] - ray[1], ray[5] - ray[2]);
|
||||
gdxRayHeap.direction.nor();// needed for libgdx
|
||||
|
||||
RenderUnit entity = null;
|
||||
for (final RenderUnit unit : this.units) {
|
||||
final MdxComplexInstance instance = unit.instance;
|
||||
if (instance.intersectRayWithCollision(gdxRayHeap, intersectionHeap)) {
|
||||
entity = unit;
|
||||
}
|
||||
}
|
||||
List<RenderUnit> sel;
|
||||
if (entity != null) {
|
||||
if (toggle) {
|
||||
sel = new ArrayList<>(this.selected);
|
||||
final int idx = sel.indexOf(entity);
|
||||
if (idx >= 0) {
|
||||
sel.remove(idx);
|
||||
}
|
||||
else {
|
||||
sel.add(entity);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sel = Arrays.asList(entity);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sel = Collections.emptyList();
|
||||
}
|
||||
this.doSelectUnit(sel);
|
||||
return sel;
|
||||
}
|
||||
|
||||
public List<RenderUnit> selectUnitOld(final float x, final float y, final boolean toggle) {
|
||||
final float[] ray = rayHeap;
|
||||
mousePosHeap.set(x, y);
|
||||
this.worldScene.camera.screenToWorldRay(ray, mousePosHeap);
|
||||
@ -1020,4 +1068,9 @@ public class War3MapViewer extends ModelViewer {
|
||||
return ordered;
|
||||
}
|
||||
|
||||
public void standOnRepeat(final MdxComplexInstance instance) {
|
||||
instance.setSequenceLoopMode(2);
|
||||
StandSequence.randomStandSequence(instance);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ public class RenderCorner extends Corner {
|
||||
public boolean cliff;
|
||||
public boolean romp;
|
||||
public float rampAdjust;
|
||||
public float depth;
|
||||
|
||||
public RenderCorner(final Corner corner) {
|
||||
super(corner);
|
||||
|
@ -4,6 +4,7 @@ import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@ -18,6 +19,7 @@ import javax.imageio.ImageIO;
|
||||
import org.apache.commons.compress.utils.IOUtils;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.GL30;
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||
import com.badlogic.gdx.math.Intersector;
|
||||
@ -40,6 +42,7 @@ import com.etheller.warsmash.viewer5.Camera;
|
||||
import com.etheller.warsmash.viewer5.PathSolver;
|
||||
import com.etheller.warsmash.viewer5.RawOpenGLTextureResource;
|
||||
import com.etheller.warsmash.viewer5.Texture;
|
||||
import com.etheller.warsmash.viewer5.gl.Extensions;
|
||||
import com.etheller.warsmash.viewer5.gl.WebGL;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.DynamicShadowManager;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.SplatModel;
|
||||
@ -55,6 +58,7 @@ public class Terrain {
|
||||
private static final Vector3 normalHeap2 = new Vector3();
|
||||
private static final float[] fourComponentHeap = new float[4];
|
||||
private static final Matrix4 tempMatrix = new Matrix4();
|
||||
private static final boolean WIREFRAME_TERRAIN = false;
|
||||
|
||||
public ShaderProgram groundShader;
|
||||
public ShaderProgram waterShader;
|
||||
@ -114,6 +118,7 @@ public class Terrain {
|
||||
public final Map<String, List<float[]>> shadows = new HashMap<>();
|
||||
public final Map<String, Texture> shadowTextures = new HashMap<>();
|
||||
private final int[] mapBounds;
|
||||
private final float[] shaderMapBounds;
|
||||
private final int[] mapSize;
|
||||
public final SoftwareGroundMesh softwareGroundMesh;
|
||||
private final int testArrayBuffer;
|
||||
@ -369,6 +374,10 @@ public class Terrain {
|
||||
this.centerOffset = w3eFile.getCenterOffset();
|
||||
this.uberSplatModels = new ArrayList<>();
|
||||
this.mapBounds = w3iFile.getCameraBoundsComplements();
|
||||
this.shaderMapBounds = new float[] { (this.mapBounds[0] * 128.0f) + this.centerOffset[0],
|
||||
(this.mapBounds[2] * 128.0f) + this.centerOffset[1],
|
||||
((this.columns - this.mapBounds[1] - 1) * 128.0f) + this.centerOffset[0],
|
||||
((this.rows - this.mapBounds[3] - 1) * 128.0f) + this.centerOffset[1] };
|
||||
this.mapSize = w3eFile.getMapSize();
|
||||
this.softwareGroundMesh = new SoftwareGroundMesh(this.groundHeights, this.groundCornerHeights,
|
||||
this.centerOffset, width, height);
|
||||
@ -382,6 +391,13 @@ public class Terrain {
|
||||
// gl.glBindBuffer(GL30.GL_ELEMENT_ARRAY_BUFFER, this.testElementBuffer);
|
||||
// gl.glBufferData(GL30.GL_ELEMENT_ARRAY_BUFFER, this.softwareGroundMesh.indices.length,
|
||||
// RenderMathUtils.wrap(this.softwareGroundMesh.indices), GL30.GL_STATIC_DRAW);
|
||||
|
||||
this.waveBuilder = new WaveBuilder(this.mapSize, this.waterTable, viewer, this.corners, this.centerOffset,
|
||||
this.waterHeightOffset, w3eFile, w3iFile);
|
||||
}
|
||||
|
||||
public void createWaves() {
|
||||
this.waveBuilder.createWaves(this);
|
||||
}
|
||||
|
||||
private void updateGroundHeights(final Rectangle area) {
|
||||
@ -415,8 +431,12 @@ public class Terrain {
|
||||
}
|
||||
}
|
||||
|
||||
this.groundCornerHeights[(j * this.columns) + i] = this.corners[i][j].computeFinalGroundHeight()
|
||||
+ rampHeight;
|
||||
final RenderCorner corner = this.corners[i][j];
|
||||
final float newGroundCornerHeight = corner.computeFinalGroundHeight() + rampHeight;
|
||||
this.groundCornerHeights[(j * this.columns) + i] = newGroundCornerHeight;
|
||||
corner.depth = (corner.getWater() != 0)
|
||||
? (this.waterHeightOffset + corner.getWaterHeight()) - newGroundCornerHeight
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
updateGroundHeights();
|
||||
@ -430,9 +450,13 @@ public class Terrain {
|
||||
}
|
||||
|
||||
private void updateCornerHeights() {
|
||||
final FloatBuffer groundCornerHeightsWrapped = RenderMathUtils.wrap(this.groundCornerHeights);
|
||||
Gdx.gl30.glBindTexture(GL30.GL_TEXTURE_2D, this.groundCornerHeight);
|
||||
Gdx.gl30.glTexSubImage2D(GL30.GL_TEXTURE_2D, 0, 0, 0, this.columns, this.rows, GL30.GL_RED, GL30.GL_FLOAT,
|
||||
RenderMathUtils.wrap(this.groundCornerHeights));
|
||||
groundCornerHeightsWrapped);
|
||||
Gdx.gl30.glBindTexture(GL30.GL_TEXTURE_2D, this.groundCornerHeightLinear);
|
||||
Gdx.gl30.glTexSubImage2D(GL30.GL_TEXTURE_2D, 0, 0, 0, this.columns, this.rows, GL30.GL_RED, GL30.GL_FLOAT,
|
||||
groundCornerHeightsWrapped);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -819,15 +843,21 @@ public class Terrain {
|
||||
// gl.glActiveTexture(GL30.GL_TEXTURE21, /*pathingMap.getTextureDynamic()*/);
|
||||
|
||||
gl.glActiveTexture(GL30.GL_TEXTURE20);
|
||||
gl.glBindTexture(GL30.GL_TEXTURE_2D, dynamicShadowManager.getDepthTexture());
|
||||
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.shadowMap);
|
||||
|
||||
// gl.glEnableVertexAttribArray(0);
|
||||
gl.glBindBuffer(GL30.GL_ARRAY_BUFFER, Shapes.INSTANCE.vertexBuffer);
|
||||
gl.glVertexAttribPointer(0, 2, GL30.GL_FLOAT, false, 0, 0);
|
||||
|
||||
gl.glBindBuffer(GL30.GL_ELEMENT_ARRAY_BUFFER, Shapes.INSTANCE.indexBuffer);
|
||||
if (WIREFRAME_TERRAIN) {
|
||||
Extensions.wireframeExtension.glPolygonMode(GL20.GL_FRONT_AND_BACK, Extensions.GL_LINE);
|
||||
}
|
||||
gl.glDrawElementsInstanced(GL30.GL_TRIANGLES, Shapes.INSTANCE.quadIndices.length * 3, GL30.GL_UNSIGNED_INT, 0,
|
||||
(this.columns - 1) * (this.rows - 1));
|
||||
if (WIREFRAME_TERRAIN) {
|
||||
Extensions.wireframeExtension.glPolygonMode(GL20.GL_FRONT_AND_BACK, Extensions.GL_FILL);
|
||||
}
|
||||
|
||||
// gl.glDisableVertexAttribArray(0);
|
||||
|
||||
@ -910,6 +940,7 @@ public class Terrain {
|
||||
gl.glUniform1i(6, (int) this.waterIndex);
|
||||
gl.glUniform1f(this.waterShader.getUniformLocation("centerOffsetX"), this.centerOffset[0]);
|
||||
gl.glUniform1f(this.waterShader.getUniformLocation("centerOffsetY"), this.centerOffset[1]);
|
||||
gl.glUniform4fv(9, 1, this.shaderMapBounds, 0);
|
||||
|
||||
gl.glActiveTexture(GL30.GL_TEXTURE0);
|
||||
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.waterHeight);
|
||||
@ -960,6 +991,10 @@ public class Terrain {
|
||||
gl.glUniform1i(1, this.viewer.renderPathing);
|
||||
gl.glUniform1i(2, this.viewer.renderLighting);
|
||||
|
||||
this.cliffShader.setUniformi("shadowMap", 2);
|
||||
gl.glActiveTexture(GL30.GL_TEXTURE2);
|
||||
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.shadowMap);
|
||||
|
||||
gl.glActiveTexture(GL30.GL_TEXTURE0);
|
||||
gl.glBindTexture(GL30.GL_TEXTURE_2D_ARRAY, this.cliffTextureArray);
|
||||
gl.glActiveTexture(GL30.GL_TEXTURE1);
|
||||
@ -1052,7 +1087,7 @@ public class Terrain {
|
||||
}
|
||||
}
|
||||
|
||||
this.shadowMap = gl.glGenBuffer();
|
||||
this.shadowMap = gl.glGenTexture();
|
||||
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.shadowMap);
|
||||
gl.glTexParameteri(GL30.GL_TEXTURE_2D, GL30.GL_TEXTURE_MAG_FILTER, GL30.GL_LINEAR);
|
||||
gl.glTexParameteri(GL30.GL_TEXTURE_2D, GL30.GL_TEXTURE_MIN_FILTER, GL30.GL_LINEAR);
|
||||
@ -1107,6 +1142,7 @@ public class Terrain {
|
||||
static Vector3 tmp1 = new Vector3();
|
||||
static Vector3 tmp2 = new Vector3();
|
||||
static Vector3 tmp3 = new Vector3();
|
||||
private final WaveBuilder waveBuilder;
|
||||
|
||||
/**
|
||||
* Intersects the given ray with list of triangles. Returns the nearest
|
||||
@ -1185,10 +1221,10 @@ public class Terrain {
|
||||
final int cellY = (int) userCellSpaceY;
|
||||
|
||||
if ((cellX >= 0) && (cellX < (this.mapSize[0] - 1)) && (cellY >= 0) && (cellY < (this.mapSize[1] - 1))) {
|
||||
final float bottomLeft = this.corners[cellX][cellY].computeFinalGroundHeight();
|
||||
final float bottomRight = this.corners[cellX + 1][cellY].computeFinalGroundHeight();
|
||||
final float topLeft = this.corners[cellX][cellY + 1].computeFinalGroundHeight();
|
||||
final float topRight = this.corners[cellX + 1][cellY + 1].computeFinalGroundHeight();
|
||||
final float bottomLeft = this.groundCornerHeights[(cellY * this.columns) + cellX];
|
||||
final float bottomRight = this.groundCornerHeights[(cellY * this.columns) + cellX + 1];
|
||||
final float topLeft = this.groundCornerHeights[((cellY + 1) * this.columns) + cellX];
|
||||
final float topRight = this.groundCornerHeights[((cellY + 1) * this.columns) + cellX + 1];
|
||||
final float sqX = userCellSpaceX - cellX;
|
||||
final float sqY = userCellSpaceY - cellY;
|
||||
float height;
|
||||
@ -1269,4 +1305,22 @@ public class Terrain {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean inPlayableArea(float x, float y) {
|
||||
x = (x - this.centerOffset[0]) / 128.0f;
|
||||
y = (y - this.centerOffset[1]) / 128.0f;
|
||||
if (x < this.mapBounds[0]) {
|
||||
return false;
|
||||
}
|
||||
if (x >= (this.mapSize[0] - this.mapBounds[1] - 1)) {
|
||||
return false;
|
||||
}
|
||||
if (y < this.mapBounds[2]) {
|
||||
return false;
|
||||
}
|
||||
if (y >= (this.mapSize[1] - this.mapBounds[3] - 1)) {
|
||||
return false;
|
||||
} // TODO why do we use floor if we can use int cast?
|
||||
return this.corners[(int) Math.floor(x)][(int) Math.floor(y)].getBoundary() == 0;
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ public class TerrainShaders {
|
||||
"layout (location = 0) uniform mat4 MVP;\r\n" + //
|
||||
"\r\n" + //
|
||||
"layout (binding = 1) uniform sampler2D height_texture;\r\n" + //
|
||||
"layout (binding = 3) uniform sampler2D shadowMap;\r\n" + //
|
||||
"layout (location = 3) uniform float centerOffsetX;\r\n" + //
|
||||
"layout (location = 4) uniform float centerOffsetY;\r\n" + //
|
||||
"\r\n" + //
|
||||
@ -25,11 +26,14 @@ public class TerrainShaders {
|
||||
"layout (location = 1) out vec3 Normal;\r\n" + //
|
||||
"layout (location = 2) out vec2 pathing_map_uv;\r\n" + //
|
||||
"layout (location = 3) out vec3 position;\r\n" + //
|
||||
"layout (location = 4) out vec2 v_suv;\r\n" + //
|
||||
"\r\n" + //
|
||||
"void main() {\r\n" + //
|
||||
" pathing_map_uv = (vec2(vPosition.x + 128, vPosition.y) / 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.x + 192, vPosition.y + 64) / 128.0) / vec2(size)).r;\r\n"
|
||||
+ //
|
||||
"\r\n" + //
|
||||
@ -38,7 +42,7 @@ public class TerrainShaders {
|
||||
" myposition.x += centerOffsetX;\r\n" + //
|
||||
" myposition.y += centerOffsetY;\r\n" + //
|
||||
" position.x /= (size.x * 128.0);\r\n" + //
|
||||
" position.y /= (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" + //
|
||||
@ -57,6 +61,7 @@ public class TerrainShaders {
|
||||
"\r\n" + //
|
||||
"layout (binding = 0) uniform sampler2DArray cliff_textures;\r\n" + //
|
||||
"layout (binding = 2) uniform usampler2D pathing_map_static;\r\n" + //
|
||||
"layout (binding = 3) uniform sampler2D shadowMap;\r\n" + //
|
||||
"\r\n" + //
|
||||
"layout (location = 1) uniform bool show_pathing_map_static;\r\n" + //
|
||||
"layout (location = 2) uniform bool show_lighting;\r\n" + //
|
||||
@ -64,12 +69,15 @@ public class TerrainShaders {
|
||||
"layout (location = 0) in vec3 UV;\r\n" + //
|
||||
"layout (location = 1) in vec3 Normal;\r\n" + //
|
||||
"layout (location = 2) in vec2 pathing_map_uv;\r\n" + //
|
||||
"layout (location = 4) in vec2 v_suv;\r\n" + //
|
||||
"\r\n" + //
|
||||
"out vec4 color;\r\n" + //
|
||||
"\r\n" + //
|
||||
"void main() {\r\n" + //
|
||||
" color = texture(cliff_textures, UV);\r\n" + //
|
||||
"\r\n" + //
|
||||
" float shadow = texture2D(shadowMap, v_suv).r;\r\n" + //
|
||||
" color.rgb *= (1.0 - shadow);\r\n" + //
|
||||
" if (show_lighting) {\r\n" + //
|
||||
" vec3 light_direction = vec3(-0.3, -0.3, 0.25);\r\n" + //
|
||||
" light_direction = normalize(light_direction);\r\n" + //
|
||||
@ -127,6 +135,7 @@ public class TerrainShaders {
|
||||
"layout (location = 3) out vec3 normal;\r\n" + //
|
||||
"layout (location = 4) out vec3 position;\r\n" + //
|
||||
"layout (location = 5) out vec3 ShadowCoord;\r\n" + //
|
||||
"layout (location = 6) out vec2 v_suv;\r\n" + //
|
||||
"\r\n" + //
|
||||
"void main() { \r\n" + //
|
||||
" ivec2 size = textureSize(terrain_texture_list, 0);\r\n" + //
|
||||
@ -153,6 +162,7 @@ public class TerrainShaders {
|
||||
+ //
|
||||
" ShadowCoord = (((texture_indices.a & 32768) == 0) ? 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" + //
|
||||
"}";
|
||||
@ -190,6 +200,7 @@ public class TerrainShaders {
|
||||
"layout (location = 3) in vec3 normal;\r\n" + //
|
||||
"layout (location = 4) in vec3 position;\r\n" + //
|
||||
"layout (location = 5) in vec3 ShadowCoord;\r\n" + //
|
||||
"layout (location = 6) in vec2 v_suv;\r\n" + //
|
||||
"\r\n" + //
|
||||
"layout (location = 0) out vec4 color;\r\n" + //
|
||||
// "layout (location = 1) out vec4 position;\r\n" + //
|
||||
@ -247,11 +258,12 @@ public class TerrainShaders {
|
||||
+ //
|
||||
" color = color * color.a + get_fragment(texture_indices.r & 31, vec3(UV, texture_indices.r >> 5)) * (1 - color.a);\r\n"
|
||||
+ //
|
||||
" float visibility = 1.0;\r\n" + //
|
||||
" float shadow = texture2D(shadowMap, v_suv).r;\r\n" + //
|
||||
// " float visibility = 1.0;\r\n" + //
|
||||
// " if ( texture2D(shadowMap, ShadowCoord.xy).z > ShadowCoord.z ) {\r\n" + //
|
||||
// " visibility = 0.5;\r\n" + //
|
||||
// " }\r\n" + //
|
||||
" color = vec4(color.xyz * visibility, 1.0);\r\n" + //
|
||||
" color = vec4(color.xyz * (1.0 - shadow), 1.0);\r\n" + //
|
||||
"\r\n" + //
|
||||
// " if (show_lighting) {\r\n" + //
|
||||
// " vec3 light_direction = vec3(-0.3, -0.3, 0.25);\r\n" + //
|
||||
@ -406,6 +418,7 @@ public class TerrainShaders {
|
||||
"\r\n" + //
|
||||
"out vec2 UV;\r\n" + //
|
||||
"out vec4 Color;\r\n" + //
|
||||
"out vec2 position;\r\n" + //
|
||||
"\r\n" + //
|
||||
"const float min_depth = 10.f / 128;\r\n" + //
|
||||
"const float deeplevel = 64.f / 128;\r\n" + //
|
||||
@ -422,7 +435,9 @@ public class TerrainShaders {
|
||||
" || 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" + //
|
||||
" gl_Position = is_water ? MVP * vec4((vPosition.x + pos.x)*128.0 + centerOffsetX, (vPosition.y + pos.y)*128.0 + centerOffsetY, water_height*128.0, 1) : vec4(2.0, 0.0, 0.0, 1.0);\r\n"
|
||||
" position = vec2((vPosition.x + pos.x)*128.0 + centerOffsetX, (vPosition.y + pos.y)*128.0 + centerOffsetY);\r\n"
|
||||
+ //
|
||||
" gl_Position = is_water ? MVP * vec4(position.xy, water_height*128.0, 1) : 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" + //
|
||||
@ -445,14 +460,19 @@ public class TerrainShaders {
|
||||
"\r\n" + //
|
||||
"\r\n" + //
|
||||
"layout (location = 6) uniform int current_texture;\r\n" + //
|
||||
"layout (location = 9) uniform vec4 mapBounds;\r\n" + //
|
||||
"\r\n" + //
|
||||
"in vec2 UV;\r\n" + //
|
||||
"in vec4 Color;\r\n" + //
|
||||
"in vec2 position;\r\n" + //
|
||||
"\r\n" + //
|
||||
"out vec4 outColor;\r\n" + //
|
||||
"\r\n" + //
|
||||
"void main() {\r\n" + //
|
||||
" outColor = texture(water_textures, vec3(UV, current_texture)) * Color;\r\n" + //
|
||||
" vec2 d2 = min(position - mapBounds.xy, mapBounds.zw - position);\r\n" + //
|
||||
" float d1 = clamp(min(d2.x, d2.y) / 64.0 + 1.0, 0.0, 1.0) * 0.8 + 0.2;;\r\n" + //
|
||||
" outColor = texture(water_textures, vec3(UV, current_texture)) * vec4(Color.rgb * d1, Color.a);\r\n"
|
||||
+ //
|
||||
"}";
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,152 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.environment;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.badlogic.gdx.math.Quaternion;
|
||||
import com.etheller.warsmash.parsers.w3x.w3e.War3MapW3e;
|
||||
import com.etheller.warsmash.parsers.w3x.w3i.War3MapW3i;
|
||||
import com.etheller.warsmash.units.DataTable;
|
||||
import com.etheller.warsmash.units.Element;
|
||||
import com.etheller.warsmash.util.RenderMathUtils;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
|
||||
|
||||
public class WaveBuilder {
|
||||
|
||||
private final int[] mapSize;
|
||||
private final DataTable waterTable;
|
||||
private final War3MapViewer viewer;
|
||||
private final RenderCorner[][] corners;
|
||||
private final float[] centerOffset;
|
||||
private final float waterHeightOffset;
|
||||
private float[] locations;
|
||||
|
||||
private final Map<String, MdxModel> models;
|
||||
private final War3MapW3e w3eFile;
|
||||
private final War3MapW3i w3iFile;
|
||||
|
||||
public WaveBuilder(final int[] mapSize, final DataTable waterTable, final War3MapViewer viewer,
|
||||
final RenderCorner[][] corners, final float[] centerOffset, final float waterHeightOffset,
|
||||
final War3MapW3e w3eFile, final War3MapW3i w3iFile) {
|
||||
this.mapSize = mapSize;
|
||||
this.waterTable = waterTable;
|
||||
this.viewer = viewer;
|
||||
this.corners = corners;
|
||||
this.centerOffset = centerOffset;
|
||||
this.waterHeightOffset = waterHeightOffset;
|
||||
this.w3eFile = w3eFile;
|
||||
this.w3iFile = w3iFile;
|
||||
this.models = new HashMap<>();
|
||||
}
|
||||
|
||||
public void createWaves(final Terrain terrain) {
|
||||
final int columns = this.mapSize[0];
|
||||
final int rows = this.mapSize[1];
|
||||
final float wavesDepth = 25f / 128f;
|
||||
final char tileset = this.w3eFile.getTileset();
|
||||
final Element waterRow = this.waterTable.get(tileset + "Sha");
|
||||
|
||||
final long wavesCliff = (this.w3iFile.getFlags() & 0x0800);
|
||||
final long wavesRolling = (this.w3iFile.getFlags() & 0x1000);
|
||||
|
||||
final String shoreline = waterRow.getField("shoreDir") + "\\" + waterRow.getField("shoreSFile") + "\\"
|
||||
+ waterRow.getField("shoreSFile") + "0.mdx";
|
||||
final String outsideCorner = waterRow.getField("shoreDir") + "\\" + waterRow.getField("shoreOCFile") + "\\"
|
||||
+ waterRow.getField("shoreOCFile") + "0.mdx";
|
||||
final String insideCorner = waterRow.getField("shoreDir") + "\\" + waterRow.getField("shoreICFile") + "\\"
|
||||
+ waterRow.getField("shoreICFile") + "0.mdx";
|
||||
// final String shoreline = "Buildings\\Other\\TempArtB\\TempArtB.mdx";
|
||||
// final String outsideCorner = "Buildings\\Other\\TempArtB\\TempArtB.mdx";
|
||||
// final String insideCorner = "Buildings\\Other\\TempArtB\\TempArtB.mdx";
|
||||
|
||||
this.locations = new float[3];
|
||||
|
||||
for (int y = 0; y < (rows - 1); ++y) {
|
||||
for (int x = 0; x < (columns - 1); ++x) {
|
||||
final RenderCorner a = this.corners[x][y];
|
||||
final RenderCorner b = this.corners[x + 1][y];
|
||||
final RenderCorner c = this.corners[x + 1][y + 1];
|
||||
final RenderCorner d = this.corners[x][y + 1];
|
||||
if ((a.getWater() != 0) || (b.getWater() != 0) || (c.getWater() != 0) || (d.getWater() != 0)) {
|
||||
final boolean isCliff = (a.getLayerHeight() != b.getLayerHeight())
|
||||
|| (a.getLayerHeight() != c.getLayerHeight()) || (a.getLayerHeight() != d.getLayerHeight());
|
||||
if (isCliff && (wavesCliff == 0)) {
|
||||
continue;
|
||||
}
|
||||
if (!isCliff && (wavesRolling == 0)) {
|
||||
continue;
|
||||
}
|
||||
final int ad = (a.depth > wavesDepth) ? 1 : 0;
|
||||
final int bd = (b.depth > wavesDepth) ? 1 : 0;
|
||||
final int cd = (c.depth > wavesDepth) ? 1 : 0;
|
||||
final int dd = (d.depth > wavesDepth) ? 1 : 0;
|
||||
final int count = ad + bd + cd + dd;
|
||||
this.locations[0] = (x * 128.0f) + this.centerOffset[0] + 64.0f;
|
||||
this.locations[1] = (y * 128.0f) + this.centerOffset[1] + 64.0f;
|
||||
this.locations[2] = ((((a.getWaterHeight() + b.getWaterHeight() + c.getWaterHeight()
|
||||
+ d.getWaterHeight()) / 4f) + this.waterHeightOffset) * 128.0f) + 1.0f;
|
||||
if (count == 1) {
|
||||
addModelInstance(terrain, insideCorner, rotation(ad, bd, cd/* , dd */) - ((3 * Math.PI) / 4));
|
||||
}
|
||||
else if (count == 2) {
|
||||
final double rot = rotation2(ad, bd, cd, dd);
|
||||
if (!Double.isNaN(rot)) {
|
||||
addModelInstance(terrain, shoreline, rot);
|
||||
}
|
||||
}
|
||||
else if (count == 3) {
|
||||
addModelInstance(terrain, outsideCorner,
|
||||
rotation(1 ^ ad, 1 ^ bd, 1 ^ cd/* , 1 ^ dd */) + ((5 * Math.PI) / 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addModelInstance(final Terrain terrain, final String path, final double rotation) {
|
||||
if (!this.models.containsKey(path)) {
|
||||
this.models.put(path,
|
||||
(MdxModel) this.viewer.load(path, this.viewer.wc3PathSolver, this.viewer.solverParams));
|
||||
}
|
||||
final MdxModel model = this.models.get(path);
|
||||
final MdxComplexInstance instance = (MdxComplexInstance) model.addInstance();
|
||||
instance.setLocation(this.locations);
|
||||
instance.setLocalRotation(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, (float) rotation));
|
||||
instance.setScene(this.viewer.worldScene);
|
||||
if (!terrain.inPlayableArea(this.locations[0], this.locations[1])) {
|
||||
instance.setVertexColor(new float[] { 51 / 255f, 51 / 255f, 51 / 255f, 1.0f });
|
||||
}
|
||||
this.viewer.standOnRepeat(instance);
|
||||
}
|
||||
|
||||
private static double rotation(final int a, final int b, final int c) {
|
||||
if (a != 0) {
|
||||
return (-3 * Math.PI) / 4;
|
||||
}
|
||||
if (b != 0) {
|
||||
return -Math.PI / 4;
|
||||
}
|
||||
if (c != 0) {
|
||||
return Math.PI / 4;
|
||||
}
|
||||
return (3 * Math.PI) / 4;
|
||||
}
|
||||
|
||||
private static double rotation2(final int a, final int b, final int c, final int d) {
|
||||
if ((a != 0) && (b != 0)) {
|
||||
return -Math.PI / 2;
|
||||
}
|
||||
if ((b != 0) && (c != 0)) {
|
||||
return 0;
|
||||
}
|
||||
if ((c != 0) && (d != 0)) {
|
||||
return Math.PI / 2;
|
||||
}
|
||||
if ((a != 0) && (d != 0)) {
|
||||
return Math.PI;
|
||||
}
|
||||
return Double.NaN;
|
||||
}
|
||||
}
|
@ -105,7 +105,7 @@ public class RenderUnit {
|
||||
ability.getOrderId()));
|
||||
}
|
||||
else if (ability instanceof CAbilityAttack) {
|
||||
this.commandCardIcons.add(new CommandCardIcon(-2, -2,
|
||||
this.commandCardIcons.add(new CommandCardIcon(3, 0,
|
||||
ImageUtils.getBLPTexture(map.dataSource, "ReplaceableTextures\\CommandButtons\\BTNAttack.blp"),
|
||||
ability.getOrderId()));
|
||||
}
|
||||
@ -117,7 +117,7 @@ public class RenderUnit {
|
||||
ability.getOrderId()));
|
||||
}
|
||||
else if (ability instanceof CAbilityPatrol) {
|
||||
this.commandCardIcons.add(new CommandCardIcon(3, 0,
|
||||
this.commandCardIcons.add(new CommandCardIcon(0, 1,
|
||||
ImageUtils.getBLPTexture(map.dataSource, "ReplaceableTextures\\CommandButtons\\BTNPatrol.blp"),
|
||||
ability.getOrderId()));
|
||||
}
|
||||
@ -202,10 +202,10 @@ public class RenderUnit {
|
||||
}
|
||||
this.lastOrder = currentOrder;
|
||||
if (this.shadow != null) {
|
||||
this.shadow.move(dx, dy);
|
||||
this.shadow.move(dx, dy, map.terrain.centerOffset);
|
||||
}
|
||||
if (this.selectionCircle != null) {
|
||||
this.selectionCircle.move(dx, dy);
|
||||
this.selectionCircle.move(dx, dy, map.terrain.centerOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import com.etheller.warsmash.WarsmashGdxMapGame;
|
||||
import com.etheller.warsmash.viewer5.gl.ANGLEInstancedArrays;
|
||||
import com.etheller.warsmash.viewer5.gl.DynamicShadowExtension;
|
||||
import com.etheller.warsmash.viewer5.gl.Extensions;
|
||||
import com.etheller.warsmash.viewer5.gl.WireframeExtension;
|
||||
|
||||
public class DesktopLauncher {
|
||||
public static void main(final String[] arg) {
|
||||
@ -44,6 +45,14 @@ public class DesktopLauncher {
|
||||
GL11.glDrawBuffer(mode);
|
||||
}
|
||||
};
|
||||
Extensions.wireframeExtension = new WireframeExtension() {
|
||||
@Override
|
||||
public void glPolygonMode(final int face, final int mode) {
|
||||
GL11.glPolygonMode(face, mode);
|
||||
}
|
||||
};
|
||||
Extensions.GL_LINE = GL11.GL_LINE;
|
||||
Extensions.GL_FILL = GL11.GL_FILL;
|
||||
final LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
|
||||
config.useGL30 = true;
|
||||
config.gles30ContextMajorVersion = 3;
|
||||
|
Loading…
Reference in New Issue
Block a user