mirror of
https://github.com/Retera/WarsmashModEngine.git
synced 2022-07-31 17:38:59 +02:00
Visually able to see units and glitchy terrain now
This commit is contained in:
parent
015b04c371
commit
e998367f77
@ -35,7 +35,7 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
|
||||
private ModelViewer viewer;
|
||||
private MdxModel model;
|
||||
private CameraManager cameraManager;
|
||||
private static int VAO;
|
||||
public static int VAO;
|
||||
private final Rectangle tempRect = new Rectangle();
|
||||
|
||||
private BitmapFont font;
|
||||
|
253
core/src/com/etheller/warsmash/WarsmashGdxMapGame.java
Normal file
253
core/src/com/etheller/warsmash/WarsmashGdxMapGame.java
Normal file
@ -0,0 +1,253 @@
|
||||
package com.etheller.warsmash;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.badlogic.gdx.ApplicationAdapter;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.InputProcessor;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.math.Quaternion;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.etheller.warsmash.datasources.CompoundDataSourceDescriptor;
|
||||
import com.etheller.warsmash.datasources.DataSource;
|
||||
import com.etheller.warsmash.datasources.DataSourceDescriptor;
|
||||
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
|
||||
import com.etheller.warsmash.viewer5.Camera;
|
||||
import com.etheller.warsmash.viewer5.CanvasProvider;
|
||||
import com.etheller.warsmash.viewer5.Scene;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
|
||||
|
||||
public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProvider, InputProcessor {
|
||||
private DataSource codebase;
|
||||
private War3MapViewer viewer;
|
||||
private CameraManager cameraManager;
|
||||
private final Rectangle tempRect = new Rectangle();
|
||||
|
||||
private BitmapFont font;
|
||||
private SpriteBatch batch;
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
|
||||
final ByteBuffer tempByteBuffer = ByteBuffer.allocateDirect(4);
|
||||
tempByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
final IntBuffer temp = tempByteBuffer.asIntBuffer();
|
||||
|
||||
Gdx.gl30.glGenVertexArrays(1, temp);
|
||||
WarsmashGdxGame.VAO = temp.get(0);
|
||||
|
||||
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
|
||||
|
||||
final String renderer = Gdx.gl.glGetString(GL20.GL_RENDERER);
|
||||
System.err.println("Renderer: " + renderer);
|
||||
|
||||
// final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor("E:\\Backups\\Warcraft\\Data\\127");
|
||||
final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor(
|
||||
"D:\\NEEDS_ORGANIZING\\MPQBuild\\War3.mpq\\war3.mpq");
|
||||
final FolderDataSourceDescriptor war3xLocalmpq = new FolderDataSourceDescriptor(
|
||||
"D:\\NEEDS_ORGANIZING\\MPQBuild\\War3xLocal.mpq\\enus-war3local.mpq");
|
||||
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor(
|
||||
"D:\\NEEDS_ORGANIZING\\MPQBuild\\Test");
|
||||
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
|
||||
this.codebase = new CompoundDataSourceDescriptor(
|
||||
Arrays.<DataSourceDescriptor>asList(war3mpq, war3xLocalmpq, testingFolder, currentFolder))
|
||||
.createDataSource();
|
||||
this.viewer = new War3MapViewer(this.codebase, this);
|
||||
|
||||
try {
|
||||
this.viewer.loadMap("ReforgedGeorgeVacation.w3x");
|
||||
}
|
||||
catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
this.cameraManager = new CameraManager();
|
||||
this.cameraManager.setupCamera(this.viewer.worldScene);
|
||||
|
||||
System.out.println("Loaded");
|
||||
Gdx.gl30.glClearColor(0.0f, 0.0f, 0.0f, 1); // TODO remove white background
|
||||
|
||||
this.font = new BitmapFont();
|
||||
this.batch = new SpriteBatch();
|
||||
|
||||
Gdx.input.setInputProcessor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
|
||||
this.cameraManager.target.add(this.cameraVelocity.x, this.cameraVelocity.y, 0);
|
||||
this.cameraManager.updateCamera();
|
||||
this.viewer.updateAndRender();
|
||||
|
||||
// gl.glDrawElements(GL20.GL_TRIANGLES, this.elements, GL20.GL_UNSIGNED_SHORT, this.faceOffset);
|
||||
|
||||
// this.batch.begin();
|
||||
// this.font.draw(this.batch, Integer.toString(Gdx.graphics.getFramesPerSecond()), 0, 0);
|
||||
// this.batch.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return Gdx.graphics.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return Gdx.graphics.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(final int width, final int height) {
|
||||
this.tempRect.width = width;
|
||||
this.tempRect.height = height;
|
||||
this.cameraManager.camera.viewport(this.tempRect);
|
||||
}
|
||||
|
||||
class CameraManager {
|
||||
private CanvasProvider canvas;
|
||||
private Camera camera;
|
||||
private float moveSpeed;
|
||||
private float rotationSpeed;
|
||||
private float zoomFactor;
|
||||
private float horizontalAngle;
|
||||
private float verticalAngle;
|
||||
private float distance;
|
||||
private Vector3 position;
|
||||
private Vector3 target;
|
||||
private Vector3 worldUp;
|
||||
private Vector3 vecHeap;
|
||||
private Quaternion quatHeap;
|
||||
private Quaternion quatHeap2;
|
||||
|
||||
// An orbit camera setup example.
|
||||
// Left mouse button controls the orbit itself.
|
||||
// The right mouse button allows to move the camera and the point it's looking
|
||||
// at on the XY plane.
|
||||
// Scrolling zooms in and out.
|
||||
private void setupCamera(final Scene scene) {
|
||||
this.canvas = scene.viewer.canvas;
|
||||
this.camera = scene.camera;
|
||||
this.moveSpeed = 2;
|
||||
this.rotationSpeed = (float) (Math.PI / 180);
|
||||
this.zoomFactor = 0.1f;
|
||||
this.horizontalAngle = 0;// (float) (Math.PI / 2);
|
||||
this.verticalAngle = (float) (Math.PI / 4);
|
||||
this.distance = 1600;
|
||||
this.position = new Vector3();
|
||||
this.target = new Vector3(0, 0, 50);
|
||||
this.worldUp = new Vector3(0, 0, 1);
|
||||
this.vecHeap = new Vector3();
|
||||
this.quatHeap = new Quaternion();
|
||||
this.quatHeap2 = new Quaternion();
|
||||
|
||||
updateCamera();
|
||||
|
||||
// cameraUpdate();
|
||||
}
|
||||
|
||||
private void updateCamera() {
|
||||
// Limit the vertical angle so it doesn't flip.
|
||||
// Since the camera uses a quaternion, flips don't matter to it, but this feels
|
||||
// better.
|
||||
this.verticalAngle = (float) Math.min(Math.max(0.01, this.verticalAngle), Math.PI - 0.01);
|
||||
|
||||
this.quatHeap.idt();
|
||||
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
|
||||
this.quatHeap2.idt();
|
||||
this.quatHeap2.setFromAxisRad(1, 0, 0, this.verticalAngle);
|
||||
this.quatHeap.mul(this.quatHeap2);
|
||||
|
||||
this.position.set(0, 0, 1);
|
||||
this.quatHeap.transform(this.position);
|
||||
this.position.scl(this.distance);
|
||||
this.position = this.position.add(this.target);
|
||||
|
||||
this.camera.moveToAndFace(this.position, this.target, this.worldUp);
|
||||
}
|
||||
|
||||
// private void cameraUpdate() {
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
||||
private final float cameraSpeed = 100.0f;
|
||||
private final Vector2 cameraVelocity = new Vector2();
|
||||
|
||||
@Override
|
||||
public boolean keyDown(final int keycode) {
|
||||
if (keycode == Input.Keys.LEFT) {
|
||||
this.cameraVelocity.x = -this.cameraSpeed;
|
||||
}
|
||||
else if (keycode == Input.Keys.RIGHT) {
|
||||
this.cameraVelocity.x = this.cameraSpeed;
|
||||
}
|
||||
else if (keycode == Input.Keys.DOWN) {
|
||||
this.cameraVelocity.y = -this.cameraSpeed;
|
||||
}
|
||||
else if (keycode == Input.Keys.UP) {
|
||||
this.cameraVelocity.y = this.cameraSpeed;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyUp(final int keycode) {
|
||||
if (keycode == Input.Keys.LEFT) {
|
||||
this.cameraVelocity.x = 0;
|
||||
}
|
||||
else if (keycode == Input.Keys.RIGHT) {
|
||||
this.cameraVelocity.x = 0;
|
||||
}
|
||||
else if (keycode == Input.Keys.DOWN) {
|
||||
this.cameraVelocity.y = 0;
|
||||
}
|
||||
else if (keycode == Input.Keys.UP) {
|
||||
this.cameraVelocity.y = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyTyped(final char character) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDown(final int screenX, final int screenY, final int pointer, final int button) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchUp(final int screenX, final int screenY, final int pointer, final int button) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDragged(final int screenX, final int screenY, final int pointer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseMoved(final int screenX, final int screenY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scrolled(final int amount) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -624,6 +624,25 @@ public final class MutableObjectData {
|
||||
return this.parentWC3Object.getFieldValue(key) == 1;
|
||||
}
|
||||
|
||||
public int readSLKTagInt(final String key) {
|
||||
if (MutableObjectData.this.metaNameToMetaId.containsKey(key)) {
|
||||
return getFieldAsInteger(MutableObjectData.this.metaNameToMetaId.get(key), 0);
|
||||
}
|
||||
return this.parentWC3Object.getFieldValue(key);
|
||||
}
|
||||
|
||||
public float readSLKTagFloat(final String key) {
|
||||
if (MutableObjectData.this.metaNameToMetaId.containsKey(key)) {
|
||||
return getFieldAsFloat(MutableObjectData.this.metaNameToMetaId.get(key), 0);
|
||||
}
|
||||
try {
|
||||
return Float.parseFloat(this.parentWC3Object.getField(key));
|
||||
}
|
||||
catch (final NumberFormatException exc) {
|
||||
return Float.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
String name = getFieldAsString(MutableObjectData.this.editorData.getNameField(),
|
||||
MutableObjectData.this.worldEditorDataType == WorldEditorDataType.UPGRADES ? 1 : 0);
|
||||
|
@ -56,7 +56,7 @@ public class MappedData {
|
||||
key = "column" + j;
|
||||
}
|
||||
|
||||
mapped.put(key, row.get(j));
|
||||
mapped.put(key, j < row.size() ? row.get(j) : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -321,8 +321,8 @@ public enum RenderMathUtils {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int testCell(final Vector4[] planes, final int left, final int right, final int bottom, final int top,
|
||||
int first) {
|
||||
public static int testCell(final Vector4[] planes, final float left, final float right, final float bottom,
|
||||
final float top, int first) {
|
||||
if (first == -1) {
|
||||
first = 0;
|
||||
}
|
||||
@ -340,7 +340,7 @@ public enum RenderMathUtils {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static float distance2Plane2(final Vector4 plane, final int px, final int py) {
|
||||
public static float distance2Plane2(final Vector4 plane, final float px, final float py) {
|
||||
return (plane.x * px) + (plane.y * py) + plane.w;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
package com.etheller.warsmash.util;
|
||||
|
||||
public class WarsmashConstants {
|
||||
public static final int MAX_PLAYERS = 16;
|
||||
public static final int MAX_PLAYERS = 28;
|
||||
}
|
||||
|
@ -45,10 +45,17 @@ public abstract class GdxTextureResource extends Texture {
|
||||
return this.gdxTexture.glTarget;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGlHandle() {
|
||||
return this.gdxTexture.getTextureObjectHandle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrapS(final boolean wrapS) {
|
||||
this.gdxTexture.setWrap(wrapS ? TextureWrap.Repeat : TextureWrap.ClampToEdge, this.gdxTexture.getVWrap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrapT(final boolean wrapT) {
|
||||
this.gdxTexture.setWrap(this.gdxTexture.getUWrap(), wrapT ? TextureWrap.Repeat : TextureWrap.ClampToEdge);
|
||||
}
|
||||
|
@ -13,7 +13,8 @@ public class Grid {
|
||||
private final int rows;
|
||||
final GridCell[] cells;
|
||||
|
||||
public Grid(final float x, float y, final int width, final int depth, final int cellWidth, final int cellDepth) {
|
||||
public Grid(final float x, final float y, final int width, final int depth, final int cellWidth,
|
||||
final int cellDepth) {
|
||||
final int columns = width / cellWidth;
|
||||
final int rows = depth / cellDepth;
|
||||
|
||||
@ -29,10 +30,10 @@ public class Grid {
|
||||
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int column = 0; column < columns; column++) {
|
||||
final int left = x + (columns * cellWidth);
|
||||
final int right = left + cellWidth;
|
||||
final int bottom = y = row * cellDepth;
|
||||
final int top = bottom + cellDepth;
|
||||
final float left = x + (columns * cellWidth);
|
||||
final float right = left + cellWidth;
|
||||
final float bottom = y + (row * cellDepth);
|
||||
final float top = bottom + cellDepth;
|
||||
|
||||
this.cells[(row * columns) + column] = new GridCell(left, right, bottom, top);
|
||||
}
|
||||
|
@ -6,15 +6,15 @@ import java.util.List;
|
||||
import com.etheller.warsmash.util.RenderMathUtils;
|
||||
|
||||
public class GridCell {
|
||||
public final int left;
|
||||
public final int right;
|
||||
public final int bottom;
|
||||
public final int top;
|
||||
public final float left;
|
||||
public final float right;
|
||||
public final float bottom;
|
||||
public final float top;
|
||||
public int plane;
|
||||
final List<ModelInstance> instances;
|
||||
public final boolean visible;
|
||||
|
||||
public GridCell(final int left, final int right, final int bottom, final int top) {
|
||||
public GridCell(final float left, final float right, final float bottom, final float top) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.bottom = bottom;
|
||||
|
@ -93,6 +93,9 @@ public abstract class ModelInstance extends Node {
|
||||
}
|
||||
|
||||
public boolean isVisible(final Camera camera) {
|
||||
if (true) {
|
||||
return true;
|
||||
}
|
||||
final float x = this.worldLocation.x;
|
||||
final float y = this.worldLocation.y;
|
||||
final float z = this.worldLocation.z;
|
||||
|
@ -45,7 +45,7 @@ public class ModelViewer {
|
||||
this.resources = new ArrayList<>();
|
||||
this.fetchCache = new HashMap<>();
|
||||
this.handlers = new HashSet<ResourceHandler>();
|
||||
this.frameTime = 1000 / 6;
|
||||
this.frameTime = 1000 / 60;
|
||||
this.gl = Gdx.gl;
|
||||
this.webGL = new WebGL(this.gl);
|
||||
this.scenes = new ArrayList<>();
|
||||
|
@ -17,7 +17,7 @@ public abstract class Node extends GenericNode {
|
||||
public Node() {
|
||||
this.pivot = new Vector3();
|
||||
this.localLocation = new Vector3();
|
||||
this.localRotation = new Quaternion(0, 0, 0, 1);
|
||||
this.localRotation = new Quaternion();
|
||||
this.localScale = new Vector3(1, 1, 1);
|
||||
this.worldLocation = new Vector3();
|
||||
this.worldRotation = new Quaternion();
|
||||
|
@ -11,7 +11,11 @@ public interface PathSolver {
|
||||
public static final PathSolver DEFAULT = new PathSolver() {
|
||||
@Override
|
||||
public SolvedPath solve(final String src, final Object solverParams) {
|
||||
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
|
||||
final int dotIndex = src.lastIndexOf('.');
|
||||
if (dotIndex == -1) {
|
||||
throw new IllegalStateException("unable to resolve: " + src);
|
||||
}
|
||||
return new SolvedPath(src, src.substring(dotIndex), true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -71,6 +71,11 @@ public abstract class RawOpenGLTextureResource extends Texture {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGlHandle() {
|
||||
return this.handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrapS(final boolean wrapS) {
|
||||
this.wrapS = wrapS ? GL20.GL_REPEAT : GL20.GL_CLAMP_TO_EDGE;
|
||||
|
@ -7,6 +7,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
|
||||
/**
|
||||
@ -43,6 +44,15 @@ public class Scene {
|
||||
public final EmittedObjectUpdater emitterObjectUpdater;
|
||||
public final Map<TextureMapper, RenderBatch> batches;
|
||||
public final Comparator<ModelInstance> instanceDepthComparator;
|
||||
/**
|
||||
* Similar to WebGL's own `alpha` parameter.
|
||||
*
|
||||
* If false, the scene will be cleared before rendering, meaning that scenes
|
||||
* behind it won't be visible through it.
|
||||
*
|
||||
* If true, alpha works as usual.
|
||||
*/
|
||||
public boolean alpha = false;
|
||||
|
||||
public Scene(final ModelViewer viewer) {
|
||||
final CanvasProvider canvas = viewer.canvas;
|
||||
@ -185,8 +195,8 @@ public class Scene {
|
||||
if (cell.isVisible(this.camera)) {
|
||||
this.visibleCells += 1;
|
||||
|
||||
for (int i = 0, l = cell.instances.size(); i < l; i++) {
|
||||
final ModelInstance instance = cell.instances.get(i);
|
||||
for (final ModelInstance instance : new ArrayList<>(cell.instances)) {
|
||||
// final ModelInstance instance = cell.instances.get(i);
|
||||
if (instance.rendered && (instance.cullFrame < frame) && instance.isVisible(this.camera)) {
|
||||
instance.cullFrame = frame;
|
||||
|
||||
@ -232,6 +242,23 @@ public class Scene {
|
||||
this.updatedParticles = this.emitterObjectUpdater.objects.size();
|
||||
}
|
||||
|
||||
public void startFrame() {
|
||||
final GL20 gl = this.viewer.gl;
|
||||
final Rectangle viewport = this.camera.rect;
|
||||
|
||||
// Set the viewport
|
||||
gl.glViewport((int) viewport.x, (int) viewport.y, (int) viewport.width, (int) viewport.height);
|
||||
|
||||
// Allow to render only in the viewport
|
||||
gl.glScissor((int) viewport.x, (int) viewport.y, (int) viewport.width, (int) viewport.height);
|
||||
|
||||
// If this scene doesn't want alpha, clear it.
|
||||
if (!this.alpha) {
|
||||
gl.glDepthMask(true);
|
||||
gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
public void renderOpaque() {
|
||||
final Rectangle viewport = this.camera.rect;
|
||||
this.viewer.gl.glViewport((int) viewport.x, (int) viewport.y, (int) viewport.width, (int) viewport.height);
|
||||
|
@ -85,9 +85,9 @@ public abstract class SkeletalNode extends GenericNode {
|
||||
computedScaling = this.localScale;
|
||||
|
||||
final Vector3 parentScale = this.parent.worldScale;
|
||||
this.worldScale.x = parentScale.x * this.worldScale.x;
|
||||
this.worldScale.y = parentScale.y * this.worldScale.y;
|
||||
this.worldScale.z = parentScale.z * this.worldScale.z;
|
||||
this.worldScale.x = parentScale.x * this.localScale.x;
|
||||
this.worldScale.y = parentScale.y * this.localScale.y;
|
||||
this.worldScale.z = parentScale.z * this.localScale.z;
|
||||
}
|
||||
|
||||
if (this.billboarded) {
|
||||
|
@ -19,6 +19,8 @@ public abstract class Texture extends HandlerResource<ResourceHandler> {
|
||||
|
||||
public abstract int getGlTarget();
|
||||
|
||||
public abstract int getGlHandle();
|
||||
|
||||
public abstract void setWrapS(final boolean wrapS);
|
||||
|
||||
public abstract void setWrapT(final boolean wrapT);
|
||||
|
@ -53,7 +53,7 @@ public class ParticleEmitter2Object extends GenericObject implements EmitterObje
|
||||
this.columns = emitter.getColumns();
|
||||
this.rows = emitter.getRows();
|
||||
|
||||
if (this.replaceableId == 0) {
|
||||
if (replaceableId == 0) {
|
||||
this.internalTexture = model.getTextures().get(emitter.getTextureId());
|
||||
}
|
||||
else if ((replaceableId == 1) || (replaceableId == 2)) {
|
||||
|
@ -1,29 +1,29 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x;
|
||||
|
||||
import com.badlogic.gdx.math.Quaternion;
|
||||
import com.etheller.warsmash.util.MappedDataRow;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||
import com.etheller.warsmash.util.RenderMathUtils;
|
||||
import com.etheller.warsmash.viewer5.BatchedInstance;
|
||||
import com.etheller.warsmash.viewer5.ModelInstance;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||
|
||||
public class Doodad {
|
||||
private final BatchedInstance instance;
|
||||
private final MappedDataRow row;
|
||||
private final ModelInstance instance;
|
||||
private final MutableGameObject row;
|
||||
|
||||
public Doodad(final War3MapViewer map, final MdxModel model, final MappedDataRow row,
|
||||
public Doodad(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
||||
final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad) {
|
||||
final boolean isSimple = ((Number) row.get("lightweight")).intValue() == 1;
|
||||
BatchedInstance instance;
|
||||
final boolean isSimple = row.readSLKTagBoolean("lightweight");
|
||||
ModelInstance instance;
|
||||
|
||||
if (isSimple) {
|
||||
instance = (BatchedInstance) model.addInstance(1);
|
||||
instance = model.addInstance(1);
|
||||
}
|
||||
else {
|
||||
instance = (BatchedInstance) model.addInstance();
|
||||
instance = model.addInstance();
|
||||
}
|
||||
|
||||
instance.move(doodad.getLocation());
|
||||
instance.rotateLocal(new Quaternion().setFromAxis(RenderMathUtils.VEC3_UNIT_Z, doodad.getAngle()));
|
||||
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, doodad.getAngle()));
|
||||
instance.scale(doodad.getScale());
|
||||
instance.setScene(map.worldScene);
|
||||
|
||||
|
@ -0,0 +1,45 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x;
|
||||
|
||||
public class HiveWEShaders {
|
||||
public static final class Cliffs {
|
||||
private Cliffs() {
|
||||
}
|
||||
|
||||
public static final String vert = "#version 450 core\r\n" + //
|
||||
"\r\n" + //
|
||||
"layout (location = 0) in vec3 vPosition;\r\n" + //
|
||||
"layout (location = 1) in vec2 vUV;\r\n" + //
|
||||
"layout (location = 2) in vec3 vNormal;\r\n" + //
|
||||
"layout (location = 3) in vec4 vOffset;\r\n" + //
|
||||
"\r\n" + //
|
||||
"layout (location = 0) uniform mat4 MVP;\r\n" + //
|
||||
"\r\n" + //
|
||||
"layout (binding = 1) uniform sampler2D height_texture;\r\n" + //
|
||||
"\r\n" + //
|
||||
"layout (location = 0) out vec3 UV;\r\n" + //
|
||||
"layout (location = 1) out vec3 Normal;\r\n" + //
|
||||
"layout (location = 2) out vec2 pathing_map_uv;\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" + //
|
||||
" float value = texture(height_texture, (vOffset.xy + vec2(vPosition.x + 192, vPosition.y + 64) / 128) / vec2(size)).r;\r\n"
|
||||
+ //
|
||||
"\r\n" + //
|
||||
" gl_Position = MVP * vec4(vPosition + vec3(vOffset.xy + vec2(1, 0), vOffset.z + value) * 128, 1);\r\n"
|
||||
+ //
|
||||
" UV = vec3(vUV, vOffset.a);\r\n" + //
|
||||
"\r\n" + //
|
||||
" ivec2 height_pos = ivec2(vOffset.xy + vec2(vPosition.x + 128, vPosition.y) / 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" + //
|
||||
" vec3 terrain_normal = normalize(vec3(hL - hR, hD - hU, 2.0));\r\n" + //
|
||||
"\r\n" + //
|
||||
" Normal = terrain_normal;\r\n" + //
|
||||
"}";
|
||||
}
|
||||
}
|
@ -47,6 +47,9 @@ public class StandSequence {
|
||||
|
||||
final int sequencesLeft = filtered.size() - i;
|
||||
final int random = (int) (i + Math.floor(Math.random() * sequencesLeft));
|
||||
if (sequencesLeft <= 0) {
|
||||
return new IndexedSequence(null, 0);
|
||||
}
|
||||
final IndexedSequence sequence = filtered.get(random);
|
||||
|
||||
return sequence;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x;
|
||||
|
||||
import com.badlogic.gdx.math.Quaternion;
|
||||
import com.etheller.warsmash.util.MappedDataRow;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||
import com.etheller.warsmash.util.RenderMathUtils;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxSimpleInstance;
|
||||
@ -9,9 +9,9 @@ import com.etheller.warsmash.viewer5.handlers.mdx.MdxSimpleInstance;
|
||||
public class TerrainDoodad {
|
||||
private static final float[] locationHeap = new float[3];
|
||||
private final MdxSimpleInstance instance;
|
||||
private final MappedDataRow row;
|
||||
private final MutableGameObject row;
|
||||
|
||||
public TerrainDoodad(final War3MapViewer map, final MdxModel model, final MappedDataRow row,
|
||||
public TerrainDoodad(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
||||
final com.etheller.warsmash.parsers.w3x.doo.TerrainDoodad doodad) {
|
||||
final float[] centerOffset = map.centerOffset;
|
||||
final MdxSimpleInstance instance = (MdxSimpleInstance) model.addInstance(1);
|
||||
@ -20,8 +20,7 @@ public class TerrainDoodad {
|
||||
locationHeap[0] = (doodad.getLocation()[1] * 128) + centerOffset[1] + 128;
|
||||
|
||||
instance.move(locationHeap);
|
||||
instance.rotateLocal(
|
||||
new Quaternion().setFromAxis(RenderMathUtils.VEC3_UNIT_Z, ((Number) row.get("fixedRot")).floatValue()));
|
||||
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, row.readSLKTagFloat("fixedRot")));
|
||||
instance.setScene(map.worldScene);
|
||||
|
||||
this.instance = instance;
|
||||
|
@ -19,6 +19,37 @@ import com.etheller.warsmash.util.RenderMathUtils;
|
||||
import com.etheller.warsmash.viewer5.gl.ANGLEInstancedArrays;
|
||||
import com.etheller.warsmash.viewer5.gl.WebGL;
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
PuffTheMagicDragonIsNoMoreToday at 9:06 PM
|
||||
that being said I think we call the tiles corners or whatever, since we store the points rather than the quads
|
||||
but at the same time there's also per-quad data xDS
|
||||
|
||||
ReteraToday at 9:06 PM
|
||||
yeah, I've seen the corner class go by several times while transcribing this latest bit to java
|
||||
hmmm
|
||||
|
||||
PuffTheMagicDragonIsNoMoreToday at 9:07 PM
|
||||
some things are per-corner, some per-tile
|
||||
note that the existing code only somewhat takes care of cliff/terrain doodads, and it's not tested much
|
||||
|
||||
ReteraToday at 9:10 PM
|
||||
well, I'll probably rip some stuff off of HiveWE too
|
||||
that was what I was thinking I'd probably do if it was necessary
|
||||
|
||||
PuffTheMagicDragonIsNoMoreToday at 9:11 PM
|
||||
last time I checked it wasn't implemented there, but that was a long time ago
|
||||
basically you want to not have ground tiles where the doodads exist, and to know where that is you need the pathing texture used by the doodads
|
||||
|
||||
ReteraToday at 9:12 PM
|
||||
oh yea
|
||||
makes sense
|
||||
|
||||
PuffTheMagicDragonIsNoMoreToday at 9:13 PM
|
||||
they also can't be supported by my hacky TerrainModel or whatever it was called, since at least some of them require blending
|
||||
*
|
||||
*/
|
||||
public class TerrainModel {
|
||||
private static final IntBuffer GL_TEMP_BUFFER = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder())
|
||||
.asIntBuffer();
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x;
|
||||
|
||||
import com.badlogic.gdx.math.Quaternion;
|
||||
import com.etheller.warsmash.util.MappedDataRow;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||
import com.etheller.warsmash.util.RenderMathUtils;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||
@ -9,25 +9,34 @@ import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||
public class Unit {
|
||||
private static final float[] heapZ = new float[3];
|
||||
public final MdxComplexInstance instance;
|
||||
public final MappedDataRow row;
|
||||
public final MutableGameObject row;
|
||||
|
||||
public Unit(final War3MapViewer map, final MdxModel model, final MappedDataRow row,
|
||||
public Unit(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
||||
final com.etheller.warsmash.parsers.w3x.unitsdoo.Unit unit) {
|
||||
final MdxComplexInstance instance = (MdxComplexInstance) model.addInstance();
|
||||
|
||||
instance.move(unit.getLocation());
|
||||
instance.rotateLocal(new Quaternion().setFromAxis(RenderMathUtils.VEC3_UNIT_Z, unit.getAngle()));
|
||||
float angle;
|
||||
if ((row != null) && row.readSLKTagBoolean("isBldg")) {
|
||||
angle = (float) Math.toRadians(270.0f);
|
||||
}
|
||||
else {
|
||||
angle = unit.getAngle();
|
||||
}
|
||||
// instance.localRotation.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle);
|
||||
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle));
|
||||
instance.scale(unit.getScale());
|
||||
instance.setTeamColor(unit.getPlayer());
|
||||
instance.setScene(map.worldScene);
|
||||
|
||||
if (row != null) {
|
||||
heapZ[0] = (((Number) row.get("moveHeight")).floatValue());
|
||||
heapZ[2] = row.readSLKTagFloat("moveHeight");
|
||||
|
||||
instance.move(heapZ);
|
||||
instance.setVertexColor(new float[] { ((Number) row.get("red")).intValue() / 255f,
|
||||
((Number) row.get("green")).intValue() / 255f, ((Number) row.get("blue")).intValue() / 255f });
|
||||
instance.uniformScale(((Number) row.get("modelScale")).floatValue());
|
||||
instance.setVertexColor(new float[] { (row.readSLKTagInt("red")) / 255f,
|
||||
(row.readSLKTagInt("green")) / 255f, (row.readSLKTagInt("blue")) / 255f });
|
||||
instance.uniformScale(row.readSLKTagFloat("modelScale"));
|
||||
|
||||
}
|
||||
|
||||
this.instance = instance;
|
||||
|
@ -0,0 +1,154 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Variations {
|
||||
private static final Map<String, Integer> CLIFF_VARS;
|
||||
private static final Map<String, Integer> CITY_CLIFF_VARS;
|
||||
|
||||
static {
|
||||
final Map<String, Integer> cliffVariations = new HashMap<>();
|
||||
cliffVariations.put("AAAB", 1);
|
||||
cliffVariations.put("AAAC", 1);
|
||||
cliffVariations.put("AABA", 1);
|
||||
cliffVariations.put("AABB", 2);
|
||||
cliffVariations.put("AABC", 0);
|
||||
cliffVariations.put("AACA", 1);
|
||||
cliffVariations.put("AACB", 0);
|
||||
cliffVariations.put("AACC", 1);
|
||||
cliffVariations.put("ABAA", 1);
|
||||
cliffVariations.put("ABAB", 1);
|
||||
cliffVariations.put("ABAC", 0);
|
||||
cliffVariations.put("ABBA", 2);
|
||||
cliffVariations.put("ABBB", 1);
|
||||
cliffVariations.put("ABBC", 0);
|
||||
cliffVariations.put("ABCA", 0);
|
||||
cliffVariations.put("ABCB", 0);
|
||||
cliffVariations.put("ABCC", 0);
|
||||
cliffVariations.put("ACAA", 1);
|
||||
cliffVariations.put("ACAB", 0);
|
||||
cliffVariations.put("ACAC", 1);
|
||||
cliffVariations.put("ACBA", 0);
|
||||
cliffVariations.put("ACBB", 0);
|
||||
cliffVariations.put("ACBC", 0);
|
||||
cliffVariations.put("ACCA", 1);
|
||||
cliffVariations.put("ACCB", 0);
|
||||
cliffVariations.put("ACCC", 1);
|
||||
cliffVariations.put("BAAA", 1);
|
||||
cliffVariations.put("BAAB", 1);
|
||||
cliffVariations.put("BAAC", 0);
|
||||
cliffVariations.put("BABA", 1);
|
||||
cliffVariations.put("BABB", 1);
|
||||
cliffVariations.put("BABC", 0);
|
||||
cliffVariations.put("BACA", 0);
|
||||
cliffVariations.put("BACB", 0);
|
||||
cliffVariations.put("BACC", 0);
|
||||
cliffVariations.put("BBAA", 1);
|
||||
cliffVariations.put("BBAB", 1);
|
||||
cliffVariations.put("BBAC", 0);
|
||||
cliffVariations.put("BBBA", 1);
|
||||
cliffVariations.put("BBCA", 0);
|
||||
cliffVariations.put("BCAA", 0);
|
||||
cliffVariations.put("BCAB", 0);
|
||||
cliffVariations.put("BCAC", 0);
|
||||
cliffVariations.put("BCBA", 0);
|
||||
cliffVariations.put("BCCA", 0);
|
||||
cliffVariations.put("CAAA", 1);
|
||||
cliffVariations.put("CAAB", 0);
|
||||
cliffVariations.put("CAAC", 1);
|
||||
cliffVariations.put("CABA", 0);
|
||||
cliffVariations.put("CABB", 0);
|
||||
cliffVariations.put("CABC", 0);
|
||||
cliffVariations.put("CACA", 1);
|
||||
cliffVariations.put("CACB", 0);
|
||||
cliffVariations.put("CACC", 1);
|
||||
cliffVariations.put("CBAA", 0);
|
||||
cliffVariations.put("CBAB", 0);
|
||||
cliffVariations.put("CBAC", 0);
|
||||
cliffVariations.put("CBBA", 0);
|
||||
cliffVariations.put("CBCA", 0);
|
||||
cliffVariations.put("CCAA", 1);
|
||||
cliffVariations.put("CCAB", 0);
|
||||
cliffVariations.put("CCAC", 1);
|
||||
cliffVariations.put("CCBA", 0);
|
||||
cliffVariations.put("CCCA", 1);
|
||||
CLIFF_VARS = cliffVariations;
|
||||
|
||||
final Map<String, Integer> cityCliffVariations = new HashMap<>();
|
||||
cityCliffVariations.put("AAAB", 2);
|
||||
cityCliffVariations.put("AAAC", 1);
|
||||
cityCliffVariations.put("AABA", 1);
|
||||
cityCliffVariations.put("AABB", 3);
|
||||
cityCliffVariations.put("AABC", 0);
|
||||
cityCliffVariations.put("AACA", 1);
|
||||
cityCliffVariations.put("AACB", 0);
|
||||
cityCliffVariations.put("AACC", 3);
|
||||
cityCliffVariations.put("ABAA", 1);
|
||||
cityCliffVariations.put("ABAB", 2);
|
||||
cityCliffVariations.put("ABAC", 0);
|
||||
cityCliffVariations.put("ABBA", 3);
|
||||
cityCliffVariations.put("ABBB", 0);
|
||||
cityCliffVariations.put("ABBC", 0);
|
||||
cityCliffVariations.put("ABCA", 0);
|
||||
cityCliffVariations.put("ABCB", 0);
|
||||
cityCliffVariations.put("ABCC", 0);
|
||||
cityCliffVariations.put("ACAA", 1);
|
||||
cityCliffVariations.put("ACAB", 0);
|
||||
cityCliffVariations.put("ACAC", 2);
|
||||
cityCliffVariations.put("ACBA", 0);
|
||||
cityCliffVariations.put("ACBB", 0);
|
||||
cityCliffVariations.put("ACBC", 0);
|
||||
cityCliffVariations.put("ACCA", 3);
|
||||
cityCliffVariations.put("ACCB", 0);
|
||||
cityCliffVariations.put("ACCC", 1);
|
||||
cityCliffVariations.put("BAAA", 1);
|
||||
cityCliffVariations.put("BAAB", 3);
|
||||
cityCliffVariations.put("BAAC", 0);
|
||||
cityCliffVariations.put("BABA", 2);
|
||||
cityCliffVariations.put("BABB", 0);
|
||||
cityCliffVariations.put("BABC", 0);
|
||||
cityCliffVariations.put("BACA", 0);
|
||||
cityCliffVariations.put("BACB", 0);
|
||||
cityCliffVariations.put("BACC", 0);
|
||||
cityCliffVariations.put("BBAA", 3);
|
||||
cityCliffVariations.put("BBAB", 1);
|
||||
cityCliffVariations.put("BBAC", 0);
|
||||
cityCliffVariations.put("BBBA", 1);
|
||||
cityCliffVariations.put("BBCA", 0);
|
||||
cityCliffVariations.put("BCAA", 0);
|
||||
cityCliffVariations.put("BCAB", 0);
|
||||
cityCliffVariations.put("BCAC", 0);
|
||||
cityCliffVariations.put("BCBA", 0);
|
||||
cityCliffVariations.put("BCCA", 0);
|
||||
cityCliffVariations.put("CAAA", 1);
|
||||
cityCliffVariations.put("CAAB", 0);
|
||||
cityCliffVariations.put("CAAC", 3);
|
||||
cityCliffVariations.put("CABA", 0);
|
||||
cityCliffVariations.put("CABB", 0);
|
||||
cityCliffVariations.put("CABC", 0);
|
||||
cityCliffVariations.put("CACA", 2);
|
||||
cityCliffVariations.put("CACB", 0);
|
||||
cityCliffVariations.put("CACC", 1);
|
||||
cityCliffVariations.put("CBAA", 0);
|
||||
cityCliffVariations.put("CBAB", 0);
|
||||
cityCliffVariations.put("CBAC", 0);
|
||||
cityCliffVariations.put("CBBA", 0);
|
||||
cityCliffVariations.put("CBCA", 0);
|
||||
cityCliffVariations.put("CCAA", 3);
|
||||
cityCliffVariations.put("CCAB", 0);
|
||||
cityCliffVariations.put("CCAC", 1);
|
||||
cityCliffVariations.put("CCBA", 0);
|
||||
cityCliffVariations.put("CCCA", 1);
|
||||
CITY_CLIFF_VARS = cityCliffVariations;
|
||||
}
|
||||
|
||||
public static int getCliffVariation(final String dir, final String tag, final int variation) {
|
||||
if ("Cliffs".equals(dir)) {
|
||||
return Math.min(variation, CLIFF_VARS.get(tag));
|
||||
}
|
||||
else {
|
||||
return Math.min(variation, CITY_CLIFF_VARS.get(tag));
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ public class W3xShaders {
|
||||
"uniform vec2 u_pixel;\r\n" + //
|
||||
"uniform vec2 u_centerOffset;\r\n" + //
|
||||
"attribute vec3 a_position;\r\n" + //
|
||||
"attribute vec3 a_normal;\r\n" + //
|
||||
// "attribute vec3 a_normal;\r\n" + //
|
||||
"attribute vec2 a_uv;\r\n" + //
|
||||
"attribute vec3 a_instancePosition;\r\n" + //
|
||||
"attribute float a_instanceTexture;\r\n" + //
|
||||
@ -25,16 +25,16 @@ public class W3xShaders {
|
||||
" // The bottom left corner of the map tile this vertex is on.\r\n" + //
|
||||
" vec2 corner = floor((a_instancePosition.xy - vec2(1.0, 0.0) - u_centerOffset.xy) / 128.0);\r\n" + //
|
||||
" // Get the 4 closest heights in the height map.\r\n" + //
|
||||
" float bottomLeft = texture2D(u_heightMap, corner * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float bottomRight = texture2D(u_heightMap, (corner + vec2(1.0, 0.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float topLeft = texture2D(u_heightMap, (corner + vec2(0.0, 1.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float topRight = texture2D(u_heightMap, (corner + vec2(1.0, 1.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float bottomLeft = texture2D(u_heightMap, corner * u_pixel + halfPixel).r;\r\n" + //
|
||||
" float bottomRight = texture2D(u_heightMap, (corner + vec2(1.0, 0.0)) * u_pixel + halfPixel).r;\r\n" + //
|
||||
" float topLeft = texture2D(u_heightMap, (corner + vec2(0.0, 1.0)) * u_pixel + halfPixel).r;\r\n" + //
|
||||
" float topRight = texture2D(u_heightMap, (corner + vec2(1.0, 1.0)) * u_pixel + halfPixel).r;\r\n" + //
|
||||
" \r\n" + //
|
||||
" // Do a bilinear interpolation between the heights to get the final value.\r\n" + //
|
||||
" float bottom = mix(bottomRight, bottomLeft, -a_position.x / 128.0);\r\n" + //
|
||||
" float top = mix(topRight, topLeft, -a_position.x / 128.0);\r\n" + //
|
||||
" float height = mix(bottom, top, a_position.y / 128.0);\r\n" + //
|
||||
" v_normal = a_normal;\r\n" + //
|
||||
// " v_normal = a_normal;\r\n" + //
|
||||
" v_uv = a_uv;\r\n" + //
|
||||
" v_texture = a_instanceTexture;\r\n" + //
|
||||
" v_position = a_position + vec3(a_instancePosition.xy, a_instancePosition.z + height * 128.0);\r\n" + //
|
||||
@ -47,7 +47,7 @@ public class W3xShaders {
|
||||
"precision mediump float;\r\n" + //
|
||||
"uniform sampler2D u_texture1;\r\n" + //
|
||||
"uniform sampler2D u_texture2;\r\n" + //
|
||||
"varying vec3 v_normal;\r\n" + //
|
||||
// "varying vec3 v_normal;\r\n" + //
|
||||
"varying vec2 v_uv;\r\n" + //
|
||||
"varying float v_texture;\r\n" + //
|
||||
"varying vec3 v_position;\r\n" + //
|
||||
@ -81,35 +81,35 @@ public class W3xShaders {
|
||||
"varying vec3 v_normal;\r\n" + //
|
||||
"const vec3 lightDirection = normalize(vec3(-0.3, -0.3, 0.25));\r\n" + //
|
||||
"vec4 sample(float tileset, vec2 uv) {\r\n" + //
|
||||
" if (tileset == 0.0) {\r\n" + //
|
||||
" if (tileset <= 0.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[0], uv);\r\n" + //
|
||||
" } else if (tileset == 1.0) {\r\n" + //
|
||||
" } else if (tileset <= 1.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[1], uv);\r\n" + //
|
||||
" } else if (tileset == 2.0) {\r\n" + //
|
||||
" } else if (tileset <= 2.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[2], uv);\r\n" + //
|
||||
" } else if (tileset == 3.0) {\r\n" + //
|
||||
" } else if (tileset <= 3.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[3], uv);\r\n" + //
|
||||
" } else if (tileset == 4.0) {\r\n" + //
|
||||
" } else if (tileset <= 4.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[4], uv);\r\n" + //
|
||||
" } else if (tileset == 5.0) {\r\n" + //
|
||||
" } else if (tileset <= 5.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[5], uv);\r\n" + //
|
||||
" } else if (tileset == 6.0) {\r\n" + //
|
||||
" } else if (tileset <= 6.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[6], uv);\r\n" + //
|
||||
" } else if (tileset == 7.0) {\r\n" + //
|
||||
" } else if (tileset <= 7.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[7], uv);\r\n" + //
|
||||
" } else if (tileset == 8.0) {\r\n" + //
|
||||
" } else if (tileset <= 8.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[8], uv);\r\n" + //
|
||||
" } else if (tileset == 9.0) {\r\n" + //
|
||||
" } else if (tileset <= 9.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[9], uv);\r\n" + //
|
||||
" } else if (tileset == 10.0) {\r\n" + //
|
||||
" } else if (tileset <= 10.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[10], uv);\r\n" + //
|
||||
" } else if (tileset == 11.0) {\r\n" + //
|
||||
" } else if (tileset <= 11.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[11], uv);\r\n" + //
|
||||
" } else if (tileset == 12.0) {\r\n" + //
|
||||
" } else if (tileset <= 12.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[12], uv);\r\n" + //
|
||||
" } else if (tileset == 13.0) {\r\n" + //
|
||||
" } else if (tileset <= 13.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[13], uv);\r\n" + //
|
||||
" } else if (tileset == 14.0) {\r\n" + //
|
||||
" } else if (tileset <= 14.5) {\r\n" + //
|
||||
" return texture2D(u_tilesets[14], uv);\r\n" + //
|
||||
" }\r\n" + //
|
||||
"}\r\n" + //
|
||||
@ -130,45 +130,66 @@ public class W3xShaders {
|
||||
" }\r\n" + //
|
||||
" // color *= clamp(dot(v_normal, lightDirection) + 0.45, 0.0, 1.0);\r\n" + //
|
||||
" gl_FragColor = color;\r\n" + //
|
||||
"}\r\n" + //
|
||||
"";
|
||||
"}";
|
||||
|
||||
public static final String vert = "\r\n" + //
|
||||
"uniform mat4 u_VP;\r\n" + //
|
||||
"uniform sampler2D u_heightMap;\r\n" + //
|
||||
"uniform vec2 u_pixel;\r\n" + //
|
||||
"uniform vec2 u_centerOffset;\r\n" + //
|
||||
"attribute vec3 a_position;\r\n" + //
|
||||
"attribute vec3 a_normal;\r\n" + //
|
||||
"attribute vec2 a_uv;\r\n" + //
|
||||
"attribute vec3 a_instancePosition;\r\n" + //
|
||||
"attribute float a_instanceTexture;\r\n" + //
|
||||
"uniform vec2 u_size;\r\n" + //
|
||||
"uniform vec2 u_offset;\r\n" + //
|
||||
"uniform bool u_extended[14];\r\n" + //
|
||||
"uniform float u_baseTileset;\r\n" + //
|
||||
"attribute vec2 a_position;\r\n" + //
|
||||
"attribute float a_InstanceID;\r\n" + //
|
||||
"attribute vec4 a_textures;\r\n" + //
|
||||
"attribute vec4 a_variations;\r\n" + //
|
||||
"varying vec4 v_tilesets;\r\n" + //
|
||||
"varying vec2 v_uv[4];\r\n" + //
|
||||
"varying vec3 v_normal;\r\n" + //
|
||||
"varying vec2 v_uv;\r\n" + //
|
||||
"varying float v_texture;\r\n" + //
|
||||
"varying vec3 v_position;\r\n" + //
|
||||
"void main() {\r\n" + //
|
||||
" // Half of a pixel in the cliff height map.\r\n" + //
|
||||
" vec2 halfPixel = u_pixel * 0.5;\r\n" + //
|
||||
" // The bottom left corner of the map tile this vertex is on.\r\n" + //
|
||||
" vec2 corner = floor((a_instancePosition.xy - vec2(1.0, 0.0) - u_centerOffset.xy) / 128.0);\r\n" + //
|
||||
" // Get the 4 closest heights in the height map.\r\n" + //
|
||||
" float bottomLeft = texture2D(u_heightMap, corner * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float bottomRight = texture2D(u_heightMap, (corner + vec2(1.0, 0.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float topLeft = texture2D(u_heightMap, (corner + vec2(0.0, 1.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float topRight = texture2D(u_heightMap, (corner + vec2(1.0, 1.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" \r\n" + //
|
||||
" // Do a bilinear interpolation between the heights to get the final value.\r\n" + //
|
||||
" float bottom = mix(bottomRight, bottomLeft, -a_position.x / 128.0);\r\n" + //
|
||||
" float top = mix(topRight, topLeft, -a_position.x / 128.0);\r\n" + //
|
||||
" float height = mix(bottom, top, a_position.y / 128.0);\r\n" + //
|
||||
" v_normal = a_normal;\r\n" + //
|
||||
" v_uv = a_uv;\r\n" + //
|
||||
" v_texture = a_instanceTexture;\r\n" + //
|
||||
" v_position = a_position + vec3(a_instancePosition.xy, a_instancePosition.z + height * 128.0);\r\n" + //
|
||||
" gl_Position = u_VP * vec4(v_position, 1.0);\r\n" + //
|
||||
"vec2 getCell(float variation) {\r\n" + //
|
||||
" if (variation < 16.0) {\r\n" + //
|
||||
" return vec2(mod(variation, 4.0), floor(variation / 4.0));\r\n" + //
|
||||
" } else {\r\n" + //
|
||||
" variation -= 16.0;\r\n" + //
|
||||
" return vec2(4.0 + mod(variation, 4.0), floor(variation / 4.0));\r\n" + //
|
||||
" }\r\n" + //
|
||||
"}\r\n" + //
|
||||
"";
|
||||
"vec2 getUV(vec2 position, bool extended, float variation) {\r\n" + //
|
||||
" vec2 cell = getCell(variation);\r\n" + //
|
||||
" vec2 cellSize = vec2(extended ? 0.125 : 0.25, 0.25);\r\n" + //
|
||||
" vec2 uv = vec2(position.x, 1.0 - position.y);\r\n" + //
|
||||
" vec2 pixelSize = vec2(1.0 / 512.0, 1.0 / 256.0); /// Note: hardcoded to 512x256 for now.\r\n" + //
|
||||
" return clamp((cell + uv) * cellSize, cell * cellSize + pixelSize, (cell + 1.0) * cellSize - pixelSize); \r\n"
|
||||
+ //
|
||||
"}\r\n" + //
|
||||
"void main() {\r\n" + //
|
||||
" vec4 textures = a_textures - u_baseTileset;\r\n" + //
|
||||
" \r\n" + //
|
||||
" if (textures[0] > 0.0 || textures[1] > 0.0 || textures[2] > 0.0 || textures[3] > 0.0) {\r\n" + //
|
||||
" v_tilesets = textures;\r\n" + //
|
||||
" v_uv[0] = getUV(a_position, u_extended[int(textures[0]) - 1], a_variations[0]);\r\n" + //
|
||||
" v_uv[1] = getUV(a_position, u_extended[int(textures[1]) - 1], a_variations[1]);\r\n" + //
|
||||
" v_uv[2] = getUV(a_position, u_extended[int(textures[2]) - 1], a_variations[2]);\r\n" + //
|
||||
" v_uv[3] = getUV(a_position, u_extended[int(textures[3]) - 1], a_variations[3]);\r\n" + //
|
||||
" vec2 corner = vec2(mod(a_InstanceID, u_size.x), floor(a_InstanceID / u_size.x));\r\n" + //
|
||||
" vec2 base = corner + a_position;\r\n" + //
|
||||
" float height = texture2D(u_heightMap, base / u_size).r;\r\n" + //
|
||||
" float hL = texture2D(u_heightMap, vec2(base - vec2(1.0, 0.0)) / (u_size)).r;\r\n" + //
|
||||
" float hR = texture2D(u_heightMap, vec2(base + vec2(1.0, 0.0)) / (u_size)).r;\r\n" + //
|
||||
" float hD = texture2D(u_heightMap, vec2(base - vec2(0.0, 1.0)) / (u_size)).r;\r\n" + //
|
||||
" float hU = texture2D(u_heightMap, vec2(base + vec2(0.0, 1.0)) / (u_size)).r;\r\n" + //
|
||||
" v_normal = normalize(vec3(hL - hR, hD - hU, 2.0));\r\n" + //
|
||||
" gl_Position = u_VP * vec4(base * 128.0 + u_offset, height * 128.0, 1.0);\r\n" + //
|
||||
" } else {\r\n" + //
|
||||
" v_tilesets = vec4(0.0);\r\n" + //
|
||||
" v_uv[0] = vec2(0.0);\r\n" + //
|
||||
" v_uv[1] = vec2(0.0);\r\n" + //
|
||||
" v_uv[2] = vec2(0.0);\r\n" + //
|
||||
" v_uv[3] = vec2(0.0);\r\n" + //
|
||||
" v_normal = vec3(0.0);\r\n" + //
|
||||
" gl_Position = vec4(0.0);\r\n" + //
|
||||
" }\r\n" + //
|
||||
"}";
|
||||
}
|
||||
|
||||
public static final class Water {
|
||||
@ -208,8 +229,8 @@ public class W3xShaders {
|
||||
" v_uv = a_position;\r\n" + //
|
||||
" vec2 corner = vec2(mod(a_InstanceID, u_size.x), floor(a_InstanceID / u_size.x));\r\n" + //
|
||||
" vec2 base = corner + a_position;\r\n" + //
|
||||
" float height = texture2D(u_heightMap, base / u_size).a;\r\n" + //
|
||||
" float waterHeight = texture2D(u_waterHeightMap, base / u_size).a + u_offsetHeight;\r\n" + //
|
||||
" float height = texture2D(u_heightMap, base / u_size).r;\r\n" + //
|
||||
" float waterHeight = texture2D(u_waterHeightMap, base / u_size).r + u_offsetHeight;\r\n" + //
|
||||
" float value = clamp(waterHeight - height, 0.0, 1.0);\r\n" + //
|
||||
" if (value <= deepLevel) {\r\n" + //
|
||||
" value = max(0.0, value - minDepth) / (deepLevel - minDepth);\r\n" + //
|
||||
|
@ -0,0 +1,230 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x;
|
||||
|
||||
public class W3xShadersWebGLDeprecated {
|
||||
public static final class Cliffs {
|
||||
private Cliffs() {
|
||||
}
|
||||
|
||||
public static final String vert = "\r\n" + //
|
||||
"uniform mat4 u_VP;\r\n" + //
|
||||
"uniform sampler2D u_heightMap;\r\n" + //
|
||||
"uniform vec2 u_pixel;\r\n" + //
|
||||
"uniform vec2 u_centerOffset;\r\n" + //
|
||||
"attribute vec3 a_position;\r\n" + //
|
||||
"attribute vec3 a_normal;\r\n" + //
|
||||
"attribute vec2 a_uv;\r\n" + //
|
||||
"attribute vec3 a_instancePosition;\r\n" + //
|
||||
"attribute float a_instanceTexture;\r\n" + //
|
||||
"varying vec3 v_normal;\r\n" + //
|
||||
"varying vec2 v_uv;\r\n" + //
|
||||
"varying float v_texture;\r\n" + //
|
||||
"varying vec3 v_position;\r\n" + //
|
||||
"void main() {\r\n" + //
|
||||
" // Half of a pixel in the cliff height map.\r\n" + //
|
||||
" vec2 halfPixel = u_pixel * 0.5;\r\n" + //
|
||||
" // The bottom left corner of the map tile this vertex is on.\r\n" + //
|
||||
" vec2 corner = floor((a_instancePosition.xy - vec2(1.0, 0.0) - u_centerOffset.xy) / 128.0);\r\n" + //
|
||||
" // Get the 4 closest heights in the height map.\r\n" + //
|
||||
" float bottomLeft = texture2D(u_heightMap, corner * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float bottomRight = texture2D(u_heightMap, (corner + vec2(1.0, 0.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float topLeft = texture2D(u_heightMap, (corner + vec2(0.0, 1.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float topRight = texture2D(u_heightMap, (corner + vec2(1.0, 1.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" \r\n" + //
|
||||
" // Do a bilinear interpolation between the heights to get the final value.\r\n" + //
|
||||
" float bottom = mix(bottomRight, bottomLeft, -a_position.x / 128.0);\r\n" + //
|
||||
" float top = mix(topRight, topLeft, -a_position.x / 128.0);\r\n" + //
|
||||
" float height = mix(bottom, top, a_position.y / 128.0);\r\n" + //
|
||||
" v_normal = a_normal;\r\n" + //
|
||||
" v_uv = a_uv;\r\n" + //
|
||||
" v_texture = a_instanceTexture;\r\n" + //
|
||||
" v_position = a_position + vec3(a_instancePosition.xy, a_instancePosition.z + height * 128.0);\r\n" + //
|
||||
" gl_Position = u_VP * vec4(v_position, 1.0);\r\n" + //
|
||||
"}\r\n" + //
|
||||
"";
|
||||
|
||||
public static final String frag = "\r\n" + //
|
||||
"// #extension GL_OES_standard_derivatives : enable\r\n" + //
|
||||
"precision mediump float;\r\n" + //
|
||||
"uniform sampler2D u_texture1;\r\n" + //
|
||||
"uniform sampler2D u_texture2;\r\n" + //
|
||||
"varying vec3 v_normal;\r\n" + //
|
||||
"varying vec2 v_uv;\r\n" + //
|
||||
"varying float v_texture;\r\n" + //
|
||||
"varying vec3 v_position;\r\n" + //
|
||||
"// const vec3 lightDirection = normalize(vec3(-0.3, -0.3, 0.25));\r\n" + //
|
||||
"vec4 sample(int texture, vec2 uv) {\r\n" + //
|
||||
" if (texture == 0) {\r\n" + //
|
||||
" return texture2D(u_texture1, uv);\r\n" + //
|
||||
" } else {\r\n" + //
|
||||
" return texture2D(u_texture2, uv);\r\n" + //
|
||||
" }\r\n" + //
|
||||
"}\r\n" + //
|
||||
"void main() {\r\n" + //
|
||||
" vec4 color = sample(int(v_texture), v_uv);\r\n" + //
|
||||
" // vec3 faceNormal = cross(dFdx(v_position), dFdy(v_position));\r\n" + //
|
||||
" // vec3 normal = normalize((faceNormal + v_normal) * 0.5);\r\n" + //
|
||||
" // color *= clamp(dot(normal, lightDirection) + 0.45, 0.1, 1.0);\r\n" + //
|
||||
" gl_FragColor = color;\r\n" + //
|
||||
"}\r\n" + //
|
||||
"";
|
||||
}
|
||||
|
||||
public static final class Ground {
|
||||
private Ground() {
|
||||
}
|
||||
|
||||
public static final String frag = "\r\n" + //
|
||||
"precision mediump float;\r\n" + //
|
||||
"uniform sampler2D u_tilesets[15];\r\n" + //
|
||||
"varying vec4 v_tilesets;\r\n" + //
|
||||
"varying vec2 v_uv[4];\r\n" + //
|
||||
"varying vec3 v_normal;\r\n" + //
|
||||
"const vec3 lightDirection = normalize(vec3(-0.3, -0.3, 0.25));\r\n" + //
|
||||
"vec4 sample(float tileset, vec2 uv) {\r\n" + //
|
||||
" if (tileset == 0.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[0], uv);\r\n" + //
|
||||
" } else if (tileset == 1.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[1], uv);\r\n" + //
|
||||
" } else if (tileset == 2.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[2], uv);\r\n" + //
|
||||
" } else if (tileset == 3.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[3], uv);\r\n" + //
|
||||
" } else if (tileset == 4.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[4], uv);\r\n" + //
|
||||
" } else if (tileset == 5.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[5], uv);\r\n" + //
|
||||
" } else if (tileset == 6.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[6], uv);\r\n" + //
|
||||
" } else if (tileset == 7.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[7], uv);\r\n" + //
|
||||
" } else if (tileset == 8.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[8], uv);\r\n" + //
|
||||
" } else if (tileset == 9.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[9], uv);\r\n" + //
|
||||
" } else if (tileset == 10.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[10], uv);\r\n" + //
|
||||
" } else if (tileset == 11.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[11], uv);\r\n" + //
|
||||
" } else if (tileset == 12.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[12], uv);\r\n" + //
|
||||
" } else if (tileset == 13.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[13], uv);\r\n" + //
|
||||
" } else if (tileset == 14.0) {\r\n" + //
|
||||
" return texture2D(u_tilesets[14], uv);\r\n" + //
|
||||
" }\r\n" + //
|
||||
"}\r\n" + //
|
||||
"vec4 blend(vec4 color, float tileset, vec2 uv) {\r\n" + //
|
||||
" vec4 texel = sample(tileset, uv);\r\n" + //
|
||||
" return mix(color, texel, texel.a);\r\n" + //
|
||||
"}\r\n" + //
|
||||
"void main() {\r\n" + //
|
||||
" vec4 color = sample(v_tilesets[0] - 1.0, v_uv[0]);\r\n" + //
|
||||
" if (v_tilesets[1] > 0.5) {\r\n" + //
|
||||
" color = blend(color, v_tilesets[1] - 1.0, v_uv[1]);\r\n" + //
|
||||
" }\r\n" + //
|
||||
" if (v_tilesets[2] > 0.5) {\r\n" + //
|
||||
" color = blend(color, v_tilesets[2] - 1.0, v_uv[2]);\r\n" + //
|
||||
" }\r\n" + //
|
||||
" if (v_tilesets[3] > 0.5) {\r\n" + //
|
||||
" color = blend(color, v_tilesets[3] - 1.0, v_uv[3]);\r\n" + //
|
||||
" }\r\n" + //
|
||||
" // color *= clamp(dot(v_normal, lightDirection) + 0.45, 0.0, 1.0);\r\n" + //
|
||||
" gl_FragColor = color;\r\n" + //
|
||||
"}\r\n" + //
|
||||
"";
|
||||
|
||||
public static final String vert = "\r\n" + //
|
||||
"uniform mat4 u_VP;\r\n" + //
|
||||
"uniform sampler2D u_heightMap;\r\n" + //
|
||||
"uniform vec2 u_pixel;\r\n" + //
|
||||
"uniform vec2 u_centerOffset;\r\n" + //
|
||||
"attribute vec3 a_position;\r\n" + //
|
||||
"attribute vec3 a_normal;\r\n" + //
|
||||
"attribute vec2 a_uv;\r\n" + //
|
||||
"attribute vec3 a_instancePosition;\r\n" + //
|
||||
"attribute float a_instanceTexture;\r\n" + //
|
||||
"varying vec3 v_normal;\r\n" + //
|
||||
"varying vec2 v_uv;\r\n" + //
|
||||
"varying float v_texture;\r\n" + //
|
||||
"varying vec3 v_position;\r\n" + //
|
||||
"void main() {\r\n" + //
|
||||
" // Half of a pixel in the cliff height map.\r\n" + //
|
||||
" vec2 halfPixel = u_pixel * 0.5;\r\n" + //
|
||||
" // The bottom left corner of the map tile this vertex is on.\r\n" + //
|
||||
" vec2 corner = floor((a_instancePosition.xy - vec2(1.0, 0.0) - u_centerOffset.xy) / 128.0);\r\n" + //
|
||||
" // Get the 4 closest heights in the height map.\r\n" + //
|
||||
" float bottomLeft = texture2D(u_heightMap, corner * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float bottomRight = texture2D(u_heightMap, (corner + vec2(1.0, 0.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float topLeft = texture2D(u_heightMap, (corner + vec2(0.0, 1.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" float topRight = texture2D(u_heightMap, (corner + vec2(1.0, 1.0)) * u_pixel + halfPixel).a;\r\n" + //
|
||||
" \r\n" + //
|
||||
" // Do a bilinear interpolation between the heights to get the final value.\r\n" + //
|
||||
" float bottom = mix(bottomRight, bottomLeft, -a_position.x / 128.0);\r\n" + //
|
||||
" float top = mix(topRight, topLeft, -a_position.x / 128.0);\r\n" + //
|
||||
" float height = mix(bottom, top, a_position.y / 128.0);\r\n" + //
|
||||
" v_normal = a_normal;\r\n" + //
|
||||
" v_uv = a_uv;\r\n" + //
|
||||
" v_texture = a_instanceTexture;\r\n" + //
|
||||
" v_position = a_position + vec3(a_instancePosition.xy, a_instancePosition.z + height * 128.0);\r\n" + //
|
||||
" gl_Position = u_VP * vec4(v_position, 1.0);\r\n" + //
|
||||
"}\r\n" + //
|
||||
"";
|
||||
}
|
||||
|
||||
public static final class Water {
|
||||
private Water() {
|
||||
}
|
||||
|
||||
public static final String frag = "\r\n" + //
|
||||
"precision mediump float;\r\n" + //
|
||||
"uniform sampler2D u_waterTexture;\r\n" + //
|
||||
"varying vec2 v_uv;\r\n" + //
|
||||
"varying vec4 v_color;\r\n" + //
|
||||
"void main() {\r\n" + //
|
||||
" gl_FragColor = texture2D(u_waterTexture, v_uv) * v_color;\r\n" + //
|
||||
"}\r\n" + //
|
||||
"";
|
||||
public static final String vert = "\r\n" + //
|
||||
"uniform mat4 u_VP;\r\n" + //
|
||||
"uniform sampler2D u_heightMap;\r\n" + //
|
||||
"uniform sampler2D u_waterHeightMap;\r\n" + //
|
||||
"uniform vec2 u_size;\r\n" + //
|
||||
"uniform vec2 u_offset;\r\n" + //
|
||||
"uniform float u_offsetHeight;\r\n" + //
|
||||
"uniform vec4 u_minDeepColor;\r\n" + //
|
||||
"uniform vec4 u_maxDeepColor;\r\n" + //
|
||||
"uniform vec4 u_minShallowColor;\r\n" + //
|
||||
"uniform vec4 u_maxShallowColor;\r\n" + //
|
||||
"attribute vec2 a_position;\r\n" + //
|
||||
"attribute float a_InstanceID;\r\n" + //
|
||||
"attribute float a_isWater;\r\n" + //
|
||||
"varying vec2 v_uv;\r\n" + //
|
||||
"varying vec4 v_color;\r\n" + //
|
||||
"const float minDepth = 10.0 / 128.0;\r\n" + //
|
||||
"const float deepLevel = 64.0 / 128.0;\r\n" + //
|
||||
"const float maxDepth = 72.0 / 128.0;\r\n" + //
|
||||
"void main() {\r\n" + //
|
||||
" if (a_isWater > 0.5) {\r\n" + //
|
||||
" v_uv = a_position;\r\n" + //
|
||||
" vec2 corner = vec2(mod(a_InstanceID, u_size.x), floor(a_InstanceID / u_size.x));\r\n" + //
|
||||
" vec2 base = corner + a_position;\r\n" + //
|
||||
" float height = texture2D(u_heightMap, base / u_size).a;\r\n" + //
|
||||
" float waterHeight = texture2D(u_waterHeightMap, base / u_size).a + u_offsetHeight;\r\n" + //
|
||||
" float value = clamp(waterHeight - height, 0.0, 1.0);\r\n" + //
|
||||
" if (value <= deepLevel) {\r\n" + //
|
||||
" value = max(0.0, value - minDepth) / (deepLevel - minDepth);\r\n" + //
|
||||
" v_color = mix(u_minShallowColor, u_maxShallowColor, value) / 255.0;\r\n" + //
|
||||
" } else {\r\n" + //
|
||||
" value = clamp(value - deepLevel, 0.0, maxDepth - deepLevel) / (maxDepth - deepLevel);\r\n" + //
|
||||
" v_color = mix(u_minDeepColor, u_maxDeepColor, value) / 255.0;\r\n" + //
|
||||
" }\r\n" + //
|
||||
" gl_Position = u_VP * vec4(base * 128.0 + u_offset, waterHeight * 128.0, 1.0);\r\n" + //
|
||||
" } else {\r\n" + //
|
||||
" v_uv = vec2(0.0);\r\n" + //
|
||||
" v_color = vec4(0.0);\r\n" + //
|
||||
" gl_Position = vec4(0.0);\r\n" + //
|
||||
" }\r\n" + //
|
||||
"}\r\n" + //
|
||||
"";
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.GL30;
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.etheller.warsmash.common.FetchDataTypeName;
|
||||
@ -21,12 +22,16 @@ import com.etheller.warsmash.datasources.DataSource;
|
||||
import com.etheller.warsmash.parsers.w3x.War3Map;
|
||||
import com.etheller.warsmash.parsers.w3x.doo.War3MapDoo;
|
||||
import com.etheller.warsmash.parsers.w3x.objectdata.Warcraft3MapObjectData;
|
||||
import com.etheller.warsmash.parsers.w3x.unitsdoo.War3MapUnitsDoo;
|
||||
import com.etheller.warsmash.parsers.w3x.w3e.Corner;
|
||||
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.units.StandardObjectData;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
||||
import com.etheller.warsmash.util.MappedData;
|
||||
import com.etheller.warsmash.util.MappedDataRow;
|
||||
import com.etheller.warsmash.util.RenderMathUtils;
|
||||
@ -34,28 +39,34 @@ import com.etheller.warsmash.util.War3ID;
|
||||
import com.etheller.warsmash.viewer5.CanvasProvider;
|
||||
import com.etheller.warsmash.viewer5.GenericResource;
|
||||
import com.etheller.warsmash.viewer5.Grid;
|
||||
import com.etheller.warsmash.viewer5.ModelInstance;
|
||||
import com.etheller.warsmash.viewer5.ModelViewer;
|
||||
import com.etheller.warsmash.viewer5.PathSolver;
|
||||
import com.etheller.warsmash.viewer5.Scene;
|
||||
import com.etheller.warsmash.viewer5.Texture;
|
||||
import com.etheller.warsmash.viewer5.gl.ANGLEInstancedArrays;
|
||||
import com.etheller.warsmash.viewer5.gl.WebGL;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||
|
||||
public class War3MapViewer extends ModelViewer {
|
||||
private static final float[] sizeHeap = new float[2];
|
||||
private static final War3ID sloc = War3ID.fromString("sloc");
|
||||
private static final LoadGenericCallback stringDataCallback = new StringDataCallbackImplementation();
|
||||
private static final StreamDataCallbackImplementation streamDataCallback = new StreamDataCallbackImplementation();
|
||||
|
||||
private static final Vector3 normalHeap1 = new Vector3();
|
||||
private static final Vector3 normalHeap2 = new Vector3();
|
||||
|
||||
public PathSolver wc3PathSolver;
|
||||
public PathSolver wc3PathSolver = PathSolver.DEFAULT;
|
||||
public SolverParams solverParams = new SolverParams();
|
||||
public ShaderProgram groundShader;
|
||||
public ShaderProgram waterShader;
|
||||
public ShaderProgram cliffShader;
|
||||
public Scene worldScene;
|
||||
public int waterIndex;
|
||||
public int waterIncreasePerFrame;
|
||||
public float waterIndex;
|
||||
public float waterIncreasePerFrame;
|
||||
public float waterHeightOffset;
|
||||
public List<Texture> waterTextures = new ArrayList<>();
|
||||
public float[] maxDeepColor = new float[4];
|
||||
@ -85,7 +96,7 @@ public class War3MapViewer extends ModelViewer {
|
||||
public List<Texture> cliffTextures = new ArrayList<>();
|
||||
public List<TerrainModel> cliffModels = new ArrayList<>();
|
||||
public War3Map mapMpq;
|
||||
public PathSolver mapPathSolver;
|
||||
public PathSolver mapPathSolver = PathSolver.DEFAULT;
|
||||
public Corner[][] corners;
|
||||
public float[] centerOffset = new float[2];
|
||||
public int[] mapSize = new int[2];
|
||||
@ -126,11 +137,11 @@ public class War3MapViewer extends ModelViewer {
|
||||
}
|
||||
|
||||
public void loadSLKs() {
|
||||
final GenericResource terrain = this.loadMapGeneric("Terrain\\Terrain.slk", FetchDataTypeName.SLK,
|
||||
final GenericResource terrain = this.loadMapGeneric("TerrainArt\\Terrain.slk", FetchDataTypeName.SLK,
|
||||
stringDataCallback);
|
||||
final GenericResource cliffTypes = this.loadMapGeneric("Terrain\\CliffTypes.slk", FetchDataTypeName.SLK,
|
||||
final GenericResource cliffTypes = this.loadMapGeneric("TerrainArt\\CliffTypes.slk", FetchDataTypeName.SLK,
|
||||
stringDataCallback);
|
||||
final GenericResource water = this.loadMapGeneric("Terrain\\Water.slk", FetchDataTypeName.SLK,
|
||||
final GenericResource water = this.loadMapGeneric("TerrainArt\\Water.slk", FetchDataTypeName.SLK,
|
||||
stringDataCallback);
|
||||
|
||||
// == when loaded, which is always in our system ==
|
||||
@ -190,6 +201,9 @@ public class War3MapViewer extends ModelViewer {
|
||||
final War3Map war3Map = new War3Map(this.gameDataSource, mapFilePath);
|
||||
|
||||
this.mapMpq = war3Map;
|
||||
setDataSource(war3Map.getCompoundDataSource());
|
||||
|
||||
// loadSLKs();
|
||||
|
||||
final PathSolver wc3PathSolver = this.wc3PathSolver;
|
||||
|
||||
@ -245,8 +259,9 @@ public class War3MapViewer extends ModelViewer {
|
||||
final MappedDataRow row = this.terrainData.getRow(groundTile.asStringValue());
|
||||
|
||||
this.tilesets.add(row);
|
||||
this.tilesetTextures.add((Texture) this
|
||||
.load(row.get("dir").toString() + "\\" + row.get("file") + texturesExt, null, this.solverParams));
|
||||
this.tilesetTextures
|
||||
.add((Texture) this.load(row.get("dir").toString() + "\\" + row.get("file") + texturesExt,
|
||||
this.mapPathSolver, this.solverParams));
|
||||
}
|
||||
|
||||
final StandardObjectData standardObjectData = new StandardObjectData(this.mapMpq.getCompoundDataSource());
|
||||
@ -254,8 +269,9 @@ public class War3MapViewer extends ModelViewer {
|
||||
final Element tilesets = worldEditData.get("TileSets");
|
||||
|
||||
this.blightTextureIndex = this.tilesetTextures.size();
|
||||
this.tilesetTextures.add((Texture) this.load(tilesets.getField(Character.toString(tileset)) + texturesExt, null,
|
||||
this.solverParams));
|
||||
this.tilesetTextures
|
||||
.add((Texture) this.load(tilesets.getField(Character.toString(tileset)).split(",")[1] + texturesExt,
|
||||
this.mapPathSolver, this.solverParams));
|
||||
|
||||
for (final War3ID cliffTile : w3e.getCliffTiles()) {
|
||||
final MappedDataRow row = this.cliffTypesData.getRow(cliffTile.asStringValue());
|
||||
@ -263,13 +279,13 @@ public class War3MapViewer extends ModelViewer {
|
||||
this.cliffTilesets.add(row);
|
||||
this.cliffTextures
|
||||
.add((Texture) this.load(row.get("texDir").toString() + "\\" + row.get("texFile") + texturesExt,
|
||||
null, this.solverParams));
|
||||
this.mapPathSolver, this.solverParams));
|
||||
}
|
||||
|
||||
final MappedDataRow waterRow = this.waterData.getRow(tileset + "Sha");
|
||||
|
||||
this.waterHeightOffset = ((Number) waterRow.get("height")).floatValue();
|
||||
this.waterIncreasePerFrame = ((Number) waterRow.get("texRate")).intValue() / 60;
|
||||
this.waterIncreasePerFrame = ((Number) waterRow.get("texRate")).intValue() / (float) 60;
|
||||
this.waterTextures.clear();
|
||||
this.maxDeepColor[0] = ((Number) waterRow.get("Dmax_R")).floatValue();
|
||||
this.maxDeepColor[1] = ((Number) waterRow.get("Dmax_G")).floatValue();
|
||||
@ -291,7 +307,7 @@ public class War3MapViewer extends ModelViewer {
|
||||
for (int i = 0, l = ((Number) waterRow.get("numTex")).intValue(); i < l; i++) {
|
||||
this.waterTextures.add(
|
||||
(Texture) this.load(waterRow.get("texFile").toString() + ((i < 10) ? "0" : "") + i + texturesExt,
|
||||
null, this.solverParams));
|
||||
this.mapPathSolver, this.solverParams));
|
||||
}
|
||||
|
||||
final GL20 gl = this.gl;
|
||||
@ -307,7 +323,7 @@ public class War3MapViewer extends ModelViewer {
|
||||
final short[] cornerTextures = new short[instanceCount * 4];
|
||||
final short[] cornerVariations = new short[instanceCount * 4];
|
||||
final short[] waterFlags = new short[instanceCount];
|
||||
final int instance = 0;
|
||||
int instance = 0;
|
||||
final Map<String, CliffInfo> cliffs = new HashMap<>();
|
||||
|
||||
this.columns = columns - 1;
|
||||
@ -339,7 +355,7 @@ public class War3MapViewer extends ModelViewer {
|
||||
topRightLayer, base);
|
||||
|
||||
if (!"AAAA".equals(fileName)) {
|
||||
final int cliffTexture = bottomLeft.getCliffTexture();
|
||||
int cliffTexture = bottomLeft.getCliffTexture();
|
||||
|
||||
// ?
|
||||
if (cliffTexture == 15) {
|
||||
@ -349,7 +365,8 @@ public class War3MapViewer extends ModelViewer {
|
||||
final MappedDataRow cliffRow = this.cliffTilesets.get(cliffTexture);
|
||||
final String dir = cliffRow.get("cliffModelDir").toString();
|
||||
final String path = "Doodads\\Terrain\\" + dir + "\\" + dir + fileName
|
||||
+ bottomLeft.getCliffVariation() + ".mdx";
|
||||
+ Variations.getCliffVariation(dir, fileName, bottomLeft.getCliffVariation())
|
||||
+ ".mdx";
|
||||
|
||||
if (!cliffs.containsKey(path)) {
|
||||
cliffs.put(path, new CliffInfo());
|
||||
@ -423,19 +440,19 @@ public class War3MapViewer extends ModelViewer {
|
||||
this.cliffHeightMap = gl.glGenTexture();
|
||||
gl.glBindTexture(GL20.GL_TEXTURE_2D, this.cliffHeightMap);
|
||||
this.webGL.setTextureMode(GL20.GL_CLAMP_TO_EDGE, GL20.GL_CLAMP_TO_EDGE, GL20.GL_NEAREST, GL20.GL_NEAREST);
|
||||
gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_ALPHA, columns, rows, 0, GL20.GL_ALPHA, GL20.GL_FLOAT,
|
||||
gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL30.GL_R32F, columns, rows, 0, GL30.GL_RED, GL20.GL_FLOAT,
|
||||
RenderMathUtils.wrap(cliffHeights));
|
||||
|
||||
this.heightMap = gl.glGenTexture();
|
||||
gl.glBindTexture(GL20.GL_TEXTURE_2D, this.heightMap);
|
||||
this.webGL.setTextureMode(GL20.GL_CLAMP_TO_EDGE, GL20.GL_CLAMP_TO_EDGE, GL20.GL_NEAREST, GL20.GL_NEAREST);
|
||||
gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_ALPHA, columns, rows, 0, GL20.GL_ALPHA, GL20.GL_FLOAT,
|
||||
gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL30.GL_R32F, columns, rows, 0, GL30.GL_RED, GL20.GL_FLOAT,
|
||||
RenderMathUtils.wrap(cornerHeights));
|
||||
|
||||
this.waterHeightMap = gl.glGenTexture();
|
||||
gl.glBindTexture(GL20.GL_TEXTURE_2D, this.waterHeightMap);
|
||||
this.webGL.setTextureMode(GL20.GL_CLAMP_TO_EDGE, GL20.GL_CLAMP_TO_EDGE, GL20.GL_NEAREST, GL20.GL_NEAREST);
|
||||
gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_ALPHA, columns, rows, 0, GL20.GL_ALPHA, GL20.GL_FLOAT,
|
||||
gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL30.GL_R32F, columns, rows, 0, GL30.GL_RED, GL20.GL_FLOAT,
|
||||
RenderMathUtils.wrap(waterHeights));
|
||||
|
||||
this.instanceBuffer = gl.glGenBuffer();
|
||||
@ -483,13 +500,481 @@ public class War3MapViewer extends ModelViewer {
|
||||
private void loadDoodadsAndDestructibles(final Warcraft3MapObjectData modifications) throws IOException {
|
||||
final War3MapDoo dooFile = this.mapMpq.readDoodads();
|
||||
|
||||
this.applyModificationFile(this.doodadsData, this.doodadMetaData, modifications.getDoodads(),
|
||||
WorldEditorDataType.DOODADS);
|
||||
this.applyModificationFile(this.doodadsData, this.destructableMetaData, modifications.getDestructibles(),
|
||||
WorldEditorDataType.DESTRUCTIBLES);
|
||||
|
||||
final War3MapDoo doo = this.mapMpq.readDoodads();
|
||||
|
||||
for (final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad : doo.getDoodads()) {
|
||||
|
||||
MutableGameObject row = modifications.getDoodads().get(doodad.getId());
|
||||
if (row == null) {
|
||||
row = modifications.getDestructibles().get(doodad.getId());
|
||||
}
|
||||
String file = row.readSLKTag("file");
|
||||
final int numVar = row.readSLKTagInt("numVar");
|
||||
|
||||
if (file.endsWith(".mdx")) {
|
||||
file = file.substring(0, file.length() - 4);
|
||||
}
|
||||
|
||||
String fileVar = file;
|
||||
|
||||
file += ".mdx";
|
||||
|
||||
if (numVar > 1) {
|
||||
fileVar += Math.min(doodad.getVariation(), numVar - 1);
|
||||
}
|
||||
|
||||
fileVar += ".mdx";
|
||||
|
||||
// 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.
|
||||
|
||||
String path;
|
||||
if (this.mapMpq.has(fileVar)) {
|
||||
path = fileVar;
|
||||
}
|
||||
else {
|
||||
path = file;
|
||||
}
|
||||
MdxModel model;
|
||||
if (this.mapMpq.has(path)) {
|
||||
model = (MdxModel) this.load(path, this.mapPathSolver, this.solverParams);
|
||||
}
|
||||
else {
|
||||
model = (MdxModel) this.load(fileVar, this.mapPathSolver, this.solverParams);
|
||||
}
|
||||
|
||||
this.doodads.add(new Doodad(this, model, row, doodad));
|
||||
}
|
||||
|
||||
// Cliff/Terrain doodads.
|
||||
for (final com.etheller.warsmash.parsers.w3x.doo.TerrainDoodad doodad : doo.getTerrainDoodads()) {
|
||||
final MutableGameObject row = modifications.getDoodads().get(doodad.getId());
|
||||
String file = row.readSLKTag("file");
|
||||
if (file.toLowerCase().endsWith(".mdl")) {
|
||||
file = file.substring(0, file.length() - 4);
|
||||
}
|
||||
if (!file.toLowerCase().endsWith(".mdx")) {
|
||||
file += ".mdx";
|
||||
}
|
||||
final MdxModel model = (MdxModel) this.load(file, this.mapPathSolver, this.solverParams);
|
||||
|
||||
this.terrainDoodads.add(new TerrainDoodad(this, model, row, doodad));
|
||||
}
|
||||
|
||||
this.doodadsReady = true;
|
||||
this.anyReady = true;
|
||||
}
|
||||
|
||||
private void loadUnitsAndItems(final Warcraft3MapObjectData modifications) {
|
||||
// TODO Auto-generated method stub
|
||||
private void applyModificationFile(final MappedData doodadsData2, final MappedData doodadMetaData2,
|
||||
final MutableObjectData destructibles, final WorldEditorDataType dataType) {
|
||||
// TODO condense ported MappedData from Ghostwolf and MutableObjectData from
|
||||
// Retera
|
||||
|
||||
}
|
||||
|
||||
private void loadUnitsAndItems(final Warcraft3MapObjectData modifications) throws IOException {
|
||||
final War3Map mpq = this.mapMpq;
|
||||
|
||||
final War3MapUnitsDoo dooFile = mpq.readUnits();
|
||||
|
||||
// Collect the units and items data.
|
||||
for (final com.etheller.warsmash.parsers.w3x.unitsdoo.Unit unit : dooFile.getUnits()) {
|
||||
MutableGameObject row = null;
|
||||
String path = null;
|
||||
|
||||
// Hardcoded?
|
||||
if (sloc.equals(unit.getId())) {
|
||||
path = "Objects\\StartLocation\\StartLocation.mdx";
|
||||
}
|
||||
else {
|
||||
row = modifications.getUnits().get(unit.getId());
|
||||
if (row == null) {
|
||||
row = modifications.getItems().get(unit.getId());
|
||||
}
|
||||
|
||||
if (row != null) {
|
||||
path = row.readSLKTag("file");
|
||||
|
||||
if (path.toLowerCase().endsWith(".mdl") || path.toLowerCase().endsWith(".mdx")) {
|
||||
path = path.substring(0, path.length() - 4);
|
||||
}
|
||||
if (row.readSLKTagInt("fileVerFlags") == 2) {
|
||||
path += "_V1";
|
||||
}
|
||||
|
||||
path += ".mdx";
|
||||
}
|
||||
}
|
||||
|
||||
if (path != null) {
|
||||
final MdxModel model = (MdxModel) this.load(path, this.mapPathSolver, this.solverParams);
|
||||
|
||||
this.units.add(new Unit(this, model, row, unit));
|
||||
}
|
||||
else {
|
||||
System.err.println("Unknown unit ID: " + unit.getId());
|
||||
}
|
||||
}
|
||||
|
||||
this.unitsReady = true;
|
||||
this.anyReady = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
if (this.anyReady) {
|
||||
this.waterIndex += this.waterIncreasePerFrame;
|
||||
|
||||
if (this.waterIndex >= this.waterTextures.size()) {
|
||||
this.waterIndex = 0;
|
||||
}
|
||||
|
||||
super.update();
|
||||
|
||||
final List<ModelInstance> instances = this.worldScene.instances;
|
||||
|
||||
for (final ModelInstance instance : instances) {
|
||||
if (instance instanceof MdxComplexInstance) {
|
||||
final MdxComplexInstance mdxComplexInstance = (MdxComplexInstance) instance;
|
||||
if (mdxComplexInstance.sequenceEnded || (mdxComplexInstance.sequence == -1)) {
|
||||
StandSequence.randomStandSequence(mdxComplexInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
if (this.anyReady) {
|
||||
final Scene worldScene = this.worldScene;
|
||||
|
||||
worldScene.startFrame();
|
||||
this.renderGround();
|
||||
this.renderCliffs();
|
||||
worldScene.renderOpaque();
|
||||
this.renderWater();
|
||||
worldScene.renderTranslucent();
|
||||
}
|
||||
}
|
||||
|
||||
public void renderGround() {
|
||||
if (this.terrainReady) {
|
||||
final GL20 gl = this.gl;
|
||||
final WebGL webgl = this.webGL;
|
||||
final ANGLEInstancedArrays instancedArrays = webgl.instancedArrays;
|
||||
final ShaderProgram shader = this.groundShader;
|
||||
final List<Texture> tilesetTextures = this.tilesetTextures;
|
||||
final int instanceAttrib = shader.getAttributeLocation("a_InstanceID");
|
||||
final int positionAttrib = shader.getAttributeLocation("a_position");
|
||||
final int texturesAttrib = shader.getAttributeLocation("a_textures");
|
||||
final int variationsAttrib = shader.getAttributeLocation("a_variations");
|
||||
final int tilesetCount = tilesetTextures.size();
|
||||
|
||||
gl.glEnable(GL20.GL_BLEND);
|
||||
gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
webgl.useShaderProgram(shader);
|
||||
|
||||
shader.setUniformMatrix("u_VP", this.worldScene.camera.viewProjectionMatrix);
|
||||
shader.setUniform2fv("u_offset", this.centerOffset, 0, 2);
|
||||
sizeHeap[0] = this.columns;
|
||||
sizeHeap[1] = this.rows;
|
||||
shader.setUniform2fv("u_size", sizeHeap, 0, 2);
|
||||
shader.setUniformi("u_heightMap", 15);
|
||||
|
||||
gl.glActiveTexture(GL20.GL_TEXTURE15);
|
||||
gl.glBindTexture(GL20.GL_TEXTURE_2D, this.heightMap);
|
||||
|
||||
gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.vertexBuffer);
|
||||
shader.setVertexAttribute(positionAttrib, 2, GL20.GL_FLOAT, false, 8, 0);
|
||||
|
||||
gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.instanceBuffer);
|
||||
shader.setVertexAttribute(instanceAttrib, 1, GL20.GL_FLOAT, false, 4, 0);
|
||||
instancedArrays.glVertexAttribDivisorANGLE(instanceAttrib, 1);
|
||||
|
||||
gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.textureBuffer);
|
||||
shader.setVertexAttribute(texturesAttrib, 4, GL20.GL_UNSIGNED_BYTE, false, 4, 0);
|
||||
instancedArrays.glVertexAttribDivisorANGLE(texturesAttrib, 1);
|
||||
|
||||
gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.variationBuffer);
|
||||
shader.setVertexAttribute(variationsAttrib, 4, GL20.GL_UNSIGNED_BYTE, false, 4, 0);
|
||||
instancedArrays.glVertexAttribDivisorANGLE(variationsAttrib, 1);
|
||||
|
||||
gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.faceBuffer);
|
||||
|
||||
shader.setUniformi("u_baseTileset", 0);
|
||||
|
||||
for (int i = 0, l = Math.min(tilesetCount, 15); i < l; i++) {
|
||||
final int isExtended = (tilesetTextures.get(i).getWidth() > tilesetTextures.get(i).getHeight()) ? 1 : 0;
|
||||
|
||||
shader.setUniformf("u_extended[" + i + "]", isExtended);
|
||||
shader.setUniformi("u_tilesets[" + i + "]", i);
|
||||
|
||||
tilesetTextures.get(i).bind(i);
|
||||
}
|
||||
|
||||
instancedArrays.glDrawElementsInstancedANGLE(GL20.GL_TRIANGLES, 6, GL20.GL_UNSIGNED_BYTE, 0,
|
||||
this.rows * this.columns);
|
||||
|
||||
if (tilesetCount > 15) {
|
||||
shader.setUniformi("u_baseTileset", 15);
|
||||
|
||||
for (int i = 0, l = tilesetCount - 15; i < l; i++) {
|
||||
final int isExtended = (tilesetTextures.get(i + 15).getWidth() > tilesetTextures.get(i + 15)
|
||||
.getHeight()) ? 1 : 0;
|
||||
|
||||
shader.setUniformf("u_extended[" + i + "]", isExtended);
|
||||
|
||||
tilesetTextures.get(i + 15).bind(i);
|
||||
}
|
||||
|
||||
instancedArrays.glDrawElementsInstancedANGLE(GL20.GL_TRIANGLES, 6, GL20.GL_UNSIGNED_BYTE, 0,
|
||||
this.rows * this.columns);
|
||||
}
|
||||
|
||||
instancedArrays.glVertexAttribDivisorANGLE(texturesAttrib, 0);
|
||||
instancedArrays.glVertexAttribDivisorANGLE(variationsAttrib, 0);
|
||||
instancedArrays.glVertexAttribDivisorANGLE(instanceAttrib, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void renderWater() {
|
||||
if (this.terrainReady) {
|
||||
final GL20 gl = this.gl;
|
||||
final WebGL webgl = this.webGL;
|
||||
final ANGLEInstancedArrays instancedArrays = webgl.instancedArrays;
|
||||
final ShaderProgram shader = this.waterShader;
|
||||
final int instanceAttrib = shader.getAttributeLocation("a_InstanceID");
|
||||
final int positionAttrib = shader.getAttributeLocation("a_position");
|
||||
final int isWaterAttrib = shader.getAttributeLocation("a_isWater");
|
||||
|
||||
gl.glDepthMask(false);
|
||||
|
||||
gl.glEnable(GL20.GL_BLEND);
|
||||
gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
webgl.useShaderProgram(shader);
|
||||
|
||||
shader.setUniformMatrix("u_VP", this.worldScene.camera.viewProjectionMatrix);
|
||||
shader.setUniform2fv("u_offset", this.centerOffset, 0, 2);
|
||||
sizeHeap[0] = this.columns;
|
||||
sizeHeap[1] = this.rows;
|
||||
shader.setUniform2fv("u_size", sizeHeap, 0, 2);
|
||||
shader.setUniformi("u_heightMap", 0);
|
||||
shader.setUniformi("u_waterHeightMap", 1);
|
||||
shader.setUniformi("u_waterTexture", 2);
|
||||
shader.setUniformf("u_offsetHeight", this.waterHeightOffset);
|
||||
shader.setUniform4fv("u_maxDeepColor", this.maxDeepColor, 0, 4);
|
||||
shader.setUniform4fv("u_minDeepColor", this.minDeepColor, 0, 4);
|
||||
shader.setUniform4fv("u_maxShallowColor", this.maxShallowColor, 0, 4);
|
||||
shader.setUniform4fv("u_minShallowColor", this.minShallowColor, 0, 4);
|
||||
|
||||
gl.glActiveTexture(GL20.GL_TEXTURE0);
|
||||
gl.glBindTexture(GL20.GL_TEXTURE_2D, this.heightMap);
|
||||
|
||||
gl.glActiveTexture(GL20.GL_TEXTURE1);
|
||||
gl.glBindTexture(GL20.GL_TEXTURE_2D, this.waterHeightMap);
|
||||
|
||||
this.waterTextures.get((int) this.waterIndex).bind(2);
|
||||
|
||||
gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.vertexBuffer);
|
||||
shader.setVertexAttribute(positionAttrib, 2, GL20.GL_FLOAT, false, 8, 0);
|
||||
|
||||
gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.instanceBuffer);
|
||||
shader.setVertexAttribute(instanceAttrib, 1, GL20.GL_FLOAT, false, 4, 0);
|
||||
instancedArrays.glVertexAttribDivisorANGLE(instanceAttrib, 1);
|
||||
|
||||
gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.waterBuffer);
|
||||
shader.setVertexAttribute(isWaterAttrib, 1, GL20.GL_UNSIGNED_BYTE, false, 1, 0);
|
||||
instancedArrays.glVertexAttribDivisorANGLE(isWaterAttrib, 1);
|
||||
|
||||
gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.faceBuffer);
|
||||
instancedArrays.glDrawElementsInstancedANGLE(GL20.GL_TRIANGLES, 6, GL20.GL_UNSIGNED_BYTE, 0,
|
||||
this.rows * this.columns);
|
||||
|
||||
instancedArrays.glVertexAttribDivisorANGLE(isWaterAttrib, 0);
|
||||
instancedArrays.glVertexAttribDivisorANGLE(instanceAttrib, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void renderCliffs() {
|
||||
if (this.cliffsReady) {
|
||||
final GL20 gl = this.gl;
|
||||
final WebGL webGL = this.webGL;
|
||||
final ANGLEInstancedArrays instancedArrays = webGL.instancedArrays;
|
||||
final ShaderProgram shader = this.cliffShader;
|
||||
|
||||
gl.glDisable(GL20.GL_BLEND);
|
||||
|
||||
webGL.useShaderProgram(shader);
|
||||
|
||||
shader.setUniformMatrix("u_VP", this.worldScene.camera.viewProjectionMatrix);
|
||||
shader.setUniformi("u_heightMap", 0);
|
||||
shader.setUniformf("u_pixel[0]", 1 / (float) (this.columns + 1));
|
||||
shader.setUniformf("u_pixel[1]", 1 / (float) (this.rows + 1));
|
||||
shader.setUniform2fv("u_centerOffset", this.centerOffset, 0, 2);
|
||||
shader.setUniformi("u_texture1", 1);
|
||||
shader.setUniformi("u_texture2", 2);
|
||||
|
||||
gl.glActiveTexture(GL20.GL_TEXTURE0);
|
||||
gl.glBindTexture(GL20.GL_TEXTURE_2D, this.cliffHeightMap);
|
||||
|
||||
gl.glActiveTexture(GL20.GL_TEXTURE1);
|
||||
gl.glBindTexture(GL20.GL_TEXTURE_2D, this.cliffTextures.get(0).getGlTarget());
|
||||
|
||||
if (this.cliffTextures.size() > 1) {
|
||||
gl.glActiveTexture(GL20.GL_TEXTURE2);
|
||||
gl.glBindTexture(GL20.GL_TEXTURE_2D, this.cliffTextures.get(1).getGlTarget());
|
||||
}
|
||||
|
||||
// Set instanced attributes.
|
||||
for (final TerrainModel cliff : this.cliffModels) {
|
||||
cliff.render(shader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String cliffFileName(final int bottomLeftLayer, final int bottomRightLayer, final int topLeftLayer,
|
||||
final int topRightLayer, final int base) {
|
||||
return Character.toString((char) ((65 + bottomLeftLayer) - base))
|
||||
+ Character.toString((char) ((65 + topLeftLayer) - base))
|
||||
+ Character.toString((char) ((65 + topRightLayer) - base))
|
||||
+ Character.toString((char) ((65 + bottomRightLayer) - base));
|
||||
}
|
||||
|
||||
public short getVariation(final int groundTexture, final int variation) {
|
||||
final Texture texture = this.tilesetTextures.get(groundTexture);
|
||||
|
||||
// Extended ?
|
||||
if (texture.getWidth() > texture.getHeight()) {
|
||||
if (variation < 16) {
|
||||
return (short) (16 + variation);
|
||||
}
|
||||
else if (variation == 16) {
|
||||
return 15;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (variation == 0) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCliff(final int column, final int row) {
|
||||
if ((column < 1) || (column > (this.columns - 1)) || (row < 1) || (row > (this.rows - 1))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Corner[][] corners = this.corners;
|
||||
final int bottomLeft = corners[row][column].getLayerHeight();
|
||||
final int bottomRight = corners[row][column + 1].getLayerHeight();
|
||||
final int topLeft = corners[row + 1][column].getLayerHeight();
|
||||
final int topRight = corners[row + 1][column + 1].getLayerHeight();
|
||||
|
||||
return (bottomLeft != bottomRight) || (bottomLeft != topLeft) || (bottomLeft != topRight);
|
||||
}
|
||||
|
||||
public short isWater(final int column, final int row) {
|
||||
return ((this.corners[row][column].getWater() != 0) || (this.corners[row][column + 1].getWater() != 0)
|
||||
|| (this.corners[row + 1][column].getWater() != 0)
|
||||
|| (this.corners[row + 1][column + 1].getWater() != 0)) ? (short) 1 : (short) 0;
|
||||
}
|
||||
|
||||
public int cliffGroundIndex(final int whichCliff) {
|
||||
final String whichTile = this.cliffTilesets.get(whichCliff).get("groundTile").toString();
|
||||
final List<MappedDataRow> tilesets = this.tilesets;
|
||||
|
||||
for (int i = 0, l = tilesets.size(); i < l; i++) {
|
||||
if (tilesets.get(i).get("tileID").toString().equals(whichTile)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(Integer.toString(whichCliff));
|
||||
}
|
||||
|
||||
public int cornerTexture(final int column, final int row) {
|
||||
final Corner[][] corners = this.corners;
|
||||
final int columns = this.columns;
|
||||
final int rows = this.rows;
|
||||
|
||||
for (int y = -1; y < 1; y++) {
|
||||
for (int x = -1; x < 1; x++) {
|
||||
if (((column + x) > 0) && ((column + x) < (columns - 1)) && ((row + y) > 0)
|
||||
&& ((row + y) < (rows - 1))) {
|
||||
if (this.isCliff(column + x, row + y)) {
|
||||
int texture = corners[row + y][column + x].getCliffTexture();
|
||||
|
||||
if (texture == 15) {
|
||||
texture = 1;
|
||||
}
|
||||
|
||||
return this.cliffGroundIndex(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Corner corner = corners[row][column];
|
||||
if (corner.getBlight() != 0) {
|
||||
return this.blightTextureIndex;
|
||||
}
|
||||
return corner.getGroundTexture();
|
||||
}
|
||||
|
||||
public Vector3 groundNormal(final Vector3 out, int x, int y) {
|
||||
final float[] centerOffset = this.centerOffset;
|
||||
final int[] mapSize = this.mapSize;
|
||||
|
||||
x = (int) ((x - centerOffset[0]) / 128);
|
||||
y = (int) ((y - centerOffset[1]) / 128);
|
||||
|
||||
final int cellX = x;
|
||||
final int cellY = y;
|
||||
|
||||
// See if this coordinate is in the map
|
||||
|
||||
if ((cellX >= 0) && (cellX < (mapSize[0] - 1)) && (cellY >= 0) && (cellY < (mapSize[1] - 1))) {
|
||||
// See http://gamedev.stackexchange.com/a/24574
|
||||
final Corner[][] corners = this.corners;
|
||||
final int bottomLeft = corners[cellY][cellX].getGroundHeight();
|
||||
final int bottomRight = corners[cellY][cellX + 1].getGroundHeight();
|
||||
final int topLeft = corners[cellY + 1][cellX].getGroundHeight();
|
||||
final int topRight = corners[cellY + 1][cellX + 1].getGroundHeight();
|
||||
final int sqX = x - cellX;
|
||||
final int sqY = y - cellY;
|
||||
|
||||
if ((sqX + sqY) < 1) {
|
||||
normalHeap1.set(1, 0, bottomRight - bottomLeft);
|
||||
normalHeap2.set(0, 1, topLeft - bottomLeft);
|
||||
}
|
||||
else {
|
||||
normalHeap1.set(-1, 0, topRight - topLeft);
|
||||
normalHeap2.set(0, 1, topRight - bottomRight);
|
||||
}
|
||||
|
||||
out.set(normalHeap1.crs(normalHeap2)).nor();
|
||||
}
|
||||
else {
|
||||
out.set(0, 0, 1);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private static final class MappedDataCallbackImplementation implements LoadGenericCallback {
|
||||
@Override
|
||||
public Object call(final InputStream data) {
|
||||
@ -514,6 +999,9 @@ public class War3MapViewer extends ModelViewer {
|
||||
private static final class StringDataCallbackImplementation implements LoadGenericCallback {
|
||||
@Override
|
||||
public Object call(final InputStream data) {
|
||||
if (data == null) {
|
||||
System.err.println("data null");
|
||||
}
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(data, "utf-8"))) {
|
||||
String line;
|
||||
@ -549,4 +1037,20 @@ public class War3MapViewer extends ModelViewer {
|
||||
public List<float[]> locations = new ArrayList<>();
|
||||
public List<Integer> textures = new ArrayList<>();
|
||||
}
|
||||
|
||||
private static final int MAXIMUM_ACCEPTED = 1 << 30;
|
||||
|
||||
/**
|
||||
* Returns a power of two size for the given target capacity.
|
||||
*/
|
||||
private static final int pow2GreaterThan(final int capacity) {
|
||||
int numElements = capacity - 1;
|
||||
numElements |= numElements >>> 1;
|
||||
numElements |= numElements >>> 2;
|
||||
numElements |= numElements >>> 4;
|
||||
numElements |= numElements >>> 8;
|
||||
numElements |= numElements >>> 16;
|
||||
return (numElements < 0) ? 1 : (numElements >= MAXIMUM_ACCEPTED) ? MAXIMUM_ACCEPTED : numElements + 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import org.lwjgl.opengl.GL33;
|
||||
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
||||
import com.etheller.warsmash.WarsmashGdxGame;
|
||||
import com.etheller.warsmash.WarsmashGdxMapGame;
|
||||
import com.etheller.warsmash.viewer5.gl.ANGLEInstancedArrays;
|
||||
import com.etheller.warsmash.viewer5.gl.Extensions;
|
||||
|
||||
@ -37,6 +37,6 @@ public class DesktopLauncher {
|
||||
// final DisplayMode desktopDisplayMode = LwjglApplicationConfiguration.getDesktopDisplayMode();
|
||||
// config.width = desktopDisplayMode.width;
|
||||
// config.height = desktopDisplayMode.height;
|
||||
new LwjglApplication(new WarsmashGdxGame(), config);
|
||||
new LwjglApplication(new WarsmashGdxMapGame(), config);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user