This commit is contained in:
Retera 2021-04-04 10:31:57 -04:00
commit 1af6a438ee
827 changed files with 97030 additions and 0 deletions

128
.gitignore vendored Normal file
View File

@ -0,0 +1,128 @@
## Java
*.class
*.war
*.ear
hs_err_pid*
## Robovm
/ios/robovm-build/
## GWT
/html/war/
/html/gwt-unitCache/
.apt_generated/
.gwt/
gwt-unitCache/
www-test/
.gwt-tmp/
## Android Studio and Intellij and Android in general
/android/libs/armeabi/
/android/libs/armeabi-v7a/
/android/libs/arm64-v8a/
/android/libs/x86/
/android/libs/x86_64/
/android/gen/
.idea/
*.ipr
*.iws
*.iml
/android/out/
com_crashlytics_export_strings.xml
## Eclipse
.classpath
.project
.metadata/
/android/bin/
/core/bin/
/desktop/bin/
/html/bin/
/ios/bin/
/ios-moe/bin/
*.tmp
*.bak
*.swp
*~.nib
.settings/
.loadpath
.externalToolBuilders/
*.launch
## NetBeans
/nbproject/private/
/android/nbproject/private/
/core/nbproject/private/
/desktop/nbproject/private/
/html/nbproject/private/
/ios/nbproject/private/
/ios-moe/nbproject/private/
/build/
/android/build/
/core/build/
/desktop/build/
/html/build/
/ios/build/
/ios-moe/build/
/nbbuild/
/android/nbbuild/
/core/nbbuild/
/desktop/nbbuild/
/html/nbbuild/
/ios/nbbuild/
/ios-moe/nbbuild/
/dist/
/android/dist/
/core/dist/
/desktop/dist/
/html/dist/
/ios/dist/
/ios-moe/dist/
/nbdist/
/android/nbdist/
/core/nbdist/
/desktop/nbdist/
/html/nbdist/
/ios/nbdist/
/ios-moe/nbdist/
nbactions.xml
nb-configuration.xml
## Gradle
/local.properties
.gradle/
gradle-app.setting
/build/
/android/build/
/core/build/
/desktop/build/
/html/build/
/ios/build/
/ios-moe/build/
## OS Specific
.DS_Store
Thumbs.db
## iOS
/ios/xcode/*.xcodeproj/*
!/ios/xcode/*.xcodeproj/xcshareddata
!/ios/xcode/*.xcodeproj/project.pbxproj
/ios/xcode/native/
/ios-moe/xcode/*.xcodeproj/*
!/ios-moe/xcode/*.xcodeproj/xcshareddata
!/ios-moe/xcode/*.xcodeproj/project.pbxproj
/ios-moe/xcode/native/
## data
/core/data

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# Warsmash
Greatest game ever

98
build.gradle Normal file
View File

@ -0,0 +1,98 @@
buildscript {
repositories {
mavenLocal()
flatDir {
dirs "$rootProject.projectDir/jars"
}
mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven { url "https://maven.nikr.net/" }
jcenter()
google()
}
}
allprojects {
apply plugin: "eclipse"
apply plugin: "idea"
version = '1.0'
ext {
appName = "warsmash"
gdxVersion = '1.9.8'
roboVMVersion = '2.3.5'
box2DLightsVersion = '1.4'
ashleyVersion = '1.7.0'
aiVersion = '1.8.0'
antlrVersion = '4.7'
}
repositories {
mavenLocal()
mavenCentral()
google()
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven { url "https://oss.sonatype.org/content/repositories/releases/" }
maven { url "https://maven.nikr.net/" }
maven { url 'https://jitpack.io' }
}
}
project(":desktop") {
apply plugin: "java"
dependencies {
compile project(":core")
compile "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion"
compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
compile "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop"
compile "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
compile "com.google.guava:guava:23.5-jre"
compile "net.nikr:dds:1.0.0"
implementation 'com.github.inwc3:wc3libs:-SNAPSHOT'
compile files(fileTree(dir:'../jars', includes: ['*.jar']))
}
}
project(":core") {
apply plugin: "java"
dependencies {
compile project(":fdfparser")
compile project(":jassparser")
compile "com.badlogicgames.gdx:gdx:$gdxVersion"
compile "com.badlogicgames.gdx:gdx-box2d:$gdxVersion"
compile "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
compile "com.google.guava:guava:23.5-jre"
compile "net.nikr:dds:1.0.0"
implementation 'com.github.inwc3:wc3libs:-SNAPSHOT'
compile files(fileTree(dir:'../jars', includes: ['*.jar']))
}
}
project(":fdfparser") {
apply plugin: "antlr"
dependencies {
antlr "org.antlr:antlr4:$antlrVersion" // use antlr version 4
}
}
project(":jassparser") {
apply plugin: "antlr"
dependencies {
antlr "org.antlr:antlr4:$antlrVersion" // use antlr version 4
}
}
tasks.eclipse.doLast {
delete ".project"
}

BIN
core/assets/badlogic.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -0,0 +1,16 @@
uniform sampler2D u_boneMap;
uniform float u_vectorSize;
uniform float u_rowSize;
mat4 fetchMatrix(float column, float row) {
column *= u_vectorSize * 4.0;
row *= u_rowSize;
// Add in half texel to sample in the middle of the texel.
// Otherwise, since the sample is directly on the boundry, small floating point errors can cause the sample to get the wrong pixel.
// This is mostly noticable with NPOT textures, which the bone maps are.
column += 0.5 * u_vectorSize;
row += 0.5 * u_rowSize;
return mat4(texture2D(u_boneMap, vec2(column, row)),
texture2D(u_boneMap, vec2(column + u_vectorSize, row)),
texture2D(u_boneMap, vec2(column + u_vectorSize * 2.0, row)),
texture2D(u_boneMap, vec2(column + u_vectorSize * 3.0, row)));
}

53
core/assets/warsmash.ini Normal file
View File

@ -0,0 +1,53 @@
[DataSources]
Count=8
Type00=MPQ
Path00="D:\Games\Warcraft III Patch 1.22\war3.mpq"
Type01=MPQ
Path01="D:\Games\Warcraft III Patch 1.22\War3x.mpq"
Type02=MPQ
Path02="D:\Games\Warcraft III Patch 1.22\War3xlocal.mpq"
Type03=MPQ
Path03="D:\Games\Warcraft III Patch 1.22\War3Patch.mpq"
Type04=Folder
Path04="..\..\resources"
Type05=Folder
Path05="D:\Backups\Warsmash\Data"
Type06=Folder
Path06="D:\Games\Warcraft III Patch 1.22\Maps"
Type07=Folder
Path07="."
[Map]
//FilePath="CombatUnitTests.w3x"
//FilePath="PitchRoll.w3x"
//FilePath="PeonStartingBase_Simple.w3x"
FilePath="PeonStartingBase_Scythe.w3x"
//FilePath="MyStromguarde.w3m"
//FilePath="ColdArrows.w3m"
//FilePath="DungeonGoldMine.w3m"
//FilePath="PlayerPeasants.w3m"
//FilePath="FireLord.w3x"
//FilePath="Maps\Campaign\NightElf03.w3m"
//FilePath="PhoenixAttack.w3x"
//FilePath="LightEnvironmentTest.w3x"
//FilePath="TorchLight2.w3x"
//FilePath="OrcAssault.w3x"
//FilePath="FrostyVsFarm.w3m"
//FilePath="ModelTest.w3x"
//FilePath="SpinningSample.w3x"
//FilePath="Maps\Campaign\Prologue02.w3m"
//FilePath="Pathing.w3x"
//FilePath="ItemFacing.w3x"
//FilePath=SomeParticleTests.w3x
//FilePath="PeonMiningMultiHall.w3x"
//FilePath="QuadtreeBugs.w3x"
//FilePath="test2.w3x"
//FilePath="FarseerHoldPositionTest.w3x"
//FilePath="Ramps.w3m"
//FilePath="V1\Farm.w3x"
//FilePath="PenguinWorld.w3x"
//FilePath="Maps\FrozenThrone\Campaign\UndeadX09.w3x"
//FilePath="LavellaLagoon.w3x"
//FilePath="WiceOrc.w3x"
//FilePath="NorthrendPathingDoodle.w3x"
//FilePath="Maps\Campaign\Prologue01.w3m"

View File

@ -0,0 +1,26 @@
[DataSources]
Count=5
Type00=Folder
Path00="D:\Games\Warcraft III CASC 1.31\war3.w3mod"
Type01=Folder
Path01="D:\Games\Warcraft III CASC 1.31\war3.w3mod\_locales\enus.w3mod"
Type02=Folder
Path02="..\..\resources"
Type03=Folder
Path03="D:\Backups\Warsmash\Data"
Type04=Folder
Path04="."
[Map]
//FilePath="PitchRoll.w3x"
//FilePath="ReforgedGeorgeVacation.w3x"
//FilePath="Maps\Campaign\NightElf03.w3m"
//FilePath="PrivateDontShare/Cult 8.w3x"
//FilePath="TorchLight2.w3x"
//FilePath="OrcAssault.w3x"
//FilePath="PeonStartingBase.w3x"
//FilePath="PhoenixAttack.w3x"
//FilePath="OperationReforged.w3x"
//FilePath="AzerothRoleplay1.909t03DecoratedV2.w3x"
//FilePath="American Colo EX 1.0 unpro.w3x"
FilePath="TheSheepAttack.w3x"

View File

@ -0,0 +1,42 @@
[DataSources]
Count=5
Type00=CASC
Path00="D:\Games\Warcraft III Patch 1.31\"
Prefixes00="war3.w3mod","war3.w3mod\_deprecated.w3mod","war3.w3mod\_locales\enus.w3mod"
Type01=Folder
Path01="..\..\resources"
Type02=Folder
Path02="D:\Backups\Warsmash\Data"
Type03=Folder
Path03="D:\Games\Warcraft III Patch 1.22\Maps"
Type04=Folder
Path04="."
[Map]
//FilePath="CombatUnitTests.w3x"
//FilePath="PitchRoll.w3x"
//FilePath="PeonStartingBase.w3x"
//FilePath="MyStromguarde.w3m"
//FilePath="ColdArrows.w3m"
//FilePath="DungeonGoldMine.w3m"
//FilePath="PlayerPeasants.w3m"
//FilePath="FireLord.w3x"
//FilePath="Maps\Campaign\NightElf03.w3m"
//FilePath="PhoenixAttack.w3x"
//FilePath="LightEnvironmentTest.w3x"
//FilePath="TorchLight2.w3x"
FilePath="OrcAssault.w3x"
//FilePath="FrostyVsFarm.w3m"
//FilePath="ModelTest.w3x"
//FilePath="SpinningSample.w3x"
//FilePath="Maps\Campaign\Prologue02.w3m"
//FilePath="Pathing.w3x"
//FilePath="ItemFacing.w3x"
//FilePath=SomeParticleTests.w3x
//FilePath="PeonMiningMultiHall.w3x"
//FilePath="QuadtreeBugs.w3x"
//FilePath="test2.w3x"
//FilePath="FarseerHoldPositionTest.w3x"
//FilePath="Ramps.w3m"
//FilePath="V1\Farm.w3x"
//FilePath="TheSheepAttack.w3x"

View File

@ -0,0 +1,26 @@
// This is the Warsmash INI file for Project Revolution
// PRSCMOD
[DataSources]
Count=9
Type00=MPQ
Path00="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\war3.mpq"
Type01=MPQ
Path01="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\War3x.mpq"
Type02=MPQ
Path02="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\War3xlocal.mpq"
Type03=MPQ
Path03="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\war3patch.mpq"
Type04=MPQ
Path04="D:\Games\Warcraft III Project Revolution\PRSCMOD\Revolution.mpq"
Type05=MPQ
Path05="D:\Games\Warcraft III Project Revolution\PRSCMOD\Sound.mpq"
Type06=Folder
Path06="D:\Games\Warcraft III Project Revolution\ProjectRevolusmash"
Type07=Folder
Path07="..\..\resources"
Type08=Folder
Path08="D:\Games\Warcraft III Project Revolution\PRSCMOD\PR-Maps"
[Map]
FilePath="ProjectRevolusmash.w3x"

View File

@ -0,0 +1,41 @@
[DataSources]
Count=5
Type00=CASC
Path00="C:\Program Files\Warcraft III"
Prefixes00=war3.w3mod,war3.w3mod\_deprecated.w3mod,war3.w3mod\_locales\enus.w3mod,war3.w3mod\_hd.w3mod,war3.w3mod\_hd.w3mod\_locales\enus.w3mod
Type01=Folder
Path01="..\..\resources"
Type02=Folder
Path02="D:\Backups\Warsmash\Data"
Type03=Folder
Path03="D:\Games\Warcraft III Patch 1.22\Maps"
Type04=Folder
Path04="."
[Map]
//FilePath="CombatUnitTests.w3x"
//FilePath="PitchRoll.w3x"
FilePath="PeonStartingBase.w3x"
//FilePath="MyStromguarde.w3m"
//FilePath="ColdArrows.w3m"
//FilePath="DungeonGoldMine.w3m"
//FilePath="PlayerPeasants.w3m"
//FilePath="FireLord.w3x"
//FilePath="Maps\Campaign\NightElf03.w3m"
//FilePath="PhoenixAttack.w3x"
//FilePath="LightEnvironmentTest.w3x"
//FilePath="TorchLight2.w3x"
//FilePath="OrcAssault.w3x"
//FilePath="FrostyVsFarm.w3m"
//FilePath="ModelTest.w3x"
//FilePath="SpinningSample.w3x"
//FilePath="Maps\Campaign\Prologue02.w3m"
//FilePath="Pathing.w3x"
//FilePath="ItemFacing.w3x"
//FilePath=SomeParticleTests.w3x
//FilePath="PeonMiningMultiHall.w3x"
//FilePath="QuadtreeBugs.w3x"
//FilePath="test2.w3x"
//FilePath="FarseerHoldPositionTest.w3x"
//FilePath="Ramps.w3m"
//FilePath="V1\Farm.w3x"

View File

@ -0,0 +1,22 @@
// This is the Warsmash INI file for Project Revolution
// PRSCMOD
[DataSources]
Count=7
Type00=MPQ
Path00="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\war3.mpq"
Type01=MPQ
Path01="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\War3x.mpq"
Type02=MPQ
Path02="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\War3xlocal.mpq"
Type03=MPQ
Path03="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\war3patch_TTOR.mpq"
Type04=Folder
Path04="D:\Games\Warcraft III Project Revolution\ProjectRevolusmash"
Type05=Folder
Path05="..\..\resources"
Type06=Folder
Path06="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\Maps"
[Map]
FilePath="(2)BootyBay.w3m"

View File

@ -0,0 +1,22 @@
// This is the Warsmash INI file for Project Revolution
// PRSCMOD
[DataSources]
Count=7
Type00=MPQ
Path00="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\war3.mpq"
Type01=MPQ
Path01="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\War3x.mpq"
Type02=MPQ
Path02="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\War3xlocal.mpq"
Type03=MPQ
Path03="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\war3patch.mpq"
Type04=MPQ
Path04="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\War3Mod.mpq"
Type05=Folder
Path05="..\..\resources"
Type06=Folder
Path06="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\Maps"
[Map]
FilePath="Maps\Campaign\Prologue01.w3m"

11
core/build.gradle Normal file
View File

@ -0,0 +1,11 @@
apply plugin: "java"
sourceCompatibility = 1.8
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
sourceSets.main.java.srcDirs = [ "src/" ]
eclipse.project {
name = appName + "-core"
}

View File

@ -0,0 +1,35 @@
package com.etheller.warsmash;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
public class CodeCounter {
public static void main(final String[] args) {
final int sourceLines = countFile(new File("src/com"));
System.out.println(sourceLines);
}
public static int countFile(final File file) {
if (file.isDirectory()) {
int sum = 0;
for (final File subFile : file.listFiles()) {
sum += countFile(subFile);
}
return sum;
}
else {
try {
if (file.getName().toLowerCase().endsWith(".java")) {
return Files.readAllLines(file.toPath()).size();
}
}
catch (final IOException e) {
e.printStackTrace();
}
return 0;
}
}
}

View File

@ -0,0 +1,61 @@
package com.etheller.warsmash;
public class MathSpeedBenchmark {
private static final int NUMBER_OF_ITERATIONS = 100000000;
public static void main(final String[] args) {
// Let us solve for Ground Distance two ways.
long sumCosineTime = 0;
long sumSquareRootTime = 0;
final float[] thrallXs = new float[NUMBER_OF_ITERATIONS];
final float[] thrallYs = new float[NUMBER_OF_ITERATIONS];
final float[] murlocXs = new float[NUMBER_OF_ITERATIONS];
final float[] murlocYs = new float[NUMBER_OF_ITERATIONS];
for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
thrallXs[i] = getRandomFloat(-25000.0f, 25000.0f);
thrallYs[i] = getRandomFloat(-25000.0f, 25000.0f);
murlocXs[i] = getRandomFloat(-25000.0f, 25000.0f);
murlocYs[i] = getRandomFloat(-25000.0f, 25000.0f);
}
final long clockTime1 = System.currentTimeMillis();
for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
final float distance2 = groundDistanceSqrt(thrallXs[i], thrallYs[i], murlocXs[i], murlocYs[i]);
}
final long clockTime2 = System.currentTimeMillis();
for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
final float distance1 = groundDistanceCos(thrallXs[i], thrallYs[i], murlocXs[i], murlocYs[i]);
}
final long clockTime3 = System.currentTimeMillis();
// if (Math.abs(distance2 - distance1) > 0.1) {
// System.out.println(thrallX + "," + thrallY);
// System.out.println(murlocX + "," + murlocY);
// System.err.println(distance1 + " != " + distance2);
// throw new RuntimeException("You have failed to do mathematics.");
// }
sumCosineTime = clockTime2 - clockTime1;
sumSquareRootTime = clockTime3 - clockTime2;
System.out.println("Square Root: " + sumCosineTime);
System.out.println("Cosine: " + sumSquareRootTime);
}
static float getRandomFloat(final float min, final float max) {
final float range = max - min;
return (float) ((Math.random() * range) + min);
}
static float groundDistanceSqrt(final float thrallX, final float thrallY, final float murlocX,
final float murlocY) {
final float dx = murlocX - thrallX;
final float dy = murlocY - thrallY;
return (float) StrictMath.sqrt((dx * dx) + (dy * dy));
}
static float groundDistanceCos(final float thrallX, final float thrallY, final float murlocX, final float murlocY) {
final float dx = murlocX - thrallX;
final float dy = murlocY - thrallY;
final double angle = StrictMath.atan2(dy, dx);
return (float) (dx / StrictMath.cos(angle));
}
}

View File

@ -0,0 +1,5 @@
package com.etheller.warsmash;
public interface SingleModelScreen {
void setModel(String path);
}

View File

@ -0,0 +1,36 @@
package com.etheller.warsmash;
import com.etheller.warsmash.util.War3ID;
public class TestMain {
public static void main(final String[] args) {
if (true) {
System.out.println(War3ID.fromString("hwat").getValue());
System.out.println(Integer.toHexString(War3ID.fromString("hwat").getValue()));
System.out.println(new War3ID(0x68776174));
return;
}
// System.out.println(Integer.parseInt("4294967295"));
for (int i = 1; i <= 30; i++) {
// System.out.println(a(i));
}
int checkX = 0;
int checkY = 0;
for (int i = 0; i < 300; i++) {
System.out.println(checkX + "," + checkY);
final double angle = ((((int) Math.floor(Math.sqrt((4 * i) + 1))) % 4) * Math.PI) / 2;
checkX += (int) Math.sin(angle);
checkY += (int) Math.cos(angle);
}
}
public static int a(final int n) {
if (n == 1) {
return 0;
}
else {
return a(n - 1) - (int) Math.sin(((Math.floor(Math.sqrt((4 * (n - 2)) + 1)) % 4) * Math.PI) / 2);
}
}
}

View File

@ -0,0 +1,535 @@
package com.etheller.warsmash;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
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.Vector3;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.util.DataSourceFileHandle;
import com.etheller.warsmash.viewer5.Camera;
import com.etheller.warsmash.viewer5.CanvasProvider;
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.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxViewer;
import com.etheller.warsmash.viewer5.handlers.mdx.Sequence;
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvider {
private static final boolean SPIN = false;
private static final boolean ADVANCE_ANIMS = true;
private DataSource codebase;
private ModelViewer viewer;
private MdxModel model;
private CameraManager cameraManager;
public static int VAO;
private final Rectangle tempRect = new Rectangle();
private BitmapFont font;
private SpriteBatch batch;
private final DataTable warsmashIni;
public WarsmashGdxGame(final DataTable warsmashIni) {
this.warsmashIni = warsmashIni;
}
@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);
VAO = temp.get(0);
Gdx.gl30.glBindVertexArray(VAO);
final String renderer = Gdx.gl.glGetString(GL20.GL_RENDERER);
System.err.println("Renderer: " + renderer);
this.codebase = WarsmashGdxMapScreen.parseDataSources(this.warsmashIni);
this.viewer = new MdxViewer(this.codebase, this, new Vector3(0.3f, 0.3f, -0.25f));
this.viewer.addHandler(new MdxHandler());
this.viewer.enableAudio();
final Scene scene = this.viewer.addSimpleScene();
scene.enableAudio();
this.cameraManager = new CameraManager();
this.cameraManager.setupCamera(scene);
final String musicPath = "Sound\\Music\\mp3Music\\Mainscreen.mp3";
final Music music = Gdx.audio.newMusic(new DataSourceFileHandle(this.viewer.dataSource, musicPath));
// music.setVolume(0.2f);
music.setLooping(true);
music.play();
// this.mainModel = (MdxModel) this.viewer.load("Doodads\\Cinematic\\ArthasIllidanFight\\ArthasIllidanFight.mdx",
// this.mainModel = (MdxModel) this.viewer.load("UI\\Glues\\SinglePlayer\\NightElf_Exp\\NightElf_Exp.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) {
// return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
// }
// }, 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);
// this.mainInstance = (MdxComplexInstance) this.mainModel.addInstance(0);
// this.mainInstance.setScene(scene);
//
// final int animIndex = 0;
// this.modelCamera = this.mainModel.cameras.get(animIndex);
// this.mainInstance.setSequence(animIndex);
//
// this.mainInstance.setSequenceLoopMode(SequenceLoopMode.LOOP_TO_NEXT_ANIMATION);
// acolytesHarvestingSceneJoke2(scene);
// singleModelScene(scene, "Buildings\\Undead\\Necropolis\\Necropolis.mdx", "birth");
// singleModelScene(scene, "Units\\Orc\\KotoBeast\\KotoBeast.mdx", "spell slam");
singleModelScene(scene, "UI\\Glues\\MainMenu\\MainMenu3D\\MainMenu3D.mdx", "Stand");
this.modelCamera = this.mainModel.cameras.get(0);
System.out.println("Loaded");
Gdx.gl30.glClearColor(0.5f, 0.5f, 0.5f, 1); // TODO remove white background
this.font = new BitmapFont();
this.batch = new SpriteBatch();
}
private void makeDruidSquare(final Scene scene) {
final MdxModel model2 = (MdxModel) this.viewer.load("units\\nightelf\\druidoftheclaw\\druidoftheclaw.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
makePerfectSquare(scene, model2, 15);
}
private void singleAcolyteScene(final Scene scene) {
final MdxModel model2 = (MdxModel) this.viewer.load("units\\undead\\acolyte\\acolyte.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.setScene(scene);
int animIndex = 0;
for (final Sequence s : model2.getSequences()) {
if (s.getName().toLowerCase().startsWith("stand work")) {
animIndex = model2.getSequences().indexOf(s);
}
}
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
private void singleModelScene(final Scene scene, final String path, final String animName) {
final MdxModel model2 = (MdxModel) this.viewer.load(path, new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.setScene(scene);
int animIndex = 0;
for (final Sequence s : model2.getSequences()) {
if (s.getName().toLowerCase().startsWith(animName)) {
animIndex = model2.getSequences().indexOf(s);
break;
}
}
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
this.mainInstance = instance3;
this.mainModel = model2;
}
private void acolytesHarvestingScene(final Scene scene) {
final MdxModel acolyteModel = (MdxModel) this.viewer.load("units\\undead\\acolyte\\acolyte.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxModel mineEffectModel = (MdxModel) this.viewer
.load("abilities\\spells\\undead\\undeadmine\\undeadminecircle.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
for (int i = 0; i < 5; i++) {
final MdxComplexInstance acolyteInstance = (MdxComplexInstance) acolyteModel.addInstance(0);
acolyteInstance.setScene(scene);
int animIndex = i % acolyteModel.getSequences().size();
for (final Sequence s : acolyteModel.getSequences()) {
if (s.getName().toLowerCase().startsWith("stand work")) {
animIndex = acolyteModel.getSequences().indexOf(s);
}
}
acolyteInstance.setSequence(animIndex);
acolyteInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
final double angle = ((Math.PI * 2) / 5) * i;
acolyteInstance.localLocation.x = (float) Math.cos(angle) * 256;
acolyteInstance.localLocation.y = (float) Math.sin(angle) * 256;
acolyteInstance.localRotation.setFromAxisRad(0, 0, 1, (float) (angle + Math.PI));
final MdxComplexInstance effectInstance = (MdxComplexInstance) mineEffectModel.addInstance(0);
effectInstance.setScene(scene);
effectInstance.setSequence(1);
effectInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
effectInstance.localLocation.x = (float) Math.cos(angle) * 256;
effectInstance.localLocation.y = (float) Math.sin(angle) * 256;
effectInstance.localRotation.setFromAxisRad(0, 0, 1, (float) (angle));
}
final MdxModel mineModel = (MdxModel) this.viewer.load("buildings\\undead\\hauntedmine\\hauntedmine.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance mineInstance = (MdxComplexInstance) mineModel.addInstance(0);
mineInstance.setScene(scene);
mineInstance.setSequence(2);
mineInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
private void acolytesHarvestingSceneJoke2(final Scene scene) {
final MdxModel acolyteModel = (MdxModel) this.viewer.load("units\\undead\\acolyte\\acolyte.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxModel mineEffectModel = (MdxModel) this.viewer
.load("abilities\\spells\\undead\\undeadmine\\undeadminecircle.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
for (int i = 0; i < 5; i++) {
final MdxComplexInstance acolyteInstance = (MdxComplexInstance) acolyteModel.addInstance(0);
acolyteInstance.setScene(scene);
int animIndex = i % acolyteModel.getSequences().size();
for (final Sequence s : acolyteModel.getSequences()) {
if (s.getName().toLowerCase().startsWith("stand work")) {
animIndex = acolyteModel.getSequences().indexOf(s);
}
}
acolyteInstance.setSequence(animIndex);
acolyteInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
final double angle = ((Math.PI * 2) / 5) * i;
acolyteInstance.localLocation.x = (float) Math.cos(angle) * 256;
acolyteInstance.localLocation.y = (float) Math.sin(angle) * 256;
acolyteInstance.localRotation.setFromAxisRad(0, 0, 1, (float) (angle + Math.PI));
final MdxComplexInstance effectInstance = (MdxComplexInstance) mineEffectModel.addInstance(0);
effectInstance.setScene(scene);
effectInstance.setSequence(1);
effectInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
effectInstance.localLocation.x = (float) Math.cos(angle) * 256;
effectInstance.localLocation.y = (float) Math.sin(angle) * 256;
effectInstance.localRotation.setFromAxisRad(0, 0, 1, (float) (angle));
}
final MdxModel mineModel = (MdxModel) this.viewer.load("units\\orc\\spiritwolf\\spiritwolf.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance mineInstance = (MdxComplexInstance) mineModel.addInstance(0);
mineInstance.setScene(scene);
mineInstance.setSequence(0);
mineInstance.localScale.x = 2;
mineInstance.localScale.y = 2;
mineInstance.localScale.z = 2;
mineInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
final MdxModel mineModel2 = (MdxModel) this.viewer
.load("abilities\\spells\\undead\\unsummon\\unsummontarget.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance mineInstance2 = (MdxComplexInstance) mineModel2.addInstance(0);
mineInstance2.setScene(scene);
mineInstance2.setSequence(0);
mineInstance2.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
private void makeFourHundred(final Scene scene, final MdxModel model2) {
for (int i = 0; i < 400; i++) {
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.localLocation.x = (((i % 20) - 10) * 128);
instance3.localLocation.y = (((i / 20) - 10) * 128);
instance3.setScene(scene);
final int animIndex = i % model2.getSequences().size();
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
}
private void makePerfectSquare(final Scene scene, final MdxModel model2, final int n) {
final int n2 = n * n;
for (int i = 0; i < n2; i++) {
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.localLocation.x = (((i % n) - (n / 2)) * 128);
instance3.localLocation.y = (((i / n) - (n / 2)) * 128);
instance3.setScene(scene);
final int animIndex = i % model2.getSequences().size();
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
}
public static void bindDefaultVertexArray() {
Gdx.gl30.glBindVertexArray(VAO);
}
private int frame = 0;
private MdxComplexInstance mainInstance;
private MdxModel mainModel;
private com.etheller.warsmash.viewer5.handlers.mdx.Camera modelCamera;
private final float[] cameraPositionTemp = new float[3];
private final float[] cameraTargetTemp = new float[3];
private final boolean firstFrame = true;
@Override
public void render() {
Gdx.gl30.glBindVertexArray(VAO);
if (SPIN) {
this.cameraManager.horizontalAngle += 0.0001;
if (this.cameraManager.horizontalAngle > (2 * Math.PI)) {
this.cameraManager.horizontalAngle = 0;
}
}
// this.modelCamera = this.mainModel.cameras.get(this.mainInstance.sequence);
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();
this.frame++;
if ((this.frame % 1000) == 0) {
System.out.println(Integer.toString(Gdx.graphics.getFramesPerSecond()));
}
if (ADVANCE_ANIMS && this.mainInstance.sequenceEnded) {
final int sequence = (this.mainInstance.sequence + 1) % this.mainModel.getSequences().size();
this.mainInstance.setSequence(sequence);
this.mainInstance.frame += (int) (Gdx.graphics.getRawDeltaTime() * 1000);
}
// if (this.firstFrame) {
// final Music music = Gdx.audio.newMusic(new DataSourceFileHandle(this.viewer.dataSource,
// "Sound\\Ambient\\DoodadEffects\\FinalCinematic.mp3"));
// music.setVolume(0.2f);
// music.setLooping(true);
// music.play();
// this.firstFrame = false;
// }
}
@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 Vector3 vecHeap2;
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 = (float) (Math.PI / 2);
this.verticalAngle = (float) (Math.PI / 4);
this.distance = 500;
this.position = new Vector3();
this.target = new Vector3(0, 0, 50);
this.worldUp = new Vector3(0, 0, 1);
this.vecHeap = new Vector3();
this.vecHeap2 = 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);
if (WarsmashGdxGame.this.modelCamera != null) {
WarsmashGdxGame.this.modelCamera.getPositionTranslation(WarsmashGdxGame.this.cameraPositionTemp,
WarsmashGdxGame.this.mainInstance.sequence, WarsmashGdxGame.this.mainInstance.frame,
WarsmashGdxGame.this.mainInstance.counter);
WarsmashGdxGame.this.modelCamera.getTargetTranslation(WarsmashGdxGame.this.cameraTargetTemp,
WarsmashGdxGame.this.mainInstance.sequence, WarsmashGdxGame.this.mainInstance.frame,
WarsmashGdxGame.this.mainInstance.counter);
this.position.set(WarsmashGdxGame.this.modelCamera.position);
this.target.set(WarsmashGdxGame.this.modelCamera.targetPosition);
// this.vecHeap2.set(this.target);
// this.vecHeap2.sub(this.position);
// this.vecHeap.set(this.vecHeap2);
// this.vecHeap.crs(this.worldUp);
// this.vecHeap.crs(this.vecHeap2);
// this.vecHeap.nor();
// this.vecHeap.scl(this.camera.rect.height / 2f);
// this.position.add(this.vecHeap);
this.position.add(WarsmashGdxGame.this.cameraPositionTemp[0],
WarsmashGdxGame.this.cameraPositionTemp[1], WarsmashGdxGame.this.cameraPositionTemp[2]);
this.target.add(WarsmashGdxGame.this.cameraTargetTemp[0], WarsmashGdxGame.this.cameraTargetTemp[1],
WarsmashGdxGame.this.cameraTargetTemp[2]);
this.camera.perspective(WarsmashGdxGame.this.modelCamera.fieldOfView * 0.75f,
Gdx.graphics.getWidth() / (float) Gdx.graphics.getHeight(),
WarsmashGdxGame.this.modelCamera.nearClippingPlane,
WarsmashGdxGame.this.modelCamera.farClippingPlane);
}
else {
this.camera.perspective(70, this.camera.getAspect(), 100, 5000);
}
this.camera.moveToAndFace(this.position, this.target, this.worldUp);
}
// private void cameraUpdate() {
//
// }
}
public DataSource getCodebase() {
return this.codebase;
}
}

View File

@ -0,0 +1,517 @@
package com.etheller.warsmash;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.etheller.warsmash.datasources.CascDataSourceDescriptor;
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.datasources.MpqDataSourceDescriptor;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.Element;
import com.etheller.warsmash.util.DataSourceFileHandle;
import com.etheller.warsmash.util.ImageUtils;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.Model;
import com.etheller.warsmash.viewer5.ModelInstance;
import com.etheller.warsmash.viewer5.ModelViewer;
import com.etheller.warsmash.viewer5.PathSolver;
import com.etheller.warsmash.viewer5.RenderBatch;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.TextureMapper;
import com.etheller.warsmash.viewer5.handlers.ModelHandler;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraPreset;
import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraRates;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayerUnitOrderExecutor;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.MeleeUI;
public class WarsmashGdxMapScreen implements InputProcessor, Screen {
public static final boolean ENABLE_AUDIO = true;
private static final boolean ENABLE_MUSIC = false;
private final War3MapViewer viewer;
private final Rectangle tempRect = new Rectangle();
// libGDX stuff
private OrthographicCamera uiCamera;
private SpriteBatch batch;
private ExtendViewport uiViewport;
private GlyphLayout glyphLayout;
private Texture solidGreenTexture;
private ShapeRenderer shapeRenderer;
private MdxModel timeIndicator;
private Scene uiScene;
private MeleeUI meleeUI;
private Music currentMusic;
private final WarsmashGdxMultiScreenGame screenManager;
private final WarsmashGdxMenuScreen menuScreen;
public WarsmashGdxMapScreen(final War3MapViewer mapViewer, final WarsmashGdxMultiScreenGame screenManager,
final WarsmashGdxMenuScreen menuScreen) {
this.viewer = mapViewer;
this.screenManager = screenManager;
this.menuScreen = menuScreen;
}
/*
* (non-Javadoc)
*
* @see com.badlogic.gdx.ApplicationAdapter#create()
*/
@Override
public void show() {
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 Element cameraData = this.viewer.miscData.get("Camera");
Element cameraListenerData = this.viewer.miscData.get("Listener");
if (cameraListenerData == null) {
cameraListenerData = new Element("Listener", new DataTable(null));
}
final CameraPreset[] cameraPresets = new CameraPreset[6];
for (int i = 0; i < cameraPresets.length; i++) {
cameraPresets[i] = new CameraPreset(cameraData.getFieldFloatValue("AOA", i),
cameraData.getFieldFloatValue("FOV", i), cameraData.getFieldFloatValue("Rotation", i),
cameraData.getFieldFloatValue("Rotation", i + cameraPresets.length),
cameraData.getFieldFloatValue("Rotation", i + (cameraPresets.length * 2)),
cameraData.getFieldFloatValue("Distance", i), cameraData.getFieldFloatValue("FarZ", i),
cameraData.getFieldFloatValue("NearZ", i), cameraData.getFieldFloatValue("Height", i),
cameraListenerData.getFieldFloatValue("ListenerDistance", i),
cameraListenerData.getFieldFloatValue("ListenerAOA", i));
}
System.out.println("Loaded");
Gdx.gl30.glClearColor(0.0f, 0.0f, 0.0f, 1); // TODO remove white background
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
final Scene portraitScene = this.viewer.addSimpleScene();
this.uiScene = this.viewer.addSimpleScene();
this.uiScene.alpha = true;
if (ENABLE_AUDIO) {
this.uiScene.enableAudio();
}
// this.mainModel = (MdxModel) this.viewer.load("UI\\Glues\\MainMenu\\MainMenu3D_exp\\MainMenu3D_exp.mdx",
// libGDX stuff
final int width = Gdx.graphics.getWidth();
final int height = Gdx.graphics.getHeight();
this.glyphLayout = new GlyphLayout();
// Constructs a new OrthographicCamera, using the given viewport width and
// height
// Height is multiplied by aspect ratio.
this.uiCamera = new OrthographicCamera();
int aspect3By4Width;
int aspect3By4Height;
if (width < ((height * 4) / 3)) {
aspect3By4Width = width;
aspect3By4Height = (width * 3) / 4;
}
else {
aspect3By4Width = (height * 4) / 3;
aspect3By4Height = height;
}
this.uiViewport = new ExtendViewport(aspect3By4Width, aspect3By4Height, this.uiCamera);
this.uiViewport.update(width, height);
this.uiCamera.position.set(this.uiViewport.getMinWorldWidth() / 2, this.uiViewport.getMinWorldHeight() / 2, 0);
this.uiCamera.update();
this.batch = new SpriteBatch();
// this.consoleUITexture = new Texture(new DataSourceFileHandle(this.viewer.dataSource, "AlphaUi.png"));
this.solidGreenTexture = ImageUtils.getAnyExtensionTexture(this.viewer.dataSource,
"ReplaceableTextures\\TeamColor\\TeamColor06.blp");
Gdx.input.setInputProcessor(this);
this.shapeRenderer = new ShapeRenderer();
// Jass2.loadJUI(this.codebase, this.uiViewport, fontGenerator, this.uiScene, this.viewer,
// new RootFrameListener() {
// @Override
// public void onCreate(final GameUI rootFrame) {
// WarsmashGdxMapGame.this.gameUI = rootFrame;
// }
// }, "Scripts\\common.jui", "Scripts\\melee.jui");
final Element cameraRatesElement = this.viewer.miscData.get("CameraRates");
final CameraRates cameraRates = new CameraRates(cameraRatesElement.getFieldFloatValue("AOA"),
cameraRatesElement.getFieldFloatValue("FOV"), cameraRatesElement.getFieldFloatValue("Rotation"),
cameraRatesElement.getFieldFloatValue("Distance"), cameraRatesElement.getFieldFloatValue("Forward"),
cameraRatesElement.getFieldFloatValue("Strafe"));
this.meleeUI = new MeleeUI(this.viewer.mapMpq, this.uiViewport, this.uiScene, portraitScene, cameraPresets,
cameraRates, this.viewer, new RootFrameListener() {
@Override
public void onCreate(final GameUI rootFrame) {
WarsmashGdxMapScreen.this.viewer.setGameUI(rootFrame);
if (ENABLE_MUSIC) {
final String musicField = rootFrame
.getSkinField("Music_V" + WarsmashConstants.GAME_VERSION);
final String[] musics = musicField.split(";");
String musicPath = musics[(int) (Math.random() * musics.length)];
if (false) {
musicPath = "Sound\\Music\\mp3Music\\PH1.mp3";
}
final Music music = Gdx.audio.newMusic(
new DataSourceFileHandle(WarsmashGdxMapScreen.this.viewer.dataSource, musicPath));
music.setVolume(1.0f);
music.setLooping(true);
music.play();
WarsmashGdxMapScreen.this.currentMusic = music;
}
}
}, new CPlayerUnitOrderExecutor(this.viewer.simulation, this.viewer.getLocalPlayerIndex(),
this.viewer.getCommandErrorListener()),
new Runnable() {
@Override
public void run() {
WarsmashGdxMapScreen.this.menuScreen.onReturnFromGame();
WarsmashGdxMapScreen.this.screenManager.setScreen(WarsmashGdxMapScreen.this.menuScreen);
}
});
this.viewer.getCommandErrorListener().setDelegate(this.meleeUI);
final ModelInstance libgdxContentInstance = new LibGDXContentLayerModel(null, this.viewer, "",
this.viewer.mapPathSolver, "").addInstance();
libgdxContentInstance.setScene(this.uiScene);
this.meleeUI.main();
updateUIScene();
resize(width, height);
try {
this.viewer.loadAfterUI();
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
public static DataSource parseDataSources(final DataTable warsmashIni) {
final Element dataSourcesConfig = warsmashIni.get("DataSources");
final int dataSourcesCount = dataSourcesConfig.getFieldValue("Count");
final List<DataSourceDescriptor> dataSourcesList = new ArrayList<>();
for (int i = 0; i < dataSourcesCount; i++) {
final String type = dataSourcesConfig.getField("Type" + (i < 10 ? "0" : "") + i);
final String path = dataSourcesConfig.getField("Path" + (i < 10 ? "0" : "") + i);
switch (type) {
case "Folder": {
dataSourcesList.add(new FolderDataSourceDescriptor(path));
break;
}
case "MPQ": {
dataSourcesList.add(new MpqDataSourceDescriptor(path));
break;
}
case "CASC": {
final String prefixes = dataSourcesConfig.getField("Prefixes" + (i < 10 ? "0" : "") + i);
dataSourcesList.add(new CascDataSourceDescriptor(path, Arrays.asList(prefixes.split(","))));
break;
}
default:
throw new RuntimeException("Unknown data source type: " + type);
}
}
return new CompoundDataSourceDescriptor(dataSourcesList).createDataSource();
}
private void updateUIScene() {
this.tempRect.x = this.uiViewport.getScreenX();
this.tempRect.y = this.uiViewport.getScreenY();
this.tempRect.width = this.uiViewport.getScreenWidth();
this.tempRect.height = this.uiViewport.getScreenHeight();
this.uiScene.camera.viewport(this.tempRect);
final float worldWidth = this.uiViewport.getWorldWidth();
final float worldHeight = this.uiViewport.getWorldHeight();
final float xScale = worldWidth / this.uiViewport.getMinWorldWidth();
final float yScale = worldHeight / this.uiViewport.getMinWorldHeight();
final float uiSceneWidth = 0.8f * xScale;
final float uiSceneHeight = 0.6f * yScale;
final float uiSceneX = ((0.8f - uiSceneWidth) / 2);
final float uiSceneY = ((0.6f - uiSceneHeight) / 2);
this.uiScene.camera.ortho(uiSceneX, uiSceneWidth + uiSceneX, uiSceneY, uiSceneHeight + uiSceneY, -1024f, 1024);
}
@Override
public void render(final float delta) {
this.uiCamera.update();
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
final float deltaTime = Gdx.graphics.getDeltaTime();
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
this.meleeUI.update(deltaTime);
this.viewer.updateAndRender();
Gdx.gl30.glDisable(GL30.GL_SCISSOR_TEST);
Gdx.gl30.glDisable(GL30.GL_CULL_FACE);
this.viewer.webGL.useShaderProgram(null);
Gdx.gl30.glActiveTexture(GL30.GL_TEXTURE0);
}
private void renderLibGDXContent() {
Gdx.gl30.glDisable(GL30.GL_SCISSOR_TEST);
Gdx.gl30.glDisable(GL30.GL_CULL_FACE);
this.viewer.webGL.useShaderProgram(null);
Gdx.gl30.glActiveTexture(GL30.GL_TEXTURE0);
this.uiViewport.apply();
this.batch.setProjectionMatrix(this.uiCamera.combined);
this.batch.begin();
this.meleeUI.render(this.batch, this.glyphLayout);
this.batch.end();
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
}
@Override
public void dispose() {
this.meleeUI.dispose();
}
@Override
public void resize(final int width, final int height) {
// super.resize(width, height);
this.uiViewport.update(width, height);
this.uiCamera.position.set(this.uiViewport.getMinWorldWidth() / 2, this.uiViewport.getMinWorldHeight() / 2, 0);
this.meleeUI.resize(setupWorldFrameViewport(width, height));
updateUIScene();
}
private Rectangle setupWorldFrameViewport(final int width, final int height) {
this.tempRect.x = 0;
this.tempRect.width = width;
final float topHeight = 0.02666f * height;
final float bottomHeight = 0.21333f * height;
this.tempRect.y = (int) bottomHeight;
this.tempRect.height = height - (int) (topHeight + bottomHeight);
return this.tempRect;
}
@Override
public boolean keyDown(final int keycode) {
this.meleeUI.keyDown(keycode);
return true;
}
@Override
public boolean keyUp(final int keycode) {
this.meleeUI.keyUp(keycode);
return true;
}
@Override
public boolean keyTyped(final char character) {
if (character == '1') {
Gdx.input.setCursorCatched(!Gdx.input.isCursorCatched());
}
return false;
}
@Override
public boolean touchDown(final int screenX, final int screenY, final int pointer, final int button) {
final float worldScreenY = this.viewer.canvas.getHeight() - screenY;
if (this.meleeUI.touchDown(screenX, screenY, worldScreenY, button)) {
return false;
}
return false;
}
@Override
public boolean touchUp(final int screenX, final int screenY, final int pointer, final int button) {
final float worldScreenY = this.viewer.canvas.getHeight() - screenY;
if (this.meleeUI.touchUp(screenX, screenY, worldScreenY, button)) {
return false;
}
return false;
}
@Override
public boolean touchDragged(final int screenX, final int screenY, final int pointer) {
final float worldScreenY = this.viewer.canvas.getHeight() - screenY;
if (this.meleeUI.touchDragged(screenX, screenY, worldScreenY, pointer)) {
return false;
}
return false;
}
@Override
public boolean mouseMoved(final int screenX, final int screenY) {
final float worldScreenY = this.viewer.canvas.getHeight() - screenY;
if (this.meleeUI.mouseMoved(screenX, screenY, worldScreenY)) {
return false;
}
return false;
}
@Override
public boolean scrolled(final int amount) {
this.meleeUI.scrolled(amount);
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;
}
}
private class LibGDXContentLayerModelInstance extends ModelInstance {
public LibGDXContentLayerModelInstance(final Model model) {
super(model);
}
@Override
public void updateAnimations(final float dt) {
}
@Override
public void clearEmittedObjects() {
}
@Override
protected void updateLights(final Scene scene2) {
}
@Override
public void renderOpaque(final Matrix4 mvp) {
}
@Override
public void renderTranslucent() {
renderLibGDXContent();
}
@Override
public void load() {
}
@Override
protected RenderBatch getBatch(final TextureMapper textureMapper2) {
throw new UnsupportedOperationException("NOT API");
}
@Override
public void setReplaceableTexture(final int replaceableTextureId, final String replaceableTextureFile) {
}
@Override
public boolean isBatched() {
return super.isBatched();
}
@Override
protected void removeLights(final Scene scene2) {
// TODO Auto-generated method stub
}
}
private class LibGDXContentLayerModel extends Model {
public LibGDXContentLayerModel(final ModelHandler handler, final ModelViewer viewer, final String extension,
final PathSolver pathSolver, final String fetchUrl) {
super(handler, viewer, extension, pathSolver, fetchUrl);
this.ok = true;
}
@Override
protected ModelInstance createInstance(final int type) {
return new LibGDXContentLayerModelInstance(this);
}
@Override
protected void lateLoad() {
}
@Override
protected void load(final InputStream src, final Object options) {
}
@Override
protected void error(final Exception e) {
}
}
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
public void hide() {
if (this.currentMusic != null) {
this.currentMusic.stop();
}
}
}

View File

@ -0,0 +1,882 @@
package com.etheller.warsmash;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Quaternion;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.util.DataSourceFileHandle;
import com.etheller.warsmash.util.ImageUtils;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.Camera;
import com.etheller.warsmash.viewer5.CanvasProvider;
import com.etheller.warsmash.viewer5.Model;
import com.etheller.warsmash.viewer5.ModelInstance;
import com.etheller.warsmash.viewer5.ModelViewer;
import com.etheller.warsmash.viewer5.PathSolver;
import com.etheller.warsmash.viewer5.RenderBatch;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.SolvedPath;
import com.etheller.warsmash.viewer5.TextureMapper;
import com.etheller.warsmash.viewer5.handlers.ModelHandler;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxViewer;
import com.etheller.warsmash.viewer5.handlers.mdx.Sequence;
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.MenuUI;
public class WarsmashGdxMenuScreen implements InputProcessor, Screen, SingleModelScreen {
private static final boolean ENABLE_AUDIO = true;
private static final boolean ENABLE_MUSIC = false;
private DataSource codebase;
private MdxViewer viewer;
private MdxModel model;
private CameraManager cameraManager;
private final Rectangle tempRect = new Rectangle();
// libGDX stuff
private OrthographicCamera uiCamera;
private SpriteBatch batch;
private Viewport uiViewport;
private GlyphLayout glyphLayout;
private final DataTable warsmashIni;
private Scene uiScene;
private Texture solidGreenTexture;
private MenuUI menuUI;
private final WarsmashGdxMultiScreenGame game;
private Music currentMusic;
private boolean hasPlayedStandHack = false;
private boolean loaded = false;
public WarsmashGdxMenuScreen(final DataTable warsmashIni, final WarsmashGdxMultiScreenGame game) {
this.warsmashIni = warsmashIni;
this.game = game;
}
@Override
public void show() {
if (!this.loaded) {
this.loaded = true;
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);
this.codebase = WarsmashGdxMapScreen.parseDataSources(this.warsmashIni);
this.viewer = new MdxViewer(this.codebase, this.game, Vector3.Zero);
this.viewer.addHandler(new MdxHandler());
this.viewer.enableAudio();
this.scene = this.viewer.addSimpleScene();
this.scene.enableAudio();
this.uiScene = this.viewer.addSimpleScene();
this.uiScene.alpha = true;
if (ENABLE_AUDIO) {
this.uiScene.enableAudio();
}
final int width = Gdx.graphics.getWidth();
final int height = Gdx.graphics.getHeight();
this.glyphLayout = new GlyphLayout();
// Constructs a new OrthographicCamera, using the given viewport width and
// height
// Height is multiplied by aspect ratio.
this.uiCamera = new OrthographicCamera();
int aspect3By4Width;
int aspect3By4Height;
if (width < ((height * 4) / 3)) {
aspect3By4Width = width;
aspect3By4Height = (width * 3) / 4;
}
else {
aspect3By4Width = (height * 4) / 3;
aspect3By4Height = height;
}
this.uiViewport = new FitViewport(aspect3By4Width, aspect3By4Height, this.uiCamera);
this.uiViewport.update(width, height);
this.uiCamera.position.set(getMinWorldWidth() / 2, getMinWorldHeight() / 2, 0);
this.uiCamera.update();
this.batch = new SpriteBatch();
// this.consoleUITexture = new Texture(new DataSourceFileHandle(this.viewer.dataSource, "AlphaUi.png"));
this.solidGreenTexture = ImageUtils.getAnyExtensionTexture(this.viewer.dataSource,
"ReplaceableTextures\\TeamColor\\TeamColor06.blp");
this.cameraManager = new CameraManager();
this.cameraManager.setupCamera(this.scene);
// this.mainModel = (MdxModel) this.viewer.load("Doodads\\Cinematic\\ArthasIllidanFight\\ArthasIllidanFight.mdx",
// this.mainModel = (MdxModel) this.viewer.load("UI\\Glues\\SinglePlayer\\NightElf_Exp\\NightElf_Exp.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) {
// return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
// }
// }, 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);
// this.mainInstance = (MdxComplexInstance) this.mainModel.addInstance(0);
// this.mainInstance.setScene(scene);
//
// final int animIndex = 0;
// this.modelCamera = this.mainModel.cameras.get(animIndex);
// this.mainInstance.setSequence(animIndex);
//
// this.mainInstance.setSequenceLoopMode(SequenceLoopMode.LOOP_TO_NEXT_ANIMATION);
// acolytesHarvestingSceneJoke2(scene);
// singleModelScene(scene, "Buildings\\Undead\\Necropolis\\Necropolis.mdx", "birth");
// singleModelScene(scene, "Units\\Orc\\KotoBeast\\KotoBeast.mdx", "spell slam");
System.out.println("Loaded");
Gdx.gl30.glClearColor(0.0f, 0.0f, 0.0f, 1);
this.menuUI = new MenuUI(this.viewer.dataSource, this.uiViewport, this.uiScene, this.viewer, this.game,
this, this.warsmashIni, new RootFrameListener() {
@Override
public void onCreate(final GameUI rootFrame) {
// WarsmashGdxMapGame.this.viewer.setGameUI(rootFrame);
if (ENABLE_MUSIC) {
final String musicField = rootFrame
.getSkinField("GlueMusic_V" + WarsmashConstants.GAME_VERSION);
final String[] musics = musicField.split(";");
final String musicPath = musics[(int) (Math.random() * musics.length)];
final Music music = Gdx.audio.newMusic(new DataSourceFileHandle(
WarsmashGdxMenuScreen.this.viewer.dataSource, musicPath));
// music.setVolume(0.2f);
music.setLooping(true);
music.play();
WarsmashGdxMenuScreen.this.currentMusic = music;
}
singleModelScene(WarsmashGdxMenuScreen.this.scene, War3MapViewer.mdx(rootFrame
.getSkinField("GlueSpriteLayerBackground_V" + WarsmashConstants.GAME_VERSION)),
"Stand");
WarsmashGdxMenuScreen.this.modelCamera = WarsmashGdxMenuScreen.this.mainModel.cameras
.get(0);
}
});
final ModelInstance libgdxContentInstance = new LibGDXContentLayerModel(null, this.viewer, "",
PathSolver.DEFAULT, "").addInstance();
libgdxContentInstance.setLocation(0f, 0f, -0.5f);
libgdxContentInstance.setScene(this.uiScene);
this.menuUI.main();
updateUIScene();
resize(width, height);
}
Gdx.input.setInputProcessor(this);
if (this.currentMusic != null) {
this.currentMusic.play();
}
}
private float getMinWorldWidth() {
if (this.uiViewport instanceof ExtendViewport) {
return ((ExtendViewport) this.uiViewport).getMinWorldWidth();
}
return this.uiViewport.getWorldWidth();
}
private float getMinWorldHeight() {
if (this.uiViewport instanceof ExtendViewport) {
return ((ExtendViewport) this.uiViewport).getMinWorldHeight();
}
return this.uiViewport.getWorldHeight();
}
private void updateUIScene() {
this.tempRect.x = this.uiViewport.getScreenX();
this.tempRect.y = this.uiViewport.getScreenY();
this.tempRect.width = this.uiViewport.getScreenWidth();
this.tempRect.height = this.uiViewport.getScreenHeight();
this.uiScene.camera.viewport(this.tempRect);
final float worldWidth = this.uiViewport.getWorldWidth();
final float worldHeight = this.uiViewport.getWorldHeight();
final float xScale = worldWidth / getMinWorldWidth();
final float yScale = worldHeight / getMinWorldHeight();
final float uiSceneWidth = 0.8f * xScale;
final float uiSceneHeight = 0.6f * yScale;
final float uiSceneX = ((0.8f - uiSceneWidth) / 2);
final float uiSceneY = ((0.6f - uiSceneHeight) / 2);
this.uiScene.camera.ortho(uiSceneX, uiSceneWidth + uiSceneX, uiSceneY, uiSceneHeight + uiSceneY, -1024f, 1024);
}
private void makeDruidSquare(final Scene scene) {
final MdxModel model2 = (MdxModel) this.viewer.load("units\\nightelf\\druidoftheclaw\\druidoftheclaw.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
makePerfectSquare(scene, model2, 15);
}
private void singleAcolyteScene(final Scene scene) {
final MdxModel model2 = (MdxModel) this.viewer.load("units\\undead\\acolyte\\acolyte.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.setScene(scene);
int animIndex = 0;
for (final Sequence s : model2.getSequences()) {
if (s.getName().toLowerCase().startsWith("stand work")) {
animIndex = model2.getSequences().indexOf(s);
}
}
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
private void singleModelScene(final Scene scene, final String path, final String animName) {
final MdxModel model2 = (MdxModel) this.viewer.load(path, new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.setScene(scene);
int animIndex = 0;
for (final Sequence s : model2.getSequences()) {
if (s.getName().toLowerCase().startsWith(animName)) {
animIndex = model2.getSequences().indexOf(s);
break;
}
}
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
this.mainInstance = instance3;
this.mainModel = model2;
}
@Override
public void setModel(final String path) {
if (this.mainInstance != null) {
this.mainInstance.detach();
}
if (path == null) {
this.modelCamera = null;
this.mainInstance = null;
this.mainModel = null;
}
else {
singleModelScene(this.scene, War3MapViewer.mdx(path), "birth");
WarsmashGdxMenuScreen.this.modelCamera = WarsmashGdxMenuScreen.this.mainModel.cameras.get(0);
// this hack is because we only have the queued animation system in RenderWidget
// which is stupid and back and needs to get moved to the model instance
// itself... our model instance class is a
// hacky replica of a model viewer tool with a bunch of irrelevant loop type
// settings instead of what it should be
this.hasPlayedStandHack = false;
}
}
private void acolytesHarvestingScene(final Scene scene) {
final MdxModel acolyteModel = (MdxModel) this.viewer.load("units\\undead\\acolyte\\acolyte.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxModel mineEffectModel = (MdxModel) this.viewer
.load("abilities\\spells\\undead\\undeadmine\\undeadminecircle.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
for (int i = 0; i < 5; i++) {
final MdxComplexInstance acolyteInstance = (MdxComplexInstance) acolyteModel.addInstance(0);
acolyteInstance.setScene(scene);
int animIndex = i % acolyteModel.getSequences().size();
for (final Sequence s : acolyteModel.getSequences()) {
if (s.getName().toLowerCase().startsWith("stand work")) {
animIndex = acolyteModel.getSequences().indexOf(s);
}
}
acolyteInstance.setSequence(animIndex);
acolyteInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
final double angle = ((Math.PI * 2) / 5) * i;
acolyteInstance.localLocation.x = (float) Math.cos(angle) * 256;
acolyteInstance.localLocation.y = (float) Math.sin(angle) * 256;
acolyteInstance.localRotation.setFromAxisRad(0, 0, 1, (float) (angle + Math.PI));
final MdxComplexInstance effectInstance = (MdxComplexInstance) mineEffectModel.addInstance(0);
effectInstance.setScene(scene);
effectInstance.setSequence(1);
effectInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
effectInstance.localLocation.x = (float) Math.cos(angle) * 256;
effectInstance.localLocation.y = (float) Math.sin(angle) * 256;
effectInstance.localRotation.setFromAxisRad(0, 0, 1, (float) (angle));
}
final MdxModel mineModel = (MdxModel) this.viewer.load("buildings\\undead\\hauntedmine\\hauntedmine.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance mineInstance = (MdxComplexInstance) mineModel.addInstance(0);
mineInstance.setScene(scene);
mineInstance.setSequence(2);
mineInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
private void acolytesHarvestingSceneJoke2(final Scene scene) {
final MdxModel acolyteModel = (MdxModel) this.viewer.load("units\\undead\\acolyte\\acolyte.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxModel mineEffectModel = (MdxModel) this.viewer
.load("abilities\\spells\\undead\\undeadmine\\undeadminecircle.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
for (int i = 0; i < 5; i++) {
final MdxComplexInstance acolyteInstance = (MdxComplexInstance) acolyteModel.addInstance(0);
acolyteInstance.setScene(scene);
int animIndex = i % acolyteModel.getSequences().size();
for (final Sequence s : acolyteModel.getSequences()) {
if (s.getName().toLowerCase().startsWith("stand work")) {
animIndex = acolyteModel.getSequences().indexOf(s);
}
}
acolyteInstance.setSequence(animIndex);
acolyteInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
final double angle = ((Math.PI * 2) / 5) * i;
acolyteInstance.localLocation.x = (float) Math.cos(angle) * 256;
acolyteInstance.localLocation.y = (float) Math.sin(angle) * 256;
acolyteInstance.localRotation.setFromAxisRad(0, 0, 1, (float) (angle + Math.PI));
final MdxComplexInstance effectInstance = (MdxComplexInstance) mineEffectModel.addInstance(0);
effectInstance.setScene(scene);
effectInstance.setSequence(1);
effectInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
effectInstance.localLocation.x = (float) Math.cos(angle) * 256;
effectInstance.localLocation.y = (float) Math.sin(angle) * 256;
effectInstance.localRotation.setFromAxisRad(0, 0, 1, (float) (angle));
}
final MdxModel mineModel = (MdxModel) this.viewer.load("units\\orc\\spiritwolf\\spiritwolf.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance mineInstance = (MdxComplexInstance) mineModel.addInstance(0);
mineInstance.setScene(scene);
mineInstance.setSequence(0);
mineInstance.localScale.x = 2;
mineInstance.localScale.y = 2;
mineInstance.localScale.z = 2;
mineInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
final MdxModel mineModel2 = (MdxModel) this.viewer
.load("abilities\\spells\\undead\\unsummon\\unsummontarget.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance mineInstance2 = (MdxComplexInstance) mineModel2.addInstance(0);
mineInstance2.setScene(scene);
mineInstance2.setSequence(0);
mineInstance2.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
private void makeFourHundred(final Scene scene, final MdxModel model2) {
for (int i = 0; i < 400; i++) {
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.localLocation.x = (((i % 20) - 10) * 128);
instance3.localLocation.y = (((i / 20) - 10) * 128);
instance3.setScene(scene);
final int animIndex = i % model2.getSequences().size();
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
}
private void makePerfectSquare(final Scene scene, final MdxModel model2, final int n) {
final int n2 = n * n;
for (int i = 0; i < n2; i++) {
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.localLocation.x = (((i % n) - (n / 2)) * 128);
instance3.localLocation.y = (((i / n) - (n / 2)) * 128);
instance3.setScene(scene);
final int animIndex = i % model2.getSequences().size();
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
}
public static void bindDefaultVertexArray() {
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
}
private final int frame = 0;
private MdxComplexInstance mainInstance;
private MdxModel mainModel;
private com.etheller.warsmash.viewer5.handlers.mdx.Camera modelCamera;
private final float[] cameraPositionTemp = new float[3];
private final float[] cameraTargetTemp = new float[3];
private final boolean firstFrame = true;
private Scene scene;
@Override
public void render(final float delta) {
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
final float deltaTime = Gdx.graphics.getDeltaTime();
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
this.cameraManager.updateCamera();
this.menuUI.update(deltaTime);
if ((this.mainInstance != null) && this.mainInstance.sequenceEnded
&& (((this.mainModel.getSequences().get(this.mainInstance.sequence).getFlags() & 0x1) == 0)
|| !this.hasPlayedStandHack)) {
SequenceUtils.randomStandSequence(this.mainInstance);
this.hasPlayedStandHack = true;
}
this.viewer.updateAndRender();
Gdx.gl30.glDisable(GL30.GL_SCISSOR_TEST);
Gdx.gl30.glDisable(GL30.GL_CULL_FACE);
this.viewer.webGL.useShaderProgram(null);
Gdx.gl30.glActiveTexture(GL30.GL_TEXTURE0);
}
@Override
public void dispose() {
this.menuUI.dispose();
}
@Override
public void resize(final int width, final int height) {
this.tempRect.width = width;
this.tempRect.height = height;
final float fourThirdsHeight = (this.tempRect.height * 4) / 3;
if (fourThirdsHeight < this.tempRect.width) {
final float dx = this.tempRect.width - fourThirdsHeight;
this.tempRect.width = fourThirdsHeight;
this.tempRect.x = dx / 2;
}
else {
final float threeFourthsWidth = (this.tempRect.width * 3) / 4;
if (threeFourthsWidth < this.tempRect.height) {
final float dy = this.tempRect.height - threeFourthsWidth;
this.tempRect.height = threeFourthsWidth;
this.tempRect.y = dy;
}
}
this.cameraManager.camera.viewport(this.tempRect);
// super.resize(width, height);
this.uiViewport.update(width, height);
this.uiCamera.position.set(getMinWorldWidth() / 2, getMinWorldHeight() / 2, 0);
this.menuUI.resize();
updateUIScene();
}
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 Vector3 vecHeap2;
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 = (float) (Math.PI / 2);
this.verticalAngle = (float) (Math.PI / 4);
this.distance = 500;
this.position = new Vector3();
this.target = new Vector3(0, 0, 50);
this.worldUp = new Vector3(0, 0, 1);
this.vecHeap = new Vector3();
this.vecHeap2 = 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);
if (WarsmashGdxMenuScreen.this.modelCamera != null) {
WarsmashGdxMenuScreen.this.modelCamera.getPositionTranslation(
WarsmashGdxMenuScreen.this.cameraPositionTemp, WarsmashGdxMenuScreen.this.mainInstance.sequence,
WarsmashGdxMenuScreen.this.mainInstance.frame, WarsmashGdxMenuScreen.this.mainInstance.counter);
WarsmashGdxMenuScreen.this.modelCamera.getTargetTranslation(WarsmashGdxMenuScreen.this.cameraTargetTemp,
WarsmashGdxMenuScreen.this.mainInstance.sequence, WarsmashGdxMenuScreen.this.mainInstance.frame,
WarsmashGdxMenuScreen.this.mainInstance.counter);
this.position.set(WarsmashGdxMenuScreen.this.modelCamera.position);
this.target.set(WarsmashGdxMenuScreen.this.modelCamera.targetPosition);
// this.vecHeap2.set(this.target);
// this.vecHeap2.sub(this.position);
// this.vecHeap.set(this.vecHeap2);
// this.vecHeap.crs(this.worldUp);
// this.vecHeap.crs(this.vecHeap2);
// this.vecHeap.nor();
// this.vecHeap.scl(this.camera.rect.height / 2f);
// this.position.add(this.vecHeap);
this.position.add(WarsmashGdxMenuScreen.this.cameraPositionTemp[0],
WarsmashGdxMenuScreen.this.cameraPositionTemp[1],
WarsmashGdxMenuScreen.this.cameraPositionTemp[2]);
this.target.add(WarsmashGdxMenuScreen.this.cameraTargetTemp[0],
WarsmashGdxMenuScreen.this.cameraTargetTemp[1], WarsmashGdxMenuScreen.this.cameraTargetTemp[2]);
this.camera.perspective(WarsmashGdxMenuScreen.this.modelCamera.fieldOfView * 0.6f,
this.camera.rect.width / this.camera.rect.height,
WarsmashGdxMenuScreen.this.modelCamera.nearClippingPlane,
WarsmashGdxMenuScreen.this.modelCamera.farClippingPlane);
}
else {
this.camera.perspective(70, this.camera.getAspect(), 100, 5000);
}
this.camera.moveToAndFace(this.position, this.target, this.worldUp);
}
// private void cameraUpdate() {
//
// }
}
public DataSource getCodebase() {
return this.codebase;
}
@Override
public boolean keyDown(final int keycode) {
return this.menuUI.keyDown(keycode);
}
@Override
public boolean keyUp(final int keycode) {
return this.menuUI.keyUp(keycode);
}
@Override
public boolean keyTyped(final char character) {
return this.menuUI.keyTyped(character);
}
@Override
public boolean touchDown(final int screenX, final int screenY, final int pointer, final int button) {
final float worldScreenY = this.game.getHeight() - screenY;
if (this.menuUI.touchDown(screenX, screenY, worldScreenY, button)) {
return false;
}
return false;
}
@Override
public boolean touchUp(final int screenX, final int screenY, final int pointer, final int button) {
final float worldScreenY = this.game.getHeight() - screenY;
if (this.menuUI.touchUp(screenX, screenY, worldScreenY, button)) {
return false;
}
return false;
}
@Override
public boolean touchDragged(final int screenX, final int screenY, final int pointer) {
final float worldScreenY = this.game.getHeight() - screenY;
if (this.menuUI.touchDragged(screenX, screenY, worldScreenY, pointer)) {
return false;
}
return false;
}
@Override
public boolean mouseMoved(final int screenX, final int screenY) {
final float worldScreenY = this.game.getHeight() - screenY;
if (this.menuUI.mouseMoved(screenX, screenY, worldScreenY)) {
return false;
}
return false;
}
@Override
public boolean scrolled(final int amount) {
// TODO Auto-generated method stub
return false;
}
private void renderLibGDXContent() {
Gdx.gl30.glDisable(GL30.GL_SCISSOR_TEST);
Gdx.gl30.glDisable(GL30.GL_CULL_FACE);
this.viewer.webGL.useShaderProgram(null);
Gdx.gl30.glActiveTexture(GL30.GL_TEXTURE0);
this.uiViewport.apply();
this.batch.setProjectionMatrix(this.uiCamera.combined);
this.batch.begin();
this.menuUI.render(this.batch, this.glyphLayout);
this.batch.end();
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
}
private class LibGDXContentLayerModelInstance extends ModelInstance {
public LibGDXContentLayerModelInstance(final Model model) {
super(model);
}
@Override
public void updateAnimations(final float dt) {
}
@Override
public void clearEmittedObjects() {
}
@Override
protected void updateLights(final Scene scene2) {
}
@Override
public void renderOpaque(final Matrix4 mvp) {
}
@Override
public void renderTranslucent() {
renderLibGDXContent();
}
@Override
public void load() {
}
@Override
protected RenderBatch getBatch(final TextureMapper textureMapper2) {
throw new UnsupportedOperationException("NOT API");
}
@Override
public void setReplaceableTexture(final int replaceableTextureId, final String replaceableTextureFile) {
}
@Override
public boolean isBatched() {
return super.isBatched();
}
@Override
protected void removeLights(final Scene scene2) {
// TODO Auto-generated method stub
}
}
private class LibGDXContentLayerModel extends Model {
public LibGDXContentLayerModel(final ModelHandler handler, final ModelViewer viewer, final String extension,
final PathSolver pathSolver, final String fetchUrl) {
super(handler, viewer, extension, pathSolver, fetchUrl);
this.ok = true;
}
@Override
protected ModelInstance createInstance(final int type) {
return new LibGDXContentLayerModelInstance(this);
}
@Override
protected void lateLoad() {
}
@Override
protected void load(final InputStream src, final Object options) {
}
@Override
protected void error(final Exception e) {
}
}
@Override
public void hide() {
if (this.currentMusic != null) {
this.currentMusic.stop();
}
this.menuUI.hide();
}
@Override
public void pause() {
}
@Override
public void resume() {
}
public void startMap(final String finalFileToLoad) {
this.menuUI.startMap(finalFileToLoad);
}
public void onReturnFromGame() {
this.menuUI.onReturnFromGame();
}
}

View File

@ -0,0 +1,23 @@
package com.etheller.warsmash;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.etheller.warsmash.viewer5.CanvasProvider;
public class WarsmashGdxMultiScreenGame extends Game implements CanvasProvider {
@Override
public void create() {
}
@Override
public float getWidth() {
return Gdx.graphics.getWidth();
}
@Override
public float getHeight() {
return Gdx.graphics.getHeight();
}
}

View File

@ -0,0 +1,177 @@
package com.etheller.warsmash;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
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.Rectangle;
import com.badlogic.gdx.math.Vector3;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.viewer5.CanvasProvider;
import com.etheller.warsmash.viewer5.ModelViewer;
import com.etheller.warsmash.viewer5.PathSolver;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.ResourceHandlerConstructionParams;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.camera.PortraitCameraManager;
import com.hiveworkshop.rms.parsers.mdlx.MdlxModel;
import com.hiveworkshop.rms.parsers.mdlx.util.MdxUtils;
public class WarsmashPreviewApplication extends ApplicationAdapter implements CanvasProvider {
private DataSource codebase;
private ModelViewer viewer;
private MdxModel model;
private PortraitCameraManager cameraManager;
public static int VAO;
private final Rectangle tempRect = new Rectangle();
private BitmapFont font;
private SpriteBatch batch;
private final DataTable warsmashIni;
public WarsmashPreviewApplication(final DataTable warsmashIni) {
this.warsmashIni = warsmashIni;
}
@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);
VAO = temp.get(0);
Gdx.gl30.glBindVertexArray(VAO);
final String renderer = Gdx.gl.glGetString(GL20.GL_RENDERER);
System.err.println("Renderer: " + renderer);
this.codebase = WarsmashGdxMapScreen.parseDataSources(this.warsmashIni);
this.viewer = new MdxViewer(this.codebase, this, new Vector3(0.3f, 0.3f, -0.25f));
this.mdxHandler = new MdxHandler();
this.viewer.addHandler(this.mdxHandler);
this.viewer.enableAudio();
this.scene = this.viewer.addSimpleScene();
this.scene.enableAudio();
this.cameraManager = new PortraitCameraManager();
this.cameraManager.setupCamera(this.scene);
this.cameraManager.distance = 500;
this.cameraManager.horizontalAngle = (float) ((Math.PI) / 2);
System.out.println("Loaded");
Gdx.gl30.glClearColor(0.5f, 0.5f, 0.5f, 1); // TODO remove white background
this.font = new BitmapFont();
this.batch = new SpriteBatch();
}
public static void bindDefaultVertexArray() {
Gdx.gl30.glBindVertexArray(VAO);
}
private int frame = 0;
private MdxComplexInstance mainInstance;
private MdxModel mainModel;
private com.etheller.warsmash.viewer5.handlers.mdx.Camera modelCamera;
private final float[] cameraPositionTemp = new float[3];
private final float[] cameraTargetTemp = new float[3];
private final boolean firstFrame = true;
private Scene scene;
private MdxHandler mdxHandler;
@Override
public void render() {
Gdx.gl30.glBindVertexArray(VAO);
this.cameraManager.updateCamera();
this.viewer.updateAndRender();
this.frame++;
if ((this.frame % 1000) == 0) {
System.out.println(Integer.toString(Gdx.graphics.getFramesPerSecond()));
}
}
@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);
}
public DataSource getCodebase() {
return this.codebase;
}
public MdlxModel loadCustomModel(final String filename) {
clearMainInstance();
final MdxModel mdx = (MdxModel) this.mdxHandler.construct(new ResourceHandlerConstructionParams(this.viewer,
this.mdxHandler, ".mdx", PathSolver.DEFAULT, filename));
final MdlxModel mdlxModel;
try (FileInputStream stream = new FileInputStream(filename)) {
mdlxModel = MdxUtils.loadMdlx(stream);
mdx.load(mdlxModel);
mdx.ok = true;
// mdx.lateLoad();
}
catch (final FileNotFoundException e) {
throw new RuntimeException(e);
}
catch (final IOException e) {
throw new RuntimeException(e);
}
this.mainModel = mdx;
final MdxComplexInstance instance = (MdxComplexInstance) mdx.addInstance();
// this.cameraManager.setModelInstance(instance, mdx);
instance.setScene(this.scene);
this.mainInstance = instance;
return mdlxModel;
}
private void clearMainInstance() {
if (this.mainInstance != null) {
this.mainInstance.detach();
this.mainInstance = null;
}
this.mainModel = null;
}
public PortraitCameraManager getCameraManager() {
return this.cameraManager;
}
public MdxComplexInstance getMainInstance() {
return this.mainInstance;
}
}

View File

@ -0,0 +1,113 @@
package com.etheller.warsmash;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
public class WarsmashTestGame extends ApplicationAdapter {
private int arrayBuffer;
private int elementBuffer;
private int VAO;
@Override
public void create() {
Gdx.gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // colour to use when clearing
final ByteBuffer tempByteBuffer = ByteBuffer.allocateDirect(4);
tempByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final IntBuffer temp = tempByteBuffer.asIntBuffer();
Gdx.gl30.glGenVertexArrays(1, temp);
this.VAO = temp.get(0);
Gdx.gl30.glBindVertexArray(this.VAO);
this.shaderProgram = new ShaderProgram(vsSimple, fsSimple);
if (!this.shaderProgram.isCompiled()) {
throw new IllegalStateException(this.shaderProgram.getLog());
}
this.arrayBuffer = Gdx.gl.glGenBuffer();
this.elementBuffer = Gdx.gl.glGenBuffer();
System.out.println("arrayBuffer: " + this.arrayBuffer + ", elementBuffer: " + this.elementBuffer);
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.arrayBuffer);
this.shaderProgram.enableVertexAttribute("a_position");
this.shaderProgram.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, 0);
Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.elementBuffer);
final ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(4 * 9);
vertexByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
this.vertexBuffer = vertexByteBuffer.asFloatBuffer();
this.vertexBuffer.put(0, -1f);
this.vertexBuffer.put(1, -1f);
this.vertexBuffer.put(2, 0);
this.vertexBuffer.put(3, 1f);
this.vertexBuffer.put(4, -1f);
this.vertexBuffer.put(5, 0);
this.vertexBuffer.put(6, 0f);
this.vertexBuffer.put(7, 1f);
this.vertexBuffer.put(8, 0);
Gdx.gl.glBufferData(GL20.GL_ARRAY_BUFFER, 9 * 4, null, GL20.GL_STATIC_DRAW);
final ByteBuffer faceByteBuffer = ByteBuffer.allocateDirect(6);
faceByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
this.faceBuffer = faceByteBuffer.asShortBuffer();
this.faceBuffer.put(0, (short) 0);
this.faceBuffer.put(1, (short) 1);
this.faceBuffer.put(2, (short) 2);
Gdx.gl.glBufferData(GL20.GL_ELEMENT_ARRAY_BUFFER, 3 * 2, null, GL20.GL_STATIC_DRAW);
}
@Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
// Gdx.gl30.glBindVertexArray(this.VAO);
this.shaderProgram.begin();
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.arrayBuffer);
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 0, 9 * 4, this.vertexBuffer);
Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.elementBuffer);
Gdx.gl.glBufferSubData(GL20.GL_ELEMENT_ARRAY_BUFFER, 0, 3 * 2, this.faceBuffer);
Gdx.gl.glDrawElements(GL20.GL_TRIANGLES, 9, GL20.GL_UNSIGNED_SHORT, 0);
// Gdx.gl.glDrawArrays(GL20.GL_TRIANGLES, 0, 3);
this.shaderProgram.end();
}
@Override
public void dispose() {
}
@Override
public void resize(final int width, final int height) {
}
public static final String vsSimple = "\r\n" + //
" attribute vec3 a_position;\r\n" + //
" void main() {\r\n" + //
" gl_Position = vec4(a_position, 1.0);\r\n" + //
" }\r\n";
public static final String fsSimple = "\r\n" + //
" void main() {\r\n" + //
" gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);\r\n" + //
" }\r\n";
private ShaderProgram shaderProgram;
private FloatBuffer vertexBuffer;
private ShortBuffer faceBuffer;
}

View File

@ -0,0 +1,138 @@
package com.etheller.warsmash;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
public class WarsmashTestGame2 extends ApplicationAdapter {
private int VBO;
private int VAO;
@Override
public void create() {
final ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(4 * 9);
vertexByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final FloatBuffer vertexBuffer = vertexByteBuffer.asFloatBuffer();
vertexBuffer.put(0, -0.5f);
vertexBuffer.put(1, -0.5f);
vertexBuffer.put(2, 0);
vertexBuffer.put(3, 0.5f);
vertexBuffer.put(4, -0.5f);
vertexBuffer.put(5, 0);
vertexBuffer.put(6, 0f);
vertexBuffer.put(7, 0.5f);
vertexBuffer.put(8, 0);
vertexBuffer.clear();
Gdx.gl30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Gdx.gl30.glEnable(GL20.GL_DEPTH_TEST);
// Gdx.gl30.glEnable(GL20.GL_CULL_FACE);
final ByteBuffer tempByteBuffer = ByteBuffer.allocateDirect(4);
System.out.println(tempByteBuffer.order());
tempByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final IntBuffer temp = tempByteBuffer.asIntBuffer();
Gdx.gl30.glGenBuffers(1, temp);
this.VBO = temp.get(0);
temp.clear();
Gdx.gl30.glGenVertexArrays(1, temp);
this.VAO = temp.get(0);
Gdx.gl30.glBindVertexArray(this.VAO);
Gdx.gl30.glBindBuffer(GL30.GL_ARRAY_BUFFER, this.VBO);
Gdx.gl30.glBufferData(GL30.GL_ARRAY_BUFFER, 9 * 4, vertexByteBuffer, GL30.GL_STATIC_DRAW);
Gdx.gl30.glVertexAttribPointer(0, 3, GL30.GL_FLOAT, false, 3 * 4, 0);
Gdx.gl30.glEnableVertexAttribArray(0);
final int vertexShader = Gdx.gl30.glCreateShader(GL30.GL_VERTEX_SHADER);
Gdx.gl30.glShaderSource(vertexShader, vsSimple);
Gdx.gl30.glCompileShader(vertexShader);
temp.clear();
Gdx.gl30.glGetShaderiv(vertexShader, GL30.GL_COMPILE_STATUS, temp);
int success = temp.get(0);
if (success == 0) {
final String infoLog = Gdx.gl30.glGetShaderInfoLog(vertexShader);
System.err.println(infoLog);
throw new IllegalStateException("bad vertex shader");
}
final int fragmentShader = Gdx.gl30.glCreateShader(GL30.GL_FRAGMENT_SHADER);
Gdx.gl30.glShaderSource(fragmentShader, fsSimple);
Gdx.gl30.glCompileShader(fragmentShader);
temp.clear();
Gdx.gl30.glGetShaderiv(fragmentShader, GL30.GL_COMPILE_STATUS, temp);
success = temp.get(0);
if (success == 0) {
final String infoLog = Gdx.gl30.glGetShaderInfoLog(fragmentShader);
System.err.println(infoLog);
throw new IllegalStateException("bad fragment shader");
}
this.shaderProgram = Gdx.gl30.glCreateProgram();
Gdx.gl30.glAttachShader(this.shaderProgram, vertexShader);
Gdx.gl30.glAttachShader(this.shaderProgram, fragmentShader);
Gdx.gl30.glLinkProgram(this.shaderProgram);
temp.clear();
Gdx.gl30.glGetProgramiv(this.shaderProgram, GL30.GL_LINK_STATUS, temp);
success = temp.get(0);
if (success == 0) {
final String infoLog = Gdx.gl30.glGetProgramInfoLog(this.shaderProgram);
System.err.println(infoLog);
throw new IllegalStateException("bad program");
}
Gdx.gl30.glDeleteShader(vertexShader);
Gdx.gl30.glDeleteShader(fragmentShader);
}
@Override
public void render() {
Gdx.gl30.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl30.glUseProgram(this.shaderProgram);
Gdx.gl30.glBindVertexArray(this.VAO);
Gdx.gl30.glDrawArrays(GL30.GL_TRIANGLES, 0, 3);
}
@Override
public void dispose() {
}
@Override
public void resize(final int width, final int height) {
final int side = Math.min(width, height);
Gdx.gl30.glViewport((width - side) / 2, (height - side) / 2, side, side);
}
public static final String vsSimple = "\r\n" + //
"#version 450 core\r\n" + //
" layout(location = 0) in vec3 aPos;\r\n" + //
" void main() {\r\n" + //
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\r\n" + //
" }\r\n";
public static final String fsSimple = "\r\n" + //
"#version 450 core\r\n" + //
" out vec4 FragColor;\r\n" + //
" void main() {\r\n" + //
" FragColor = vec4(0.2f, 1.0f, 0.2f, 1.0f);\r\n" + //
" }\r\n";
private int shaderProgram;
}

View File

@ -0,0 +1,145 @@
package com.etheller.warsmash;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
public class WarsmashTestGame3 extends ApplicationAdapter {
private int VBO;
private int VAO;
@Override
public void create() {
Gdx.gl30.glBindVertexArray(0);
this.vertexByteBuffer = ByteBuffer.allocateDirect(4 * 9);
this.vertexByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final FloatBuffer vertexBuffer = this.vertexByteBuffer.asFloatBuffer();
vertexBuffer.put(0, -0.5f);
vertexBuffer.put(1, -0.5f);
vertexBuffer.put(2, 0);
vertexBuffer.put(3, 0.5f);
vertexBuffer.put(4, -0.5f);
vertexBuffer.put(5, 0);
vertexBuffer.put(6, 0f);
vertexBuffer.put(7, 0.5f);
vertexBuffer.put(8, 0);
vertexBuffer.clear();
Gdx.gl30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Gdx.gl30.glEnable(GL20.GL_DEPTH_TEST);
// Gdx.gl30.glEnable(GL20.GL_CULL_FACE);
final ByteBuffer tempByteBuffer = ByteBuffer.allocateDirect(4);
tempByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final IntBuffer temp = tempByteBuffer.asIntBuffer();
Gdx.gl30.glGenVertexArrays(1, temp);
this.VAO = temp.get(0);
Gdx.gl30.glBindVertexArray(this.VAO);
temp.clear();
Gdx.gl30.glGenBuffers(1, temp);
this.VBO = temp.get(0);
Gdx.gl30.glBindBuffer(GL30.GL_ARRAY_BUFFER, this.VBO);
Gdx.gl30.glBufferData(GL30.GL_ARRAY_BUFFER, 9 * 4, this.vertexByteBuffer, GL30.GL_STATIC_DRAW);
Gdx.gl30.glVertexAttribPointer(0, 3, GL30.GL_FLOAT, false, 3 * 4, 0);
Gdx.gl30.glEnableVertexAttribArray(0);
final int vertexShader = Gdx.gl30.glCreateShader(GL30.GL_VERTEX_SHADER);
Gdx.gl30.glShaderSource(vertexShader, vsSimple);
Gdx.gl30.glCompileShader(vertexShader);
temp.clear();
Gdx.gl30.glGetShaderiv(vertexShader, GL30.GL_COMPILE_STATUS, temp);
int success = temp.get(0);
if (success == 0) {
final String infoLog = Gdx.gl30.glGetShaderInfoLog(vertexShader);
System.err.println(infoLog);
throw new IllegalStateException("bad vertex shader");
}
final int fragmentShader = Gdx.gl30.glCreateShader(GL30.GL_FRAGMENT_SHADER);
Gdx.gl30.glShaderSource(fragmentShader, fsSimple);
Gdx.gl30.glCompileShader(fragmentShader);
temp.clear();
Gdx.gl30.glGetShaderiv(fragmentShader, GL30.GL_COMPILE_STATUS, temp);
success = temp.get(0);
if (success == 0) {
final String infoLog = Gdx.gl30.glGetShaderInfoLog(fragmentShader);
System.err.println(infoLog);
throw new IllegalStateException("bad fragment shader");
}
this.shaderProgram = Gdx.gl30.glCreateProgram();
Gdx.gl30.glAttachShader(this.shaderProgram, vertexShader);
Gdx.gl30.glAttachShader(this.shaderProgram, fragmentShader);
Gdx.gl30.glLinkProgram(this.shaderProgram);
temp.clear();
Gdx.gl30.glGetProgramiv(this.shaderProgram, GL30.GL_LINK_STATUS, temp);
success = temp.get(0);
if (success == 0) {
final String infoLog = Gdx.gl30.glGetProgramInfoLog(this.shaderProgram);
System.err.println(infoLog);
throw new IllegalStateException("bad program");
}
Gdx.gl30.glDeleteShader(vertexShader);
Gdx.gl30.glDeleteShader(fragmentShader);
}
@Override
public void render() {
Gdx.gl30.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl30.glBindVertexArray(this.VAO);
Gdx.gl30.glUseProgram(this.shaderProgram);
Gdx.gl30.glBindBuffer(GL30.GL_ARRAY_BUFFER, this.VBO);
Gdx.gl30.glVertexAttribPointer(0, 3, GL30.GL_FLOAT, false, 3 * 4, 0);
Gdx.gl30.glEnableVertexAttribArray(0);
Gdx.gl30.glDrawArrays(GL30.GL_TRIANGLES, 0, 3);
}
@Override
public void dispose() {
}
@Override
public void resize(final int width, final int height) {
final int side = Math.min(width, height);
Gdx.gl30.glViewport((width - side) / 2, (height - side) / 2, side, side);
}
public static final String vsSimple = "\r\n" + //
"#version 450 core\r\n" + //
" layout(location = 0) in vec3 aPos;\r\n" + //
" void main() {\r\n" + //
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\r\n" + //
" }\r\n";
public static final String fsSimple = "\r\n" + //
"#version 450 core\r\n" + //
" out vec4 FragColor;\r\n" + //
" void main() {\r\n" + //
" FragColor = vec4(0.2f, 1.0f, 0.2f, 1.0f);\r\n" + //
" }\r\n";
private int shaderProgram;
private ByteBuffer vertexByteBuffer;
}

View File

@ -0,0 +1,163 @@
package com.etheller.warsmash;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
public class WarsmashTestGameAttributes extends ApplicationAdapter {
private int arrayBuffer;
private int elementBuffer;
private int VAO;
@Override
public void create() {
Gdx.gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // colour to use when clearing
final ByteBuffer tempByteBuffer = ByteBuffer.allocateDirect(4);
tempByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final IntBuffer temp = tempByteBuffer.asIntBuffer();
Gdx.gl30.glGenVertexArrays(1, temp);
this.VAO = temp.get(0);
Gdx.gl30.glBindVertexArray(this.VAO);
this.shaderProgram = new ShaderProgram(vsSimple, fsSimple);
if (!this.shaderProgram.isCompiled()) {
throw new IllegalStateException(this.shaderProgram.getLog());
}
this.arrayBuffer = Gdx.gl.glGenBuffer();
this.elementBuffer = Gdx.gl.glGenBuffer();
System.out.println("arrayBuffer: " + this.arrayBuffer + ", elementBuffer: " + this.elementBuffer);
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.arrayBuffer);
Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.elementBuffer);
final ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(4 * 9);
vertexByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
this.vertexBuffer = vertexByteBuffer.asFloatBuffer();
this.vertexBuffer.put(0, -1f);
this.vertexBuffer.put(1, -1f);
this.vertexBuffer.put(2, 0);
this.vertexBuffer.put(3, 1f);
this.vertexBuffer.put(4, -1f);
this.vertexBuffer.put(5, 0);
this.vertexBuffer.put(6, 0f);
this.vertexBuffer.put(7, 1f);
this.vertexBuffer.put(8, 0);
Gdx.gl.glBufferData(GL20.GL_ARRAY_BUFFER, ((9 * 4) * 2) + 3, null, GL20.GL_STATIC_DRAW);
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 0, 9 * 4, this.vertexBuffer);
final ByteBuffer vertex2ByteBuffer = ByteBuffer.allocateDirect(4 * 9);
vertex2ByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final FloatBuffer vertexBuffer2 = vertex2ByteBuffer.asFloatBuffer();
vertexBuffer2.put(0, -1f);
vertexBuffer2.put(1, -1f);
vertexBuffer2.put(2, 0);
vertexBuffer2.put(3, 1f);
vertexBuffer2.put(4, -1f);
vertexBuffer2.put(5, 0);
vertexBuffer2.put(6, 0f);
vertexBuffer2.put(7, 1f);
vertexBuffer2.put(8, 0);
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 9 * 4, 9 * 4, vertexBuffer2);
final ByteBuffer skinByteBuffer = ByteBuffer.allocateDirect(3);
skinByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
skinByteBuffer.put((byte) 34);
skinByteBuffer.put((byte) 35);
skinByteBuffer.put((byte) 36);
skinByteBuffer.clear();
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 9 * 4 * 2, 3, skinByteBuffer);
// this.shaderProgram.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, 0);
// this.shaderProgram.enableVertexAttribute("a_position");
// this.shaderProgram.setVertexAttribute("a_position2", 3, GL20.GL_FLOAT, false, 0, 4 * 9);
// this.shaderProgram.enableVertexAttribute("a_position2");
// this.shaderProgram.setVertexAttribute("a_boneNumber", 1, GL20.GL_UNSIGNED_BYTE, false, 1, 4 * 9 * 2);
// this.shaderProgram.enableVertexAttribute("a_boneNumber");
final ByteBuffer faceByteBuffer = ByteBuffer.allocateDirect(6);
faceByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
this.faceBuffer = faceByteBuffer.asShortBuffer();
this.faceBuffer.put(0, (short) 0);
this.faceBuffer.put(1, (short) 1);
this.faceBuffer.put(2, (short) 2);
Gdx.gl.glBufferData(GL20.GL_ELEMENT_ARRAY_BUFFER, 3 * 2, null, GL20.GL_STATIC_DRAW);
final int glGetError = Gdx.gl.glGetError();
System.out.println(glGetError);
}
@Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
// Gdx.gl30.glBindVertexArray(this.VAO);
this.shaderProgram.begin();
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.arrayBuffer);
this.shaderProgram.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, 0);
this.shaderProgram.enableVertexAttribute("a_position");
this.shaderProgram.setVertexAttribute("a_position2", 3, GL20.GL_FLOAT, false, 0, 4 * 9);
this.shaderProgram.enableVertexAttribute("a_position2");
this.shaderProgram.setVertexAttribute("a_boneNumber", 1, GL20.GL_UNSIGNED_BYTE, false, 1, 4 * 9 * 2);
this.shaderProgram.enableVertexAttribute("a_boneNumber");
Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.elementBuffer);
Gdx.gl.glBufferSubData(GL20.GL_ELEMENT_ARRAY_BUFFER, 0, 3 * 2, this.faceBuffer);
Gdx.gl.glDrawElements(GL20.GL_TRIANGLES, 3, GL20.GL_UNSIGNED_SHORT, 0);
// Gdx.gl.glDrawArrays(GL20.GL_TRIANGLES, 0, 3);
this.shaderProgram.end();
}
@Override
public void dispose() {
}
@Override
public void resize(final int width, final int height) {
}
public static final String vsSimple = "\r\n" + //
" attribute vec3 a_position;\r\n" + //
" attribute vec3 a_position2;\r\n" + //
" attribute float a_boneNumber;\r\n" + //
" varying float fragNumber;\r\n" + //
" void main() {\r\n" + //
" gl_Position = vec4(a_position2.x, a_position2.y, a_position2.z, 1.0);\r\n" + //
" fragNumber = a_boneNumber;\r\n" + //
" }\r\n";
public static final String fsSimple = "\r\n" + //
" varying float fragNumber;\r\n" + //
" void main() {\r\n" + //
" if( fragNumber > 35.5 ) {\r\n" + //
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\r\n" + //
" } else if( fragNumber > 34.5 ) {\r\n" + //
" gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);\r\n" + //
" } else if( fragNumber > 33.5 ) {\r\n" + //
" gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);\r\n" + //
" } else {\r\n" + //
" gl_FragColor = vec4(fragNumber*100.0, fragNumber, fragNumber, 1.0);\r\n" + //
" }\r\n" + //
" }\r\n";
private ShaderProgram shaderProgram;
private FloatBuffer vertexBuffer;
private ShortBuffer faceBuffer;
}

View File

@ -0,0 +1,213 @@
package com.etheller.warsmash;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.Arrays;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
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.hiveworkshop.rms.parsers.mdlx.MdlxGeoset;
import com.hiveworkshop.rms.parsers.mdlx.MdlxModel;
public class WarsmashTestGameAttributes2 extends ApplicationAdapter {
private int arrayBuffer;
private int elementBuffer;
private int VAO;
private DataSource codebase;
@Override
public void create() {
final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor(
"D:\\NEEDS_ORGANIZING\\MPQBuild\\War3.mpq\\war3.mpq");
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor(
"D:\\NEEDS_ORGANIZING\\MPQBuild\\Test");
this.codebase = new CompoundDataSourceDescriptor(Arrays.<DataSourceDescriptor>asList(war3mpq, testingFolder))
.createDataSource();
final MdlxModel model;
try {
model = new MdlxModel(this.codebase.read("Buildings\\Other\\TempArtB\\TempArtB.mdx"));
}
catch (final IOException e) {
throw new RuntimeException(e);
}
Gdx.gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // colour to use when clearing
final ByteBuffer tempByteBuffer = ByteBuffer.allocateDirect(4);
tempByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final IntBuffer temp = tempByteBuffer.asIntBuffer();
Gdx.gl30.glGenVertexArrays(1, temp);
this.VAO = temp.get(0);
Gdx.gl30.glBindVertexArray(this.VAO);
this.shaderProgram = new ShaderProgram(vsSimple, fsSimple);
if (!this.shaderProgram.isCompiled()) {
throw new IllegalStateException(this.shaderProgram.getLog());
}
this.arrayBuffer = Gdx.gl.glGenBuffer();
this.elementBuffer = Gdx.gl.glGenBuffer();
System.out.println("arrayBuffer: " + this.arrayBuffer + ", elementBuffer: " + this.elementBuffer);
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.arrayBuffer);
Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.elementBuffer);
final MdlxGeoset geoset0 = model.getGeosets().get(0);
final float[] vertices = geoset0.getVertices();
final ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(4 * 9);
vertexByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
this.vertexBuffer = vertexByteBuffer.asFloatBuffer();
this.vertexBuffer.put(0, -1f);
this.vertexBuffer.put(1, -1f);
this.vertexBuffer.put(2, 0);
this.vertexBuffer.put(3, 1f);
this.vertexBuffer.put(4, -1f);
this.vertexBuffer.put(5, 0);
this.vertexBuffer.put(6, 0f);
this.vertexBuffer.put(7, 1f);
this.vertexBuffer.put(8, 0);
Gdx.gl.glBufferData(GL20.GL_ARRAY_BUFFER, ((9 * 4) * 2) + 3, null, GL20.GL_STATIC_DRAW);
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 0, 9 * 4, this.vertexBuffer);
final ByteBuffer vertex2ByteBuffer = ByteBuffer.allocateDirect(4 * 9);
vertex2ByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final FloatBuffer vertexBuffer2 = vertex2ByteBuffer.asFloatBuffer();
vertexBuffer2.put(0, -1f);
vertexBuffer2.put(1, -1f);
vertexBuffer2.put(2, 0);
vertexBuffer2.put(3, 1f);
vertexBuffer2.put(4, -1f);
vertexBuffer2.put(5, 0);
vertexBuffer2.put(6, 0f);
vertexBuffer2.put(7, 1f);
vertexBuffer2.put(8, 0);
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 9 * 4, 9 * 4, vertexBuffer2);
final ByteBuffer skinByteBuffer = ByteBuffer.allocateDirect(3);
skinByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
skinByteBuffer.put((byte) 34);
skinByteBuffer.put((byte) 35);
skinByteBuffer.put((byte) 36);
skinByteBuffer.clear();
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 9 * 4 * 2, 3, skinByteBuffer);
// this.shaderProgram.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, 0);
// this.shaderProgram.enableVertexAttribute("a_position");
// this.shaderProgram.setVertexAttribute("a_position2", 3, GL20.GL_FLOAT, false, 0, 4 * 9);
// this.shaderProgram.enableVertexAttribute("a_position2");
// this.shaderProgram.setVertexAttribute("a_boneNumber", 1, GL20.GL_UNSIGNED_BYTE, false, 1, 4 * 9 * 2);
// this.shaderProgram.enableVertexAttribute("a_boneNumber");
final ByteBuffer faceByteBuffer = ByteBuffer.allocateDirect(6);
faceByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
this.faceBuffer = faceByteBuffer.asShortBuffer();
this.faceBuffer.put(0, (short) 0);
this.faceBuffer.put(1, (short) 1);
this.faceBuffer.put(2, (short) 2);
Gdx.gl.glBufferData(GL20.GL_ELEMENT_ARRAY_BUFFER, 3 * 2, null, GL20.GL_STATIC_DRAW);
final int glGetError = Gdx.gl.glGetError();
System.out.println(glGetError);
}
@Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
// Gdx.gl30.glBindVertexArray(this.VAO);
this.shaderProgram.begin();
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.arrayBuffer);
this.shaderProgram.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, 0);
this.shaderProgram.enableVertexAttribute("a_position");
this.shaderProgram.setVertexAttribute("a_position2", 3, GL20.GL_FLOAT, false, 0, 4 * 9);
this.shaderProgram.enableVertexAttribute("a_position2");
this.shaderProgram.setVertexAttribute("a_boneNumber", 1, GL20.GL_UNSIGNED_BYTE, false, 1, 4 * 9 * 2);
this.shaderProgram.enableVertexAttribute("a_boneNumber");
Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.elementBuffer);
Gdx.gl.glBufferSubData(GL20.GL_ELEMENT_ARRAY_BUFFER, 0, 3 * 2, this.faceBuffer);
Gdx.gl.glDrawElements(GL20.GL_TRIANGLES, 3, GL20.GL_UNSIGNED_SHORT, 0);
// Gdx.gl.glDrawArrays(GL20.GL_TRIANGLES, 0, 3);
this.shaderProgram.end();
}
@Override
public void dispose() {
}
@Override
public void resize(final int width, final int height) {
}
public static final String vsSimple = "\r\n" + //
" attribute vec3 a_position;\r\n" + //
" attribute vec3 a_position2;\r\n" + //
" attribute float a_boneNumber;\r\n" + //
" varying float fragNumber;\r\n" + //
" void main() {\r\n" + //
" gl_Position = vec4(a_position2.x, a_position2.y, a_position2.z, 1.0);\r\n" + //
" fragNumber = a_boneNumber;\r\n" + //
" }\r\n";
public static final String fsSimple = "\r\n" + //
" varying float fragNumber;\r\n" + //
" void main() {\r\n" + //
" if( fragNumber > 35.5 ) {\r\n" + //
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\r\n" + //
" } else if( fragNumber > 34.5 ) {\r\n" + //
" gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);\r\n" + //
" } else if( fragNumber > 33.5 ) {\r\n" + //
" gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);\r\n" + //
" } else {\r\n" + //
" gl_FragColor = vec4(fragNumber*100.0, fragNumber, fragNumber, 1.0);\r\n" + //
" }\r\n" + //
" }\r\n";
private ShaderProgram shaderProgram;
private FloatBuffer vertexBuffer;
private ShortBuffer faceBuffer;
private static ShortBuffer wrapFaces(final int[] faces) {
final ShortBuffer wrapper = ByteBuffer.allocateDirect(faces.length * 2).order(ByteOrder.nativeOrder())
.asShortBuffer();
for (final int face : faces) {
wrapper.put((short) face);
}
wrapper.clear();
return wrapper;
}
private static ByteBuffer wrap(final byte[] skin) {
final ByteBuffer wrapper = ByteBuffer.allocateDirect(skin.length).order(ByteOrder.nativeOrder());
wrapper.put(skin);
wrapper.clear();
return wrapper;
}
private static FloatBuffer wrap(final float[] positions) {
final FloatBuffer wrapper = ByteBuffer.allocateDirect(positions.length * 4).order(ByteOrder.nativeOrder())
.asFloatBuffer();
wrapper.put(positions);
wrapper.clear();
return wrapper;
}
}

View File

@ -0,0 +1,244 @@
package com.etheller.warsmash;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import com.badlogic.gdx.ApplicationAdapter;
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.etheller.warsmash.viewer5.Shaders;
public class WarsmashTestGameTextureBuffer extends ApplicationAdapter {
private int arrayBuffer;
private int elementBuffer;
private int VAO;
private ShaderProgram shaderProgram;
private FloatBuffer vertexBuffer;
private ShortBuffer faceBuffer;
@Override
public void create() {
// ShaderProgram.pedantic = false;
Gdx.gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // colour to use when clearing
final ByteBuffer tempByteBuffer = ByteBuffer.allocateDirect(4);
tempByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final IntBuffer temp = tempByteBuffer.asIntBuffer();
Gdx.gl30.glGenVertexArrays(1, temp);
this.VAO = temp.get(0);
Gdx.gl30.glBindVertexArray(this.VAO);
System.out.println(vsSimple);
this.shaderProgram = new ShaderProgram(vsSimple, fsSimple);
if (!this.shaderProgram.isCompiled()) {
throw new IllegalStateException(this.shaderProgram.getLog());
}
this.arrayBuffer = Gdx.gl.glGenBuffer();
this.elementBuffer = Gdx.gl.glGenBuffer();
System.out.println("arrayBuffer: " + this.arrayBuffer + ", elementBuffer: " + this.elementBuffer);
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.arrayBuffer);
Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.elementBuffer);
final ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(4 * 9);
vertexByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
this.vertexBuffer = vertexByteBuffer.asFloatBuffer();
this.vertexBuffer.put(0, -1f);
this.vertexBuffer.put(1, -1f);
this.vertexBuffer.put(2, 0);
this.vertexBuffer.put(3, 1f);
this.vertexBuffer.put(4, -1f);
this.vertexBuffer.put(5, 0);
this.vertexBuffer.put(6, 0f);
this.vertexBuffer.put(7, 1f);
this.vertexBuffer.put(8, 0);
Gdx.gl.glBufferData(GL20.GL_ARRAY_BUFFER, ((9 * 4) * 2) + 3, null, GL20.GL_STATIC_DRAW);
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 0, 9 * 4, this.vertexBuffer);
final ByteBuffer vertex2ByteBuffer = ByteBuffer.allocateDirect(4 * 9);
vertex2ByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final FloatBuffer vertexBuffer2 = vertex2ByteBuffer.asFloatBuffer();
vertexBuffer2.put(0, -1f);
vertexBuffer2.put(1, -1f);
vertexBuffer2.put(2, 0);
vertexBuffer2.put(3, 1f);
vertexBuffer2.put(4, -1f);
vertexBuffer2.put(5, 0);
vertexBuffer2.put(6, 0f);
vertexBuffer2.put(7, 1f);
vertexBuffer2.put(8, 0);
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 9 * 4, 9 * 4, vertexBuffer2);
final ByteBuffer skinByteBuffer = ByteBuffer.allocateDirect(3);
skinByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
skinByteBuffer.put((byte) 34);
skinByteBuffer.put((byte) 35);
skinByteBuffer.put((byte) 36);
skinByteBuffer.clear();
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 9 * 4 * 2, 3, skinByteBuffer);
// this.shaderProgram.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, 0);
// this.shaderProgram.enableVertexAttribute("a_position");
// this.shaderProgram.setVertexAttribute("a_position2", 3, GL20.GL_FLOAT, false, 0, 4 * 9);
// this.shaderProgram.enableVertexAttribute("a_position2");
// this.shaderProgram.setVertexAttribute("a_boneNumber", 1, GL20.GL_UNSIGNED_BYTE, false, 1, 4 * 9 * 2);
// this.shaderProgram.enableVertexAttribute("a_boneNumber");
// this.shaderProgram.setUniformi("u_boneMap", 15);
final ByteBuffer faceByteBuffer = ByteBuffer.allocateDirect(6);
faceByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
this.faceBuffer = faceByteBuffer.asShortBuffer();
this.faceBuffer.put(0, (short) 0);
this.faceBuffer.put(1, (short) 1);
this.faceBuffer.put(2, (short) 2);
Gdx.gl.glBufferData(GL20.GL_ELEMENT_ARRAY_BUFFER, 3 * 2, null, GL20.GL_STATIC_DRAW);
final int glGetError = Gdx.gl.glGetError();
System.out.println(glGetError);
final ByteBuffer vertex3ByteBuffer = ByteBuffer.allocateDirect(4 * 16);
vertex3ByteBuffer.order(ByteOrder.nativeOrder());
this.vertexTextureBuffer3 = vertex3ByteBuffer.asFloatBuffer();
this.vertexTextureBuffer3.put(0, 0.5f);
this.vertexTextureBuffer3.put(1, 0);
this.vertexTextureBuffer3.put(2, 0);
this.vertexTextureBuffer3.put(3, 0);
this.vertexTextureBuffer3.put(4, 0);
this.vertexTextureBuffer3.put(5, 1);
this.vertexTextureBuffer3.put(6, 0);
this.vertexTextureBuffer3.put(7, 0);
this.vertexTextureBuffer3.put(8, 0);
this.vertexTextureBuffer3.put(9, 0);
this.vertexTextureBuffer3.put(10, 1);
this.vertexTextureBuffer3.put(11, 0);
this.vertexTextureBuffer3.put(12, 0.0f);
this.vertexTextureBuffer3.put(13, 0.0f);
this.vertexTextureBuffer3.put(14, 0);
this.vertexTextureBuffer3.put(15, 1);
// this.vertexTextureBuffer = Gdx.gl.glGenBuffer();
this.vertexTexture = Gdx.gl.glGenTexture();
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE15);
// Gdx.gl.glBindBuffer(GL20.GL_TEXTURE_2D, this.vertexTextureBuffer);
// Gdx.gl.glBindBuffer(GL20.GL_TEXTURE_2D, 0);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, this.vertexTexture);
Gdx.gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_S, GL20.GL_CLAMP_TO_EDGE);
Gdx.gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_T, GL20.GL_CLAMP_TO_EDGE);
Gdx.gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER, GL20.GL_NEAREST);
Gdx.gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER, GL20.GL_NEAREST);
Gdx.gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL30.GL_RGBA, 4, 1, 0, GL30.GL_RGBA, GL20.GL_FLOAT,
this.vertexTextureBuffer3);
}
@Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
// Gdx.gl30.glBindVertexArray(this.VAO);
this.shaderProgram.begin();
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.arrayBuffer);
this.shaderProgram.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, 0);
this.shaderProgram.enableVertexAttribute("a_position");
this.shaderProgram.setVertexAttribute("a_position2", 3, GL20.GL_FLOAT, false, 0, 4 * 9);
this.shaderProgram.enableVertexAttribute("a_position2");
this.shaderProgram.setVertexAttribute("a_boneNumber", 1, GL20.GL_UNSIGNED_BYTE, false, 1, 4 * 9 * 2);
this.shaderProgram.enableVertexAttribute("a_boneNumber");
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE15);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, this.vertexTexture);
Gdx.gl.glTexSubImage2D(GL20.GL_TEXTURE_2D, 0, 0, 0, 4, 1, GL30.GL_RGBA, GL20.GL_FLOAT,
this.vertexTextureBuffer3);
this.shaderProgram.setUniformi("u_boneMap", 15);
this.shaderProgram.setUniformf("u_vectorSize", 1f / 4);
this.shaderProgram.setUniformf("u_rowSize", 1);
Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.elementBuffer);
Gdx.gl.glBufferSubData(GL20.GL_ELEMENT_ARRAY_BUFFER, 0, 3 * 2, this.faceBuffer);
Gdx.gl.glDrawElements(GL20.GL_TRIANGLES, 3, GL20.GL_UNSIGNED_SHORT, 0);
// Gdx.gl.glDrawArrays(GL20.GL_TRIANGLES, 0, 3);
this.shaderProgram.end();
}
@Override
public void dispose() {
}
@Override
public void resize(final int width, final int height) {
}
public static final String boneTexture = ""//
+ " uniform samplerBuffer u_boneMap;\r\n" + //
// " uniform uint u_vectorSize;\r\n" + //
" uniform uint u_rowSize;\r\n" + //
" mat4 fetchMatrix(uint column, uint row) {\r\n" + //
// " column *= u_vectorSize * 4.0;\r\n" + //
// " row *= u_rowSize;\r\n" + //
" // Add in half texel to sample in the middle of the texel.\r\n" + //
" // Otherwise, since the sample is directly on the boundry, small floating point errors can cause the sample to get the wrong pixel.\r\n"
+ //
" // This is mostly noticable with NPOT textures, which the bone maps are.\r\n" + //
// " column += 0.5 * u_vectorSize;\r\n" + //
// " row += 0.5 * u_rowSize;\r\n" + //
" return mat4(texelFetch(u_boneMap, row * u_rowSize + column * 4),\r\n" + //
" texelFetch(u_boneMap, row * u_rowSize + column * 4 + 1),\r\n" + //
" texelFetch(u_boneMap, row * u_rowSize + column * 4 + 2),\r\n" + //
" texelFetch(u_boneMap, row * u_rowSize + column * 4 + 3);\r\n" + //
" }";
public static final String vsSimple = "\r\n" + //
"\r\n" + //
" attribute vec3 a_position;\r\n" + //
" attribute vec3 a_position2;\r\n" + //
" attribute float a_boneNumber;\r\n" + //
" varying float fragNumber;\r\n" + //
Shaders.boneTexture + "\r\n" + //
" void main() {\r\n" + //
" mat4 bone = fetchMatrix(0.0, 0.0);\r\n" + //
" if( a_boneNumber <= 34.5 ) {\r\n" + //
" gl_Position = vec4(a_position2.x * bone[0][0], a_position2.y, a_position2.z, 1.0);\r\n" + //
" } else {\r\n" + //
" gl_Position = vec4(a_position2.x, a_position2.y, a_position2.z, 1.0);\r\n" + //
" }\r\n" + //
" fragNumber = a_boneNumber;\r\n" + //
" }\r\n";
public static final String fsSimple = "\r\n" + //
" varying float fragNumber;\r\n" + //
Shaders.boneTexture + "\r\n" + //
" void main() {\r\n" + //
" mat4 bone = fetchMatrix(0.0, 0.0);\r\n" + //
" if( fragNumber > 35.5 ) {\r\n" + //
" gl_FragColor = bone[0];//vec4(1.0, 0.0, 0.0, 1.0);\r\n" + //
" } else if( fragNumber > 34.5 ) {\r\n" + //
" gl_FragColor = bone[1];//vec4(0.0, 1.0, 1.0, 1.0);\r\n" + //
" } else if( fragNumber > 33.5 ) {\r\n" + //
" gl_FragColor = bone[2];//vec4(1.0, 0.0, 1.0, 1.0);\r\n" + //
" } else {\r\n" + //
" gl_FragColor = vec4(fragNumber*100.0, fragNumber, fragNumber, 1.0);\r\n" + //
" }\r\n" + //
" }\r\n";
private int vertexTexture;
private int vertexTextureBuffer;
private FloatBuffer vertexTextureBuffer3;
}

View File

@ -0,0 +1,203 @@
package com.etheller.warsmash;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.etheller.warsmash.viewer5.Shaders;
import com.etheller.warsmash.viewer5.gl.DataTexture;
public class WarsmashTestGameTextureBuffer2 extends ApplicationAdapter {
private int arrayBuffer;
private int elementBuffer;
private int VAO;
@Override
public void create() {
// ShaderProgram.pedantic = false;
Gdx.gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // colour to use when clearing
final ByteBuffer tempByteBuffer = ByteBuffer.allocateDirect(4);
tempByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final IntBuffer temp = tempByteBuffer.asIntBuffer();
Gdx.gl30.glGenVertexArrays(1, temp);
this.VAO = temp.get(0);
Gdx.gl30.glBindVertexArray(this.VAO);
System.out.println(vsSimple);
this.shaderProgram = new ShaderProgram(vsSimple, fsSimple);
if (!this.shaderProgram.isCompiled()) {
throw new IllegalStateException(this.shaderProgram.getLog());
}
this.arrayBuffer = Gdx.gl.glGenBuffer();
this.elementBuffer = Gdx.gl.glGenBuffer();
System.out.println("arrayBuffer: " + this.arrayBuffer + ", elementBuffer: " + this.elementBuffer);
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.arrayBuffer);
Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.elementBuffer);
final ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(4 * 9);
vertexByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
this.vertexBuffer = vertexByteBuffer.asFloatBuffer();
this.vertexBuffer.put(0, -1f);
this.vertexBuffer.put(1, -1f);
this.vertexBuffer.put(2, 0);
this.vertexBuffer.put(3, 1f);
this.vertexBuffer.put(4, -1f);
this.vertexBuffer.put(5, 0);
this.vertexBuffer.put(6, 0f);
this.vertexBuffer.put(7, 1f);
this.vertexBuffer.put(8, 0);
Gdx.gl.glBufferData(GL20.GL_ARRAY_BUFFER, ((9 * 4) * 2) + 3, null, GL20.GL_STATIC_DRAW);
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 0, 9 * 4, this.vertexBuffer);
final ByteBuffer vertex2ByteBuffer = ByteBuffer.allocateDirect(4 * 9);
vertex2ByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final FloatBuffer vertexBuffer2 = vertex2ByteBuffer.asFloatBuffer();
vertexBuffer2.put(0, -1f);
vertexBuffer2.put(1, -1f);
vertexBuffer2.put(2, 0);
vertexBuffer2.put(3, 1f);
vertexBuffer2.put(4, -1f);
vertexBuffer2.put(5, 0);
vertexBuffer2.put(6, 0f);
vertexBuffer2.put(7, 1f);
vertexBuffer2.put(8, 0);
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 9 * 4, 9 * 4, vertexBuffer2);
final ByteBuffer skinByteBuffer = ByteBuffer.allocateDirect(3);
skinByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
skinByteBuffer.put((byte) 34);
skinByteBuffer.put((byte) 35);
skinByteBuffer.put((byte) 36);
skinByteBuffer.clear();
Gdx.gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 9 * 4 * 2, 3, skinByteBuffer);
// this.shaderProgram.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, 0);
// this.shaderProgram.enableVertexAttribute("a_position");
// this.shaderProgram.setVertexAttribute("a_position2", 3, GL20.GL_FLOAT, false, 0, 4 * 9);
// this.shaderProgram.enableVertexAttribute("a_position2");
// this.shaderProgram.setVertexAttribute("a_boneNumber", 1, GL20.GL_UNSIGNED_BYTE, false, 1, 4 * 9 * 2);
// this.shaderProgram.enableVertexAttribute("a_boneNumber");
// this.shaderProgram.setUniformi("u_boneMap", 15);
final ByteBuffer faceByteBuffer = ByteBuffer.allocateDirect(6);
faceByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
this.faceBuffer = faceByteBuffer.asShortBuffer();
this.faceBuffer.put(0, (short) 0);
this.faceBuffer.put(1, (short) 1);
this.faceBuffer.put(2, (short) 2);
Gdx.gl.glBufferData(GL20.GL_ELEMENT_ARRAY_BUFFER, 3 * 2, null, GL20.GL_STATIC_DRAW);
final int glGetError = Gdx.gl.glGetError();
System.out.println(glGetError);
final ByteBuffer vertex3ByteBuffer = ByteBuffer.allocateDirect(4 * 16);
vertex3ByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final FloatBuffer vertexBuffer3 = vertex3ByteBuffer.asFloatBuffer();
vertexBuffer3.put(0, 1);
vertexBuffer3.put(1, 0);
vertexBuffer3.put(2, 0);
vertexBuffer3.put(3, 0);
vertexBuffer3.put(4, 0);
vertexBuffer3.put(5, 1);
vertexBuffer3.put(6, 0);
vertexBuffer3.put(7, 0);
vertexBuffer3.put(8, 0);
vertexBuffer3.put(9, 0);
vertexBuffer3.put(10, 1);
vertexBuffer3.put(11, 0);
vertexBuffer3.put(12, 0.0f);
vertexBuffer3.put(13, 0.0f);
vertexBuffer3.put(14, 0);
vertexBuffer3.put(15, 1);
this.dataTexture = new DataTexture(Gdx.gl, 4, 4, 1);
this.dataTexture.bindAndUpdate(vertexBuffer3);
}
@Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
// Gdx.gl30.glBindVertexArray(this.VAO);
this.shaderProgram.begin();
this.dataTexture.bind(15);
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, this.arrayBuffer);
this.shaderProgram.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, 0);
this.shaderProgram.enableVertexAttribute("a_position");
this.shaderProgram.setVertexAttribute("a_position2", 3, GL20.GL_FLOAT, false, 0, 4 * 9);
this.shaderProgram.enableVertexAttribute("a_position2");
this.shaderProgram.setVertexAttribute("a_boneNumber", 1, GL20.GL_UNSIGNED_BYTE, false, 1, 4 * 9 * 2);
this.shaderProgram.enableVertexAttribute("a_boneNumber");
this.shaderProgram.setUniformi("u_boneMap", 15);
this.shaderProgram.setUniformf("u_vectorSize", 1f / this.dataTexture.getWidth());
this.shaderProgram.setUniformf("u_rowSize", 1);
Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, this.elementBuffer);
Gdx.gl.glBufferSubData(GL20.GL_ELEMENT_ARRAY_BUFFER, 0, 3 * 2, this.faceBuffer);
Gdx.gl.glDrawElements(GL20.GL_TRIANGLES, 3, GL20.GL_UNSIGNED_SHORT, 0);
// Gdx.gl.glDrawArrays(GL20.GL_TRIANGLES, 0, 3);
this.shaderProgram.end();
}
@Override
public void dispose() {
}
@Override
public void resize(final int width, final int height) {
}
public static final String vsSimple = "\r\n" + //
"\r\n" + //
" attribute vec3 a_position;\r\n" + //
" attribute vec3 a_position2;\r\n" + //
" attribute float a_boneNumber;\r\n" + //
" varying float fragNumber;\r\n" + //
Shaders.boneTexture + "\r\n" + //
" void main() {\r\n" + //
" mat4 bone = fetchMatrix(0.0, 0.0);\r\n" + //
" gl_Position = bone * vec4(a_position2.x, a_position2.y, a_position2.z, 1.0);\r\n" + //
" fragNumber = a_boneNumber;\r\n" + //
" }\r\n";
public static final String fsSimple = "\r\n" + //
" varying float fragNumber;\r\n" + //
" void main() {\r\n" + //
" if( fragNumber > 35.5 ) {\r\n" + //
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\r\n" + //
" } else if( fragNumber > 34.5 ) {\r\n" + //
" gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);\r\n" + //
" } else if( fragNumber > 33.5 ) {\r\n" + //
" gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);\r\n" + //
" } else {\r\n" + //
" gl_FragColor = vec4(fragNumber*100.0, fragNumber, fragNumber, 1.0);\r\n" + //
" }\r\n" + //
" }\r\n";
private ShaderProgram shaderProgram;
private FloatBuffer vertexBuffer;
private ShortBuffer faceBuffer;
private DataTexture dataTexture;
}

View File

@ -0,0 +1,47 @@
package com.etheller.warsmash;
import java.util.Arrays;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
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.util.ImageUtils;
public class WarsmashTestMyTextureGame extends ApplicationAdapter {
private DataSource codebase;
private Texture texture;
private SpriteBatch batch;
@Override
public void create() {
final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor("E:\\Backups\\Warcraft\\Data\\127");
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor(
"D:\\NEEDS_ORGANIZING\\MPQBuild\\Test");
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
this.codebase = new CompoundDataSourceDescriptor(
Arrays.<DataSourceDescriptor>asList(war3mpq, testingFolder, currentFolder)).createDataSource();
this.texture = ImageUtils.getAnyExtensionTexture(this.codebase, "Textures\\Dust3x.blp");
Gdx.gl.glClearColor(0, 0, 0, 1);
this.batch = new SpriteBatch();
this.batch.enableBlending();
}
@Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
this.batch.begin();
this.batch.draw(this.texture, 20, 20, 256, 256);
this.batch.end();
}
}

View File

@ -0,0 +1,13 @@
package com.etheller.warsmash.common;
/**
* These will probably change the further I get from the source material I am
* copying from.
*/
public enum FetchDataTypeName {
IMAGE,
TEXT,
SLK,
ARRAY_BUFFER,
BLOB;
}

View File

@ -0,0 +1,7 @@
package com.etheller.warsmash.common;
import java.io.InputStream;
public interface LoadGenericCallback {
Object call(InputStream data); // TODO typing
}

View File

@ -0,0 +1,225 @@
package com.etheller.warsmash.datasources;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import com.hiveworkshop.blizzard.casc.io.WarcraftIIICASC;
import com.hiveworkshop.blizzard.casc.io.WarcraftIIICASC.FileSystem;
import com.hiveworkshop.json.JSONArray;
import com.hiveworkshop.json.JSONObject;
import com.hiveworkshop.json.JSONTokener;
public class CascDataSource implements DataSource {
private final String[] prefixes;
private WarcraftIIICASC warcraftIIICASC;
private FileSystem rootFileSystem;
private List<String> listFile;
private Map<String, String> fileAliases;
public CascDataSource(final String warcraft3InstallPath, final String[] prefixes) {
this.prefixes = prefixes;
for (int i = 0; i < (prefixes.length / 2); i++) {
final String temp = prefixes[i];
prefixes[i] = prefixes[prefixes.length - i - 1];
prefixes[prefixes.length - i - 1] = temp;
}
try {
this.warcraftIIICASC = new WarcraftIIICASC(Paths.get(warcraft3InstallPath), true);
this.rootFileSystem = this.warcraftIIICASC.getRootFileSystem();
this.listFile = this.rootFileSystem.enumerateFiles();
this.fileAliases = new HashMap<>();
if (this.has("filealiases.json")) {
try (InputStream stream = this.getResourceAsStream("filealiases.json")) {
stream.mark(4);
if ('\ufeff' != stream.read()) {
stream.reset(); // not the BOM marker
}
final JSONArray jsonObject = new JSONArray(new JSONTokener(stream));
for (int i = 0; i < jsonObject.length(); i++) {
final JSONObject alias = jsonObject.getJSONObject(i);
final String src = alias.getString("src");
final String dest = alias.getString("dest");
this.fileAliases.put(src.toLowerCase(Locale.US).replace('/', '\\'),
dest.toLowerCase(Locale.US).replace('/', '\\'));
if ((src.toLowerCase(Locale.US).contains(".blp")
|| dest.toLowerCase(Locale.US).contains(".blp"))
&& (!alias.has("assetType") || "Texture".equals(alias.getString("assetType")))) {
// This case: I saw a texture that resolves in game but was failing in our code
// here, because of this entry:
// {"src":"Units/Human/WarWagon/SiegeEngine.blp",
// "dest":"Textures/Steamtank.blp", "assetType": "Texture"},
// Our repo here checks BLP then DDS at a high-up application level thing, and
// the problem is that this entry is written using .BLP but we must be able to
// resolve .DDS when we go to look it up. The actual model is .BLP so maybe
// that's how the game does it, but my alias mapping is happening after the
// .BLP->.DDS dynamic fix, and not before.
this.fileAliases.put(src.toLowerCase(Locale.US).replace('/', '\\').replace(".blp", ".dds"),
dest.toLowerCase(Locale.US).replace('/', '\\').replace(".blp", ".dds"));
}
}
}
}
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
@Override
public InputStream getResourceAsStream(String filepath) {
filepath = filepath.toLowerCase(Locale.US).replace('/', '\\').replace(':', '\\');
final String resolvedAlias = this.fileAliases.get(filepath);
if (resolvedAlias != null) {
filepath = resolvedAlias;
}
for (final String prefix : this.prefixes) {
final String tempFilepath = prefix + "\\" + filepath;
final InputStream stream = internalGetResourceAsStream(tempFilepath);
if (stream != null) {
return stream;
}
}
return internalGetResourceAsStream(filepath);
}
private InputStream internalGetResourceAsStream(final String tempFilepath) {
try {
if (this.rootFileSystem.isFile(tempFilepath) && this.rootFileSystem.isFileAvailable(tempFilepath)) {
final ByteBuffer buffer = this.rootFileSystem.readFileData(tempFilepath);
if (buffer.hasArray()) {
return new ByteArrayInputStream(buffer.array());
}
final byte[] data = new byte[buffer.remaining()];
buffer.clear();
buffer.get(data);
return new ByteArrayInputStream(data);
}
}
catch (final IOException e) {
throw new RuntimeException("CASC parser error for: " + tempFilepath, e);
}
return null;
}
@Override
public ByteBuffer read(String path) {
path = path.toLowerCase(Locale.US).replace('/', '\\').replace(':', '\\');
final String resolvedAlias = this.fileAliases.get(path);
if (resolvedAlias != null) {
path = resolvedAlias;
}
for (final String prefix : this.prefixes) {
final String tempFilepath = prefix + "\\" + path;
final ByteBuffer stream = internalRead(tempFilepath);
if (stream != null) {
return stream;
}
}
return internalRead(path);
}
private ByteBuffer internalRead(final String tempFilepath) {
try {
if (this.rootFileSystem.isFile(tempFilepath) && this.rootFileSystem.isFileAvailable(tempFilepath)) {
final ByteBuffer buffer = this.rootFileSystem.readFileData(tempFilepath);
return buffer;
}
}
catch (final IOException e) {
throw new RuntimeException("CASC parser error for: " + tempFilepath, e);
}
return null;
}
@Override
public File getFile(String filepath) {
filepath = filepath.toLowerCase(Locale.US).replace('/', '\\').replace(':', '\\');
final String resolvedAlias = this.fileAliases.get(filepath);
if (resolvedAlias != null) {
filepath = resolvedAlias;
}
for (final String prefix : this.prefixes) {
final String tempFilepath = prefix + "\\" + filepath;
final File file = internalGetFile(tempFilepath);
if (file != null) {
return file;
}
}
return internalGetFile(filepath);
}
private File internalGetFile(final String tempFilepath) {
try {
if (this.rootFileSystem.isFile(tempFilepath) && this.rootFileSystem.isFileAvailable(tempFilepath)) {
final ByteBuffer buffer = this.rootFileSystem.readFileData(tempFilepath);
String tmpdir = System.getProperty("java.io.tmpdir");
if (!tmpdir.endsWith(File.separator)) {
tmpdir += File.separator;
}
final String tempDir = tmpdir + "MatrixEaterExtract/";
final File tempProduct = new File(tempDir + tempFilepath.replace('\\', File.separatorChar));
tempProduct.delete();
tempProduct.getParentFile().mkdirs();
try (final FileChannel fileChannel = FileChannel.open(tempProduct.toPath(), StandardOpenOption.CREATE,
StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.TRUNCATE_EXISTING)) {
fileChannel.write(buffer);
}
tempProduct.deleteOnExit();
return tempProduct;
}
}
catch (final IOException e) {
throw new RuntimeException("CASC parser error for: " + tempFilepath, e);
}
return null;
}
@Override
public boolean has(String filepath) {
filepath = filepath.toLowerCase(Locale.US).replace('/', '\\').replace(':', '\\');
final String resolvedAlias = this.fileAliases.get(filepath);
if (resolvedAlias != null) {
filepath = resolvedAlias;
}
for (final String prefix : this.prefixes) {
final String tempFilepath = prefix + "\\" + filepath;
try {
if (this.rootFileSystem.isFile(tempFilepath)) {
return true;
}
}
catch (final IOException e) {
throw new RuntimeException("CASC parser error for: " + tempFilepath, e);
}
}
try {
return this.rootFileSystem.isFile(filepath);
}
catch (final IOException e) {
throw new RuntimeException("CASC parser error for: " + filepath, e);
}
}
@Override
public Collection<String> getListfile() {
return this.listFile;
}
@Override
public void close() throws IOException {
this.warcraftIIICASC.close();
}
}

View File

@ -0,0 +1,96 @@
package com.etheller.warsmash.datasources;
import java.util.Collections;
import java.util.List;
public class CascDataSourceDescriptor implements DataSourceDescriptor {
/**
* Generated serial id
*/
private static final long serialVersionUID = 832549098549298820L;
private final String gameInstallPath;
private final List<String> prefixes;
public CascDataSourceDescriptor(final String gameInstallPath, final List<String> prefixes) {
this.gameInstallPath = gameInstallPath;
this.prefixes = prefixes;
}
@Override
public DataSource createDataSource() {
return new CascDataSource(this.gameInstallPath, this.prefixes.toArray(new String[this.prefixes.size()]));
}
@Override
public String getDisplayName() {
return "CASC: " + this.gameInstallPath;
}
public void addPrefix(final String prefix) {
this.prefixes.add(prefix);
}
public void deletePrefix(final int index) {
this.prefixes.remove(index);
}
public void movePrefixUp(final int index) {
if (index > 0) {
Collections.swap(this.prefixes, index, index - 1);
}
}
public void movePrefixDown(final int index) {
if (index < (this.prefixes.size() - 1)) {
Collections.swap(this.prefixes, index, index + 1);
}
}
public String getGameInstallPath() {
return this.gameInstallPath;
}
public List<String> getPrefixes() {
return this.prefixes;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (prime * result) + ((this.gameInstallPath == null) ? 0 : this.gameInstallPath.hashCode());
result = (prime * result) + ((this.prefixes == null) ? 0 : this.prefixes.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final CascDataSourceDescriptor other = (CascDataSourceDescriptor) obj;
if (this.gameInstallPath == null) {
if (other.gameInstallPath != null) {
return false;
}
}
else if (!this.gameInstallPath.equals(other.gameInstallPath)) {
return false;
}
if (this.prefixes == null) {
if (other.prefixes != null) {
return false;
}
}
else if (!this.prefixes.equals(other.prefixes)) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,153 @@
package com.etheller.warsmash.datasources;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class CompoundDataSource implements DataSource {
private final List<DataSource> mpqList = new ArrayList<>();
public CompoundDataSource(final List<DataSource> dataSources) {
if (dataSources != null) {
for (final DataSource dataSource : dataSources) {
this.mpqList.add(dataSource);
}
}
}
Map<String, File> cache = new HashMap<>();
@Override
public File getFile(final String filepath) {
if (this.cache.containsKey(filepath)) {
return this.cache.get(filepath);
}
try {
for (int i = this.mpqList.size() - 1; i >= 0; i--) {
final DataSource mpq = this.mpqList.get(i);
final File tempProduct = mpq.getFile(filepath);
if (tempProduct != null) {
this.cache.put(filepath, tempProduct);
return tempProduct;
}
}
}
catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
public ByteBuffer read(final String path) throws IOException {
try {
for (int i = this.mpqList.size() - 1; i >= 0; i--) {
final DataSource mpq = this.mpqList.get(i);
final ByteBuffer buffer = mpq.read(path);
if (buffer != null) {
return buffer;
}
}
}
catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
public InputStream getResourceAsStream(final String filepath) {
try {
for (int i = this.mpqList.size() - 1; i >= 0; i--) {
final DataSource mpq = this.mpqList.get(i);
final InputStream resourceAsStream = mpq.getResourceAsStream(filepath);
if (resourceAsStream != null) {
return resourceAsStream;
}
}
}
catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
public boolean has(final String filepath) {
if (this.cache.containsKey(filepath)) {
return true;
}
for (int i = this.mpqList.size() - 1; i >= 0; i--) {
final DataSource mpq = this.mpqList.get(i);
if (mpq.has(filepath)) {
return true;
}
}
return false;
}
public void refresh(final List<DataSourceDescriptor> dataSourceDescriptors) {
for (final DataSource dataSource : this.mpqList) {
try {
dataSource.close();
}
catch (final NullPointerException e) {
e.printStackTrace();
}
catch (final IOException e) {
e.printStackTrace();
}
}
this.cache.clear();
this.mpqList.clear();
if (dataSourceDescriptors != null) {
for (final DataSourceDescriptor descriptor : dataSourceDescriptors) {
this.mpqList.add(descriptor.createDataSource());
}
}
}
public interface LoadedMPQ {
void unload();
boolean hasListfile();
boolean has(String path);
}
public Set<String> getMergedListfile() {
final Set<String> listfile = new HashSet<>();
for (final DataSource mpqGuy : this.mpqList) {
final Collection<String> dataSourceListfile = mpqGuy.getListfile();
if (dataSourceListfile != null) {
for (final String element : dataSourceListfile) {
listfile.add(element);
}
}
}
return listfile;
}
@Override
public Collection<String> getListfile() {
return getMergedListfile();
}
@Override
public void close() throws IOException {
for (final DataSource mpqGuy : this.mpqList) {
mpqGuy.close();
}
}
}

View File

@ -0,0 +1,27 @@
package com.etheller.warsmash.datasources;
import java.util.ArrayList;
import java.util.List;
public class CompoundDataSourceDescriptor implements DataSourceDescriptor {
private final List<DataSourceDescriptor> dataSourceDescriptors;
public CompoundDataSourceDescriptor(final List<DataSourceDescriptor> dataSourceDescriptors) {
this.dataSourceDescriptors = dataSourceDescriptors;
}
@Override
public DataSource createDataSource() {
final List<DataSource> dataSources = new ArrayList<>();
for (final DataSourceDescriptor descriptor : this.dataSourceDescriptors) {
dataSources.add(descriptor.createDataSource());
}
return new CompoundDataSource(dataSources);
}
@Override
public String getDisplayName() {
return "CompoundDataSourceDescriptor";
}
}

View File

@ -0,0 +1,49 @@
package com.etheller.warsmash.datasources;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Collection;
public interface DataSource {
/**
* Efficiently return a stream instance that will read the data source file's
* contents directly from the data source. For example, this will read a file
* within an MPQ or CASC storage without extracting it.
*
* @param filepath
* @return
* @throws IOException
*/
InputStream getResourceAsStream(String filepath) throws IOException;
/**
* Inefficiently copy a file from the data source onto the Hard Drive of the
* computer, and then return a java File instance pointed at the file.
*
* @param filepath
* @return
* @throws IOException
*/
File getFile(String filepath) throws IOException;
ByteBuffer read(String path) throws IOException;
/**
* Returns true if the data source contains a valid entry for a particular file.
* Some data sources (MPQs) may contain files for which this returns true, even
* though they cannot list the file in their Listfile.
*
* @param filepath
* @return
*/
boolean has(String filepath);
/**
* @return a list of data source contents, or null if no list is provided
*/
Collection<String> getListfile();
void close() throws IOException;
}

View File

@ -0,0 +1,9 @@
package com.etheller.warsmash.datasources;
import java.io.Serializable;
public interface DataSourceDescriptor extends Serializable {
DataSource createDataSource();
String getDisplayName();
}

View File

@ -0,0 +1,87 @@
package com.etheller.warsmash.datasources;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
public class FolderDataSource implements DataSource {
private final Path folderPath;
private final Set<String> listfile;
public FolderDataSource(final Path folderPath) {
this.folderPath = folderPath;
this.listfile = new HashSet<>();
try {
Files.walk(folderPath).filter(Files::isRegularFile).forEach(new Consumer<Path>() {
@Override
public void accept(final Path t) {
FolderDataSource.this.listfile.add(folderPath.relativize(t).toString());
}
});
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
@Override
public InputStream getResourceAsStream(String filepath) throws IOException {
filepath = fixFilepath(filepath);
if (!has(filepath)) {
return null;
}
return Files.newInputStream(this.folderPath.resolve(filepath), StandardOpenOption.READ);
}
@Override
public File getFile(String filepath) throws IOException {
filepath = fixFilepath(filepath);
if (!has(filepath)) {
return null;
}
return new File(this.folderPath.toString() + File.separatorChar + filepath);
}
@Override
public ByteBuffer read(String path) throws IOException {
path = fixFilepath(path);
if (!has(path)) {
return null;
}
return ByteBuffer.wrap(Files.readAllBytes(Paths.get(this.folderPath.toString(), path)));
}
@Override
public boolean has(String filepath) {
filepath = fixFilepath(filepath);
if ("".equals(filepath)) {
return false; // special case for folder data source, dont do this
}
final Path resolvedPath = this.folderPath.resolve(filepath);
return Files.exists(resolvedPath) && !Files.isDirectory(resolvedPath);
}
@Override
public Collection<String> getListfile() {
return this.listfile;
}
@Override
public void close() {
}
private static String fixFilepath(final String filepath) {
return filepath.replace('\\', File.separatorChar).replace('/', File.separatorChar).replace(':',
File.separatorChar);
}
}

View File

@ -0,0 +1,57 @@
package com.etheller.warsmash.datasources;
import java.nio.file.Paths;
public class FolderDataSourceDescriptor implements DataSourceDescriptor {
/**
* Generated serial id
*/
private static final long serialVersionUID = -476724730967709309L;
private final String folderPath;
public FolderDataSourceDescriptor(final String folderPath) {
this.folderPath = folderPath;
}
@Override
public DataSource createDataSource() {
return new FolderDataSource(Paths.get(this.folderPath));
}
@Override
public String getDisplayName() {
return "Folder: " + this.folderPath;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (prime * result) + ((this.folderPath == null) ? 0 : this.folderPath.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final FolderDataSourceDescriptor other = (FolderDataSourceDescriptor) obj;
if (this.folderPath == null) {
if (other.folderPath != null) {
return false;
}
}
else if (!this.folderPath.equals(other.folderPath)) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,166 @@
package com.etheller.warsmash.datasources;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import mpq.ArchivedFile;
import mpq.ArchivedFileExtractor;
import mpq.ArchivedFileStream;
import mpq.HashLookup;
import mpq.MPQArchive;
import mpq.MPQException;
public class MpqDataSource implements DataSource {
private final MPQArchive archive;
private final SeekableByteChannel inputChannel;
private final ArchivedFileExtractor extractor = new ArchivedFileExtractor();
public MpqDataSource(final MPQArchive archive, final SeekableByteChannel inputChannel) {
this.archive = archive;
this.inputChannel = inputChannel;
}
public MPQArchive getArchive() {
return this.archive;
}
public SeekableByteChannel getInputChannel() {
return this.inputChannel;
}
@Override
public InputStream getResourceAsStream(final String filepath) throws IOException {
ArchivedFile file = null;
try {
file = this.archive.lookupHash2(new HashLookup(filepath));
}
catch (final MPQException exc) {
if (exc.getMessage().equals("lookup not found")) {
return null;
}
else {
throw new IOException(exc);
}
}
final ArchivedFileStream stream = new ArchivedFileStream(this.inputChannel, this.extractor, file);
final InputStream newInputStream = Channels.newInputStream(stream);
return newInputStream;
}
@Override
public ByteBuffer read(final String path) throws IOException {
ArchivedFile file = null;
try {
file = this.archive.lookupHash2(new HashLookup(path));
}
catch (final MPQException exc) {
if (exc.getMessage().equals("lookup not found")) {
return null;
}
else {
throw new IOException(exc);
}
}
try (final ArchivedFileStream stream = new ArchivedFileStream(this.inputChannel, this.extractor, file)) {
final long size = stream.size();
final ByteBuffer buffer = ByteBuffer.allocate((int) size);
stream.read(buffer);
return buffer;
}
}
@Override
public File getFile(final String filepath) throws IOException {
// TODO Auto-generated method stub
// System.out.println("getting it from the outside: " +
// filepath);
ArchivedFile file = null;
try {
file = this.archive.lookupHash2(new HashLookup(filepath));
}
catch (final MPQException exc) {
if (exc.getMessage().equals("lookup not found")) {
return null;
}
else {
throw new IOException(exc);
}
}
final ArchivedFileStream stream = new ArchivedFileStream(this.inputChannel, this.extractor, file);
final InputStream newInputStream = Channels.newInputStream(stream);
String tmpdir = System.getProperty("java.io.tmpdir");
if (!tmpdir.endsWith(File.separator)) {
tmpdir += File.separator;
}
final String tempDir = tmpdir + "RMSExtract/";
final File tempProduct = new File(tempDir + filepath.replace('\\', File.separatorChar));
tempProduct.delete();
tempProduct.getParentFile().mkdirs();
Files.copy(newInputStream, tempProduct.toPath());
tempProduct.deleteOnExit();
return tempProduct;
}
@Override
public boolean has(final String filepath) {
try {
this.archive.lookupPath(filepath);
return true;
}
catch (final MPQException exc) {
if (exc.getMessage().equals("lookup not found")) {
return false;
}
else {
throw new RuntimeException(exc);
}
}
}
@Override
public Collection<String> getListfile() {
try {
final Set<String> listfile = new HashSet<>();
ArchivedFile listfileContents;
listfileContents = this.archive.lookupHash2(new HashLookup("(listfile)"));
final ArchivedFileStream stream = new ArchivedFileStream(this.inputChannel, this.extractor,
listfileContents);
final InputStream newInputStream = Channels.newInputStream(stream);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(newInputStream))) {
String line;
while ((line = reader.readLine()) != null) {
listfile.add(line);
}
}
catch (final IOException exc) {
throw new RuntimeException(exc);
}
return listfile;
}
catch (final MPQException exc) {
if (exc.getMessage().equals("lookup not found")) {
return null;
}
else {
throw new RuntimeException(exc);
}
}
}
@Override
public void close() throws IOException {
this.inputChannel.close();
}
}

View File

@ -0,0 +1,78 @@
package com.etheller.warsmash.datasources;
import java.io.IOException;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
import mpq.MPQArchive;
import mpq.MPQException;
public class MpqDataSourceDescriptor implements DataSourceDescriptor {
/**
* Generated serial id
*/
private static final long serialVersionUID = 8424254987711783598L;
private final String mpqFilePath;
public MpqDataSourceDescriptor(final String mpqFilePath) {
this.mpqFilePath = mpqFilePath;
}
@Override
public DataSource createDataSource() {
try {
SeekableByteChannel sbc;
sbc = Files.newByteChannel(Paths.get(this.mpqFilePath), EnumSet.of(StandardOpenOption.READ));
return new MpqDataSource(new MPQArchive(sbc), sbc);
}
catch (final IOException e) {
throw new RuntimeException(e);
}
catch (final MPQException e) {
throw new RuntimeException(e);
}
}
@Override
public String getDisplayName() {
return "MPQ Archive: " + this.mpqFilePath;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (prime * result) + ((this.mpqFilePath == null) ? 0 : this.mpqFilePath.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final MpqDataSourceDescriptor other = (MpqDataSourceDescriptor) obj;
if (this.mpqFilePath == null) {
if (other.mpqFilePath != null) {
return false;
}
}
else if (!this.mpqFilePath.equals(other.mpqFilePath)) {
return false;
}
return true;
}
public String getMpqFilePath() {
return this.mpqFilePath;
}
}

View File

@ -0,0 +1,55 @@
package com.etheller.warsmash.datasources;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class SubdirDataSource implements DataSource {
private final DataSource dataSource;
private final String subdir;
public SubdirDataSource(final DataSource dataSource, final String subdir) {
this.dataSource = dataSource;
this.subdir = subdir;
}
@Override
public File getFile(final String filepath) throws IOException {
return this.dataSource.getFile(this.subdir + filepath);
}
@Override
public ByteBuffer read(final String path) throws IOException {
return this.dataSource.read(this.subdir + path);
}
@Override
public InputStream getResourceAsStream(final String filepath) throws IOException {
return this.dataSource.getResourceAsStream(this.subdir + filepath);
}
@Override
public boolean has(final String filepath) {
return this.dataSource.has(this.subdir + filepath);
}
@Override
public Collection<String> getListfile() {
final List<String> results = new ArrayList<>();
for (final String x : this.dataSource.getListfile()) {
if (x.startsWith(this.subdir)) {
results.add(x.substring(this.subdir.length()));
}
}
return results;
}
@Override
public void close() throws IOException {
this.dataSource.close();
}
}

View File

@ -0,0 +1,32 @@
package com.etheller.warsmash.networking;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import com.etheller.warsmash.util.WarsmashConstants;
public class TestClient {
public static void main(final String[] args) {
try {
try (final DatagramChannel channel = DatagramChannel.open()
.connect(new InetSocketAddress(InetAddress.getLocalHost(), WarsmashConstants.PORT_NUMBER))) {
final ByteBuffer buffer = ByteBuffer.allocate(256);
buffer.clear();
buffer.put((byte) 3);
buffer.put((byte) 2);
buffer.put((byte) 4);
buffer.put((byte) 1);
buffer.flip();
channel.write(buffer);
}
}
catch (final IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,82 @@
package com.etheller.warsmash.networking;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Set;
import com.etheller.warsmash.util.WarsmashConstants;
public class WarsmashGameServer implements Runnable {
private final Selector selector;
private boolean running;
private final SelectionKey key;
private final ByteBuffer readBuffer;
public WarsmashGameServer() throws IOException {
this.selector = Selector.open();
this.running = true;
final DatagramChannel channel = DatagramChannel.open()
.bind(new InetSocketAddress(WarsmashConstants.PORT_NUMBER));
channel.configureBlocking(false);
this.key = channel.register(this.selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
this.readBuffer = ByteBuffer.allocate(256);
}
@Override
public void run() {
while (this.running) {
try {
final int selectedKeyCount = this.selector.select();
if (selectedKeyCount > 0) {
final Set<SelectionKey> selectedKeys = this.selector.selectedKeys();
final Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
final SelectionKey key = keyIterator.next();
if (key.isReadable()) {
final DatagramChannel channel = (DatagramChannel) key.channel();
this.readBuffer.clear();
final SocketAddress receiveAddr = channel.receive(this.readBuffer);
this.readBuffer.flip();
System.out.println("NOTE - Received from: " + receiveAddr);
while (this.readBuffer.hasRemaining()) {
System.out.println("NOTE - Received: " + this.readBuffer.get());
}
}
keyIterator.remove();
}
}
}
catch (final IOException e) {
System.err.println("Error reading from channel:");
e.printStackTrace();
}
}
}
public void setRunning(final boolean running) {
this.running = running;
}
public static void main(final String[] args) {
WarsmashGameServer warsmashGameServer;
try {
warsmashGameServer = new WarsmashGameServer();
new Thread(warsmashGameServer).start();
}
catch (final IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,48 @@
package com.etheller.warsmash.parsers.fdf;
import java.io.IOException;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.fdfparser.FDFLexer;
import com.etheller.warsmash.fdfparser.FDFParser;
import com.etheller.warsmash.fdfparser.FDFParserBuilder;
public class DataSourceFDFParserBuilder implements FDFParserBuilder {
private final DataSource dataSource;
public DataSourceFDFParserBuilder(final DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public FDFParser build(final String path) {
FDFLexer lexer;
try {
lexer = new FDFLexer(CharStreams.fromStream(this.dataSource.getResourceAsStream(path)));
}
catch (final IOException e) {
throw new RuntimeException(e);
}
final FDFParser fdfParser = new FDFParser(new CommonTokenStream(lexer));
final BaseErrorListener errorListener = new BaseErrorListener() {
@Override
public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line,
final int charPositionInLine, final String msg, final RecognitionException e) {
String sourceName = path;
if (!sourceName.isEmpty()) {
sourceName = String.format("%s:%d:%d: ", sourceName, line, charPositionInLine);
}
System.err.println(sourceName + "line " + line + ":" + charPositionInLine + " " + msg);
}
};
fdfParser.addErrorListener(errorListener);
return fdfParser;
}
}

View File

@ -0,0 +1,44 @@
package com.etheller.warsmash.parsers.fdf;
import java.util.HashMap;
import java.util.Map;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.units.Element;
import com.etheller.warsmash.util.DataSourceFileHandle;
public class DynamicFontGeneratorHolder {
private final DataSource dataSource;
private final Element skin;
private final Map<String, FreeTypeFontGenerator> fontNameToGenerator;
public DynamicFontGeneratorHolder(final DataSource dataSource, final Element skin) {
this.dataSource = dataSource;
this.skin = skin;
this.fontNameToGenerator = new HashMap<>();
}
public FreeTypeFontGenerator getFontGenerator(final String font) {
FreeTypeFontGenerator fontGenerator = this.fontNameToGenerator.get(font);
if (fontGenerator == null) {
final String fontName = this.skin.getField(font);
if (fontName == null) {
throw new IllegalStateException("No such font: " + font);
}
if (!this.dataSource.has(fontName)) {
throw new IllegalStateException("No such font file: " + fontName + " (for \"" + font + "\")");
}
fontGenerator = new FreeTypeFontGenerator(new DataSourceFileHandle(this.dataSource, fontName));
this.fontNameToGenerator.put(font, fontGenerator);
}
return fontGenerator;
}
public void dispose() {
for (final FreeTypeFontGenerator generator : this.fontNameToGenerator.values()) {
generator.dispose();
}
this.fontNameToGenerator.clear();
}
}

View File

@ -0,0 +1,22 @@
package com.etheller.warsmash.parsers.fdf;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.Element;
public class GameSkin {
private final Element skin;
private final DataTable skinsTable;
public GameSkin(final Element skin, final DataTable skinsTable) {
this.skin = skin;
this.skinsTable = skinsTable;
}
public Element getSkin() {
return this.skin;
}
public DataTable getSkinsTable() {
return this.skinsTable;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
package com.etheller.warsmash.parsers.fdf;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
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.fdfparser.FDFParser;
import com.etheller.warsmash.fdfparser.FrameDefinitionVisitor;
import com.etheller.warsmash.parsers.fdf.datamodel.FrameDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FrameTemplateEnvironment;
public class Main {
public static final boolean REPORT_SYNTAX_ERRORS = true;
public static void main(final String[] args) {
if (args.length < 1) {
System.err.println("Usage: <Filename>");
return;
}
try {
final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor(
"E:\\Backups\\Warcraft\\Data\\127");
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor(
"E:\\Backups\\Warsmash\\Data");
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
final DataSource dataSource = new CompoundDataSourceDescriptor(
Arrays.<DataSourceDescriptor>asList(war3mpq, testingFolder, currentFolder)).createDataSource();
final FrameTemplateEnvironment templates = new FrameTemplateEnvironment();
final DataSourceFDFParserBuilder dataSourceFDFParserBuilder = new DataSourceFDFParserBuilder(dataSource);
final FrameDefinitionVisitor fdfVisitor = new FrameDefinitionVisitor(templates, dataSourceFDFParserBuilder);
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(dataSource.getResourceAsStream("UI\\FrameDef\\FrameDef.toc")))) {
String line;
while ((line = reader.readLine()) != null) {
final FDFParser firstFileParser = dataSourceFDFParserBuilder.build(line);
fdfVisitor.visit(firstFileParser.program());
}
}
final FrameDefinition bnetChat = templates.getFrame("ConsoleUI");
System.out.println("Value of ConsoleUI: " + bnetChat);
}
catch (final Exception exc) {
exc.printStackTrace();
System.err.println(exc.getMessage());
}
}
}

View File

@ -0,0 +1,38 @@
package com.etheller.warsmash.parsers.fdf;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
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.hiveworkshop.rms.parsers.mdlx.MdlxModel;
import com.hiveworkshop.rms.parsers.mdlx.util.MdxUtils;
public class ModelExport {
public static void main(final String[] args) {
final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor("E:\\Backups\\Warcraft\\Data\\127");
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor("E:\\Backups\\Warsmash\\Data");
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
final DataSource dataSource = new CompoundDataSourceDescriptor(
Arrays.<DataSourceDescriptor>asList(war3mpq, testingFolder, currentFolder)).createDataSource();
try (InputStream modelStream = dataSource
.getResourceAsStream("UI\\Glues\\MainMenu\\MainMenu3D\\MainMenu3D.mdx")) {
final MdlxModel model = new MdlxModel(dataSource.read("UI\\Glues\\MainMenu\\MainMenu3D\\MainMenu3D.mdx"));
try (FileOutputStream fos = new FileOutputStream(new File("C:\\Temp\\MainMenu3D.mdl"))) {
MdxUtils.saveMdl(model, fos);
}
}
catch (final IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,397 @@
package com.etheller.warsmash.parsers.fdf.frames;
import java.util.EnumMap;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
public abstract class AbstractRenderableFrame implements UIFrame {
private static final FramePoint[] LEFT_ANCHOR_PRIORITY = { FramePoint.LEFT, FramePoint.TOPLEFT,
FramePoint.BOTTOMLEFT };
private static final FramePoint[] RIGHT_ANCHOR_PRIORITY = { FramePoint.RIGHT, FramePoint.TOPRIGHT,
FramePoint.BOTTOMRIGHT };
private static final FramePoint[] CENTER_HORIZ_ANCHOR_PRIORITY = { FramePoint.CENTER, FramePoint.TOP,
FramePoint.BOTTOM };
private static final FramePoint[] CENTER_VERT_ANCHOR_PRIORITY = { FramePoint.CENTER, FramePoint.LEFT,
FramePoint.RIGHT };
private static final FramePoint[] TOP_ANCHOR_PRIORITY = { FramePoint.TOP, FramePoint.TOPLEFT, FramePoint.TOPRIGHT };
private static final FramePoint[] BOTTOM_ANCHOR_PRIORITY = { FramePoint.BOTTOM, FramePoint.BOTTOMLEFT,
FramePoint.BOTTOMRIGHT };
private static final boolean DEBUG_LOG = false;
protected String name;
protected UIFrame parent;
protected boolean visible = true;
protected int level;
protected final Rectangle renderBounds = new Rectangle(0, 0, 0, 0); // in libgdx rendering space
private final EnumMap<FramePoint, FramePointAssignment> framePointToAssignment = new EnumMap<>(FramePoint.class);
protected float assignedHeight;
protected float assignedWidth;
public AbstractRenderableFrame(final String name, final UIFrame parent) {
this.name = name;
this.parent = parent;
}
@Override
public void setSetAllPoints(final boolean setAllPoints) {
for (final FramePoint framePoint : FramePoint.values()) {
if (!this.framePointToAssignment.containsKey(framePoint)) {
this.framePointToAssignment.put(framePoint, new SetPoint(framePoint, this.parent, framePoint, 0, 0));
}
}
}
@Override
public void setSetAllPoints(final boolean setAllPoints, final float inset) {
this.framePointToAssignment.put(FramePoint.TOPLEFT,
new SetPoint(FramePoint.TOPLEFT, this.parent, FramePoint.TOPLEFT, inset, -inset));
this.framePointToAssignment.put(FramePoint.LEFT,
new SetPoint(FramePoint.LEFT, this.parent, FramePoint.LEFT, inset, 0));
this.framePointToAssignment.put(FramePoint.BOTTOMLEFT,
new SetPoint(FramePoint.BOTTOMLEFT, this.parent, FramePoint.BOTTOMLEFT, inset, inset));
this.framePointToAssignment.put(FramePoint.BOTTOM,
new SetPoint(FramePoint.BOTTOM, this.parent, FramePoint.BOTTOM, 0, inset));
this.framePointToAssignment.put(FramePoint.BOTTOMRIGHT,
new SetPoint(FramePoint.BOTTOMRIGHT, this.parent, FramePoint.BOTTOMRIGHT, -inset, inset));
this.framePointToAssignment.put(FramePoint.RIGHT,
new SetPoint(FramePoint.RIGHT, this.parent, FramePoint.RIGHT, -inset, 0));
this.framePointToAssignment.put(FramePoint.TOPRIGHT,
new SetPoint(FramePoint.TOPRIGHT, this.parent, FramePoint.TOPRIGHT, -inset, -inset));
this.framePointToAssignment.put(FramePoint.TOP,
new SetPoint(FramePoint.TOP, this.parent, FramePoint.TOP, 0, -inset));
this.framePointToAssignment.put(FramePoint.CENTER,
new SetPoint(FramePoint.CENTER, this.parent, FramePoint.CENTER, 0, 0));
}
@Override
public void setWidth(final float width) {
this.assignedWidth = width;
this.renderBounds.width = width;
}
@Override
public float getAssignedWidth() {
return this.assignedWidth;
}
@Override
public float getAssignedHeight() {
return this.assignedHeight;
}
@Override
public void setHeight(final float height) {
this.assignedHeight = height;
this.renderBounds.height = height;
}
private FramePointAssignment getByPriority(final FramePoint[] priorities) {
for (final FramePoint priorityFramePoint : priorities) {
final FramePointAssignment framePointAssignment = this.framePointToAssignment.get(priorityFramePoint);
if (framePointAssignment != null) {
return framePointAssignment;
}
}
return null;
}
public void clearFramePointAssignments() {
this.framePointToAssignment.clear();
}
private FramePointAssignment getLeftAnchor() {
return getByPriority(LEFT_ANCHOR_PRIORITY);
}
private FramePointAssignment getRightAnchor() {
return getByPriority(RIGHT_ANCHOR_PRIORITY);
}
private FramePointAssignment getTopAnchor() {
return getByPriority(TOP_ANCHOR_PRIORITY);
}
private FramePointAssignment getBottomAnchor() {
return getByPriority(BOTTOM_ANCHOR_PRIORITY);
}
private FramePointAssignment getCenterHorizontalAnchor() {
return getByPriority(CENTER_HORIZ_ANCHOR_PRIORITY);
}
private FramePointAssignment getCenterVerticalAnchor() {
return getByPriority(CENTER_VERT_ANCHOR_PRIORITY);
}
@Override
public float getFramePointX(final FramePoint framePoint) {
switch (framePoint) {
case CENTER:
case BOTTOM:
case TOP:
return this.renderBounds.x + (this.renderBounds.width / 2);
case BOTTOMLEFT:
case LEFT:
case TOPLEFT:
return this.renderBounds.x;
case BOTTOMRIGHT:
case RIGHT:
case TOPRIGHT:
return this.renderBounds.x + this.renderBounds.width;
default:
return 0;
}
}
@Override
public void setFramePointX(final FramePoint framePoint, final float x) {
if (this.renderBounds.width == 0) {
this.renderBounds.x = x;
return;
}
switch (framePoint) {
case CENTER:
case BOTTOM:
case TOP:
this.renderBounds.x = x - (this.renderBounds.width / 2);
return;
case BOTTOMLEFT:
case LEFT:
case TOPLEFT:
if (getRightAnchor() != null) {
final float oldRightX = this.renderBounds.x + this.renderBounds.width;
this.renderBounds.x = x;
this.renderBounds.width = oldRightX - x;
}
else {
// no right anchor, keep width
this.renderBounds.x = x;
}
return;
case BOTTOMRIGHT:
case RIGHT:
case TOPRIGHT:
if (getLeftAnchor() != null) {
this.renderBounds.width = x - this.renderBounds.x;
}
else {
this.renderBounds.x = x - this.renderBounds.width;
}
return;
default:
return;
}
}
@Override
public float getFramePointY(final FramePoint framePoint) {
switch (framePoint) {
case LEFT:
case CENTER:
case RIGHT:
return this.renderBounds.y + (this.renderBounds.height / 2);
case BOTTOMLEFT:
case BOTTOM:
case BOTTOMRIGHT:
return this.renderBounds.y;
case TOPLEFT:
case TOP:
case TOPRIGHT:
return this.renderBounds.y + this.renderBounds.height;
default:
return 0;
}
}
@Override
public void setFramePointY(final FramePoint framePoint, final float y) {
if (this.renderBounds.height == 0) {
this.renderBounds.y = y;
return;
}
switch (framePoint) {
case LEFT:
case CENTER:
case RIGHT:
this.renderBounds.y = y - (this.renderBounds.height / 2);
return;
case TOPLEFT:
case TOP:
case TOPRIGHT:
if (getBottomAnchor() != null) {
this.renderBounds.height = y - this.renderBounds.y;
}
else {
this.renderBounds.y = y - this.renderBounds.height;
}
return;
case BOTTOMLEFT:
case BOTTOM:
case BOTTOMRIGHT:
if (getTopAnchor() != null) {
final float oldBottomY = this.renderBounds.y + this.renderBounds.height;
this.renderBounds.y = y;
this.renderBounds.height = oldBottomY - y;
}
else {
this.renderBounds.y = y;
}
return;
default:
return;
}
}
@Override
public void addAnchor(final AnchorDefinition anchorDefinition) {
this.framePointToAssignment.put(anchorDefinition.getMyPoint(), new SetPoint(anchorDefinition.getMyPoint(),
this.parent, anchorDefinition.getMyPoint(), anchorDefinition.getX(), anchorDefinition.getY()));
}
@Override
public void addSetPoint(final SetPoint setPointDefinition) {
this.framePointToAssignment.put(setPointDefinition.getMyPoint(), setPointDefinition);
}
@Override
public void positionBounds(final GameUI gameUI, final Viewport viewport) {
if (this.parent == null) {
// TODO this is a bit of a hack, remove later
return;
}
if (this.framePointToAssignment.isEmpty()) {
this.renderBounds.x = this.parent.getFramePointX(FramePoint.LEFT);
this.renderBounds.y = this.parent.getFramePointY(FramePoint.BOTTOM);
}
else {
final FramePointAssignment leftAnchor = getLeftAnchor();
final FramePointAssignment rightAnchor = getRightAnchor();
final FramePointAssignment topAnchor = getTopAnchor();
final FramePointAssignment bottomAnchor = getBottomAnchor();
final FramePointAssignment centerHorizontalAnchor = getCenterHorizontalAnchor();
final FramePointAssignment centerVerticalAnchor = getCenterVerticalAnchor();
if (leftAnchor != null) {
this.renderBounds.x = leftAnchor.getX(gameUI, viewport);
if (this.assignedWidth == 0) {
if (rightAnchor != null) {
this.renderBounds.width = rightAnchor.getX(gameUI, viewport) - this.renderBounds.x;
}
else if (centerHorizontalAnchor != null) {
this.renderBounds.width = (centerHorizontalAnchor.getX(gameUI, viewport) - this.renderBounds.x)
* 2;
}
}
}
else if (rightAnchor != null) {
this.renderBounds.x = rightAnchor.getX(gameUI, viewport) - this.renderBounds.width;
if (centerHorizontalAnchor != null) {
this.renderBounds.width = (this.renderBounds.x - centerHorizontalAnchor.getX(gameUI, viewport)) * 2;
}
}
else if (centerHorizontalAnchor != null) {
this.renderBounds.x = centerHorizontalAnchor.getX(gameUI, viewport) - (this.renderBounds.width / 2);
}
if (bottomAnchor != null) {
this.renderBounds.y = bottomAnchor.getY(gameUI, viewport);
if (this.assignedHeight == 0) {
if (topAnchor != null) {
this.renderBounds.height = topAnchor.getY(gameUI, viewport) - this.renderBounds.y;
}
else if (centerVerticalAnchor != null) {
this.renderBounds.height = (centerVerticalAnchor.getY(gameUI, viewport) - this.renderBounds.y)
* 2;
}
}
}
else if (topAnchor != null) {
this.renderBounds.y = topAnchor.getY(gameUI, viewport) - this.renderBounds.height;
if (centerVerticalAnchor != null) {
this.renderBounds.height = (this.renderBounds.y - centerVerticalAnchor.getY(gameUI, viewport)) * 2;
}
}
else if (centerVerticalAnchor != null) {
this.renderBounds.y = centerVerticalAnchor.getY(gameUI, viewport) - (this.renderBounds.height / 2);
}
}
if (DEBUG_LOG) {
System.out.println(getClass().getSimpleName() + ":" + this.name + ":" + hashCode()
+ " finishing position bounds: " + this.renderBounds);
}
innerPositionBounds(gameUI, viewport);
}
protected abstract void innerPositionBounds(GameUI gameUI, final Viewport viewport);
@Override
public boolean isVisible() {
return this.visible;
}
public int getLevel() {
return this.level;
}
@Override
public void setVisible(final boolean visible) {
this.visible = visible;
}
public void setLevel(final int level) {
this.level = level;
}
@Override
public final void render(final SpriteBatch batch, final BitmapFont font20, final GlyphLayout glyphLayout) {
if (this.visible) {
internalRender(batch, font20, glyphLayout);
}
}
@Override
public UIFrame getParent() {
return this.parent;
}
@Override
public boolean isVisibleOnScreen() {
boolean visibleOnScreen = this.visible;
UIFrame ancestor = this.parent;
while (visibleOnScreen && (ancestor != null)) {
visibleOnScreen &= ancestor.isVisible();
ancestor = ancestor.getParent();
}
return visibleOnScreen;
}
protected abstract void internalRender(SpriteBatch batch, BitmapFont baseFont, GlyphLayout glyphLayout);
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
return null;
}
@Override
public UIFrame touchUp(final float screenX, final float screenY, final int button) {
return null;
}
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
return null;
}
@Override
public String getName() {
return this.name;
}
public Rectangle getRenderBounds() {
return this.renderBounds;
}
}

View File

@ -0,0 +1,90 @@
package com.etheller.warsmash.parsers.fdf.frames;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
public abstract class AbstractUIFrame extends AbstractRenderableFrame implements UIFrame {
private final List<UIFrame> childFrames = new ArrayList<>();
public void add(final UIFrame childFrame) {
if (childFrame == null) {
return;
}
this.childFrames.add(childFrame);
}
public void remove(final UIFrame childFrame) {
if (childFrame == null) {
return;
}
this.childFrames.remove(childFrame);
}
public AbstractUIFrame(final String name, final UIFrame parent) {
super(name, parent);
}
@Override
public void setVisible(final boolean visible) {
super.setVisible(visible);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
for (final UIFrame childFrame : this.childFrames) {
childFrame.render(batch, baseFont, glyphLayout);
}
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
for (final UIFrame childFrame : this.childFrames) {
childFrame.positionBounds(gameUI, viewport);
}
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (isVisible()) {
for (final UIFrame childFrame : this.childFrames) {
final UIFrame clickedChild = childFrame.touchDown(screenX, screenY, button);
if (clickedChild != null) {
return clickedChild;
}
}
}
return super.touchDown(screenX, screenY, button);
}
@Override
public UIFrame touchUp(final float screenX, final float screenY, final int button) {
if (isVisible()) {
for (final UIFrame childFrame : this.childFrames) {
final UIFrame clickedChild = childFrame.touchUp(screenX, screenY, button);
if (clickedChild != null) {
return clickedChild;
}
}
}
return super.touchUp(screenX, screenY, button);
}
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
if (isVisible()) {
for (final UIFrame childFrame : this.childFrames) {
final UIFrame clickedChild = childFrame.getFrameChildUnderMouse(screenX, screenY);
if (clickedChild != null) {
return clickedChild;
}
}
}
return super.getFrameChildUnderMouse(screenX, screenY);
}
}

View File

@ -0,0 +1,36 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
public class AnchorPoint implements FramePointAssignment {
private final FramePoint framePoint;
private final float x;
private final float y;
public AnchorPoint(final FramePoint framePoint, final float x, final float y) {
this.framePoint = framePoint;
this.x = x;
this.y = y;
}
public float getX() {
return this.x;
}
public float getY() {
return this.y;
}
@Override
public float getX(final GameUI gameUI, final Viewport uiViewport) {
return gameUI.getFramePointX(this.framePoint) + this.x;
}
@Override
public float getY(final GameUI gameUI, final Viewport uiViewport) {
return gameUI.getFramePointY(this.framePoint) + this.y;
}
}

View File

@ -0,0 +1,197 @@
package com.etheller.warsmash.parsers.fdf.frames;
import java.util.EnumSet;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.etheller.warsmash.parsers.fdf.datamodel.BackdropCornerFlags;
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
public class BackdropFrame extends AbstractUIFrame {
private final boolean decorateFileNames;
private final boolean tileBackground;
private final Texture background;
private final EnumSet<BackdropCornerFlags> cornerFlags;
private final float cornerSize;
private float backgroundSize;
private final Vector4Definition backgroundInsets;
private final Texture edgeFile;
private final float edgeFileWidth;
private final float edgeUVWidth;
private final float edgeFileHeight;
private final float edgeUVHeight;
private final boolean mirrored;
public BackdropFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
final boolean tileBackground, final Texture background, final EnumSet<BackdropCornerFlags> cornerFlags,
final float cornerSize, final float backgroundSize, final Vector4Definition backgroundInsets,
final Texture edgeFile, final boolean mirrored) {
super(name, parent);
this.decorateFileNames = decorateFileNames;
this.tileBackground = tileBackground && (backgroundSize > 0);
this.background = background;
this.cornerFlags = cornerFlags;
this.cornerSize = cornerSize;
this.backgroundSize = backgroundSize;
this.backgroundInsets = backgroundInsets;
this.edgeFile = edgeFile;
this.edgeFileWidth = edgeFile == null ? 0.0f : edgeFile.getWidth();
this.edgeFileHeight = edgeFile == null ? 0.0f : edgeFile.getHeight();
this.edgeUVWidth = 1f / 8f;
this.edgeUVHeight = 1f;
this.mirrored = mirrored;
this.backgroundSize -= (backgroundInsets.getX() + backgroundInsets.getY() + backgroundInsets.getZ()
+ backgroundInsets.getW()) / 2f;
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
if (this.background != null) {
final float backgroundX = this.renderBounds.x + this.backgroundInsets.getX();
final float backgroundY = this.renderBounds.y + this.backgroundInsets.getY();
final float backgroundWidth = this.renderBounds.width - this.backgroundInsets.getX()
- this.backgroundInsets.getZ();
final float backgroundHeight = this.renderBounds.height - this.backgroundInsets.getY()
- this.backgroundInsets.getW();
if (this.tileBackground) {
final float backgroundVerticalRepeatCount = (backgroundHeight / this.backgroundSize);
final float backgroundHorizontalRepeatCount = backgroundWidth / this.backgroundSize;
final float backgroundHeightRemainder = backgroundHeight % this.backgroundSize;
final float backgroundHeightRemainderRatio = backgroundHeightRemainder / this.backgroundSize;
final float backgroundWidthRemainder = backgroundWidth % this.backgroundSize;
final float backgroundWidthRemainderRatio = backgroundWidthRemainder / this.backgroundSize;
final int backgroundVerticalFloorRepeatCount = (int) Math.floor(backgroundVerticalRepeatCount);
final int backgroundHorizontalFloorRepeatCount = (int) Math.floor(backgroundHorizontalRepeatCount);
for (int j = 0; j < backgroundVerticalFloorRepeatCount; j++) {
for (int i = 0; i < backgroundHorizontalFloorRepeatCount; i++) {
batch.draw(this.background, backgroundX + (i * this.backgroundSize),
backgroundY + (j * this.backgroundSize), this.backgroundSize, this.backgroundSize);
}
batch.draw(this.background,
backgroundX + ((backgroundHorizontalFloorRepeatCount) * this.backgroundSize),
backgroundY + (j * this.backgroundSize), backgroundWidthRemainder, this.backgroundSize, 0,
1.0f, backgroundWidthRemainderRatio, 0);
}
for (int i = 0; i < backgroundHorizontalFloorRepeatCount; i++) {
batch.draw(this.background, backgroundX + (i * this.backgroundSize),
backgroundY + (backgroundVerticalFloorRepeatCount * this.backgroundSize),
this.backgroundSize, backgroundHeightRemainder, 0, 1.0f, 1.0f,
backgroundHeightRemainderRatio);
}
batch.draw(this.background,
backgroundX + ((backgroundHorizontalFloorRepeatCount) * this.backgroundSize),
backgroundY + (backgroundVerticalFloorRepeatCount * this.backgroundSize),
backgroundWidthRemainder, backgroundHeightRemainder, 0, 1.0f, backgroundWidthRemainderRatio,
backgroundHeightRemainderRatio);
}
else {
if (this.mirrored) {
batch.draw(this.background, backgroundX, backgroundY, backgroundWidth, backgroundHeight, 0, 0,
this.background.getWidth(), this.background.getHeight(), true, false);
}
else {
batch.draw(this.background, backgroundX, backgroundY, backgroundWidth, backgroundHeight);
}
}
}
if (this.edgeFile != null) {
if (this.cornerFlags.contains(BackdropCornerFlags.BL)) {
batch.draw(this.edgeFile, this.renderBounds.x, this.renderBounds.y, this.cornerSize, this.cornerSize,
this.edgeUVWidth * 6, this.edgeUVHeight, this.edgeUVWidth * 7, 0);
}
if (this.cornerFlags.contains(BackdropCornerFlags.BR)) {
batch.draw(this.edgeFile, (this.renderBounds.x + this.renderBounds.width) - this.cornerSize,
this.renderBounds.y, this.cornerSize, this.cornerSize, this.edgeUVWidth * 7, this.edgeUVHeight,
this.edgeUVWidth * 8, 0);
}
if (this.cornerFlags.contains(BackdropCornerFlags.UL)) {
batch.draw(this.edgeFile, this.renderBounds.x,
this.renderBounds.y + (this.renderBounds.height - this.cornerSize), this.cornerSize,
this.cornerSize, this.edgeUVWidth * 4, this.edgeUVHeight, this.edgeUVWidth * 5, 0);
}
if (this.cornerFlags.contains(BackdropCornerFlags.UR)) {
batch.draw(this.edgeFile, (this.renderBounds.x + this.renderBounds.width) - this.cornerSize,
this.renderBounds.y + (this.renderBounds.height - this.cornerSize), this.cornerSize,
this.cornerSize, this.edgeUVWidth * 5, this.edgeUVHeight, this.edgeUVWidth * 6, 0);
}
final float borderVerticalRepeatCount = (this.renderBounds.height / this.cornerSize);
final float heightRemainder = this.renderBounds.height % this.cornerSize;
final float heightRemainderRatio = heightRemainder / this.cornerSize;
final int borderVerticalRepeatCountLessOne = (int) (borderVerticalRepeatCount - 1);
if (this.cornerFlags.contains(BackdropCornerFlags.L)) {
for (int i = 1; i < borderVerticalRepeatCountLessOne; i++) {
batch.draw(this.edgeFile, this.renderBounds.x, this.renderBounds.y + (this.cornerSize * i),
this.cornerSize, this.cornerSize, this.edgeUVWidth * 0, this.edgeUVHeight,
this.edgeUVWidth * 1, 0);
}
if (borderVerticalRepeatCountLessOne > 0) {
batch.draw(this.edgeFile, this.renderBounds.x,
this.renderBounds.y + (this.cornerSize * borderVerticalRepeatCountLessOne), this.cornerSize,
heightRemainder, this.edgeUVWidth * 0, heightRemainderRatio, this.edgeUVWidth * 1, 0);
}
}
if (this.cornerFlags.contains(BackdropCornerFlags.R)) {
for (int i = 1; i < borderVerticalRepeatCountLessOne; i++) {
batch.draw(this.edgeFile, (this.renderBounds.x + this.renderBounds.width) - this.cornerSize,
this.renderBounds.y + (this.cornerSize * i), this.cornerSize, this.cornerSize,
this.edgeUVWidth * 1, this.edgeUVHeight, this.edgeUVWidth * 2, 0);
}
if (borderVerticalRepeatCountLessOne > 0) {
batch.draw(this.edgeFile, (this.renderBounds.x + this.renderBounds.width) - this.cornerSize,
this.renderBounds.y + (this.cornerSize * borderVerticalRepeatCountLessOne), this.cornerSize,
heightRemainder, this.edgeUVWidth * 1, heightRemainderRatio, this.edgeUVWidth * 2, 0);
}
}
final float borderHorizontalRepeatCount = this.renderBounds.width / this.cornerSize;
final float widthRemainder = (this.renderBounds.width % this.cornerSize) / this.cornerSize;
final int widthRemainderByHeight = (int) (widthRemainder * this.edgeFileHeight);
final int widthRemainderByCornerSize = (int) (widthRemainder * this.cornerSize);
final int borderHorizontalRepeatCountLessOne = (int) (borderHorizontalRepeatCount - 1);
final float halfPi = 270;
if (this.cornerFlags.contains(BackdropCornerFlags.B)) {
for (int i = 1; i < borderHorizontalRepeatCountLessOne; i++) {
batch.draw(this.edgeFile, this.renderBounds.x + (this.cornerSize * i), this.renderBounds.y,
this.cornerSize / 2, this.cornerSize / 2, this.cornerSize, this.cornerSize, 1.0f, 1.0f,
halfPi, (int) ((this.edgeFileWidth * 3f) / 8f), 0, (int) (this.edgeFileWidth / 8),
(int) this.edgeFileHeight, false, false);
}
if (borderHorizontalRepeatCountLessOne > 0) {
batch.draw(this.edgeFile,
(this.renderBounds.x + (this.cornerSize * borderHorizontalRepeatCountLessOne))
- ((this.cornerSize - widthRemainderByCornerSize) / 2),
this.renderBounds.y + ((this.cornerSize - widthRemainderByCornerSize) / 2),
this.cornerSize / 2, widthRemainderByCornerSize / 2, this.cornerSize,
widthRemainderByCornerSize, 1.0f, 1.0f, halfPi, (int) ((this.edgeFileWidth * 3f) / 8f), 0,
(int) (this.edgeFileWidth / 8), widthRemainderByHeight, false, false);
}
}
if (this.cornerFlags.contains(BackdropCornerFlags.T)) {
for (int i = 1; i < borderHorizontalRepeatCountLessOne; i++) {
batch.draw(this.edgeFile, this.renderBounds.x + (this.cornerSize * i),
this.renderBounds.y + (this.renderBounds.height - this.cornerSize), this.cornerSize / 2,
this.cornerSize / 2, this.cornerSize, this.cornerSize, 1.0f, 1.0f, halfPi,
(int) ((this.edgeFileWidth * 2f) / 8f), 0, (int) (this.edgeFileWidth / 8),
(int) this.edgeFileHeight, false, false);
}
if (borderHorizontalRepeatCountLessOne > 0) {
batch.draw(this.edgeFile,
(this.renderBounds.x + (this.cornerSize * borderHorizontalRepeatCountLessOne))
- ((this.cornerSize - widthRemainderByCornerSize) / 2),
this.renderBounds.y
+ (this.renderBounds.height - ((this.cornerSize + widthRemainderByCornerSize) / 2)),
this.cornerSize / 2, widthRemainderByCornerSize / 2, this.cornerSize,
widthRemainderByCornerSize, 1.0f, 1.0f, halfPi, (int) ((this.edgeFileWidth * 2f) / 8f), 0,
(int) (this.edgeFileWidth / 8), widthRemainderByHeight, false, false);
}
}
}
super.internalRender(batch, baseFont, glyphLayout);
}
public float getCornerSize() {
return this.cornerSize;
}
}

View File

@ -0,0 +1,35 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
public class ControlFrame extends AbstractRenderableFrame {
private UIFrame controlBackdrop;
public ControlFrame(final String name, final UIFrame parent) {
super(name, parent);
}
public void setControlBackdrop(final UIFrame controlBackdrop) {
this.controlBackdrop = controlBackdrop;
}
public UIFrame getControlBackdrop() {
return this.controlBackdrop;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
this.controlBackdrop.positionBounds(gameUI, viewport);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
this.controlBackdrop.render(batch, baseFont, glyphLayout);
}
}

View File

@ -0,0 +1,179 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.FocusableFrame;
public class EditBoxFrame extends AbstractRenderableFrame implements FocusableFrame {
private UIFrame controlBackdrop;
private final float editBorderSize;
private final Color editCursorColor;
private StringFrame editTextFrame;
private boolean focused = false;
private int cursorIndex;
// TODO design in such a way that references to these are not held !! very bad
// code design here
private GameUI gameUI;
private Viewport viewport;
private GlyphLayout glyphLayout;
private Runnable onChange;
public EditBoxFrame(final String name, final UIFrame parent, final float editBorderSize,
final Color editCursorColor) {
super(name, parent);
this.editBorderSize = editBorderSize;
this.editCursorColor = editCursorColor;
}
public void setControlBackdrop(final UIFrame controlBackdrop) {
this.controlBackdrop = controlBackdrop;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
this.gameUI = gameUI;
this.viewport = viewport;
this.controlBackdrop.positionBounds(gameUI, viewport);
this.editTextFrame.positionBounds(gameUI, viewport);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
this.glyphLayout = glyphLayout;
this.controlBackdrop.render(batch, baseFont, glyphLayout);
this.editTextFrame.render(batch, baseFont, glyphLayout);
if (this.focused) {
final long time = TimeUtils.millis();
if ((time % 500) > 250) {
final BitmapFont frameFont = this.editTextFrame.getFrameFont();
frameFont.setColor(this.editCursorColor);
final int cursorRenderPosition = Math.min(this.cursorIndex, this.editTextFrame.getText().length());
this.cursorIndex = cursorRenderPosition;
glyphLayout.setText(frameFont, this.editTextFrame.getText().substring(0, cursorRenderPosition));
final float cursorXOffset = glyphLayout.width;
glyphLayout.setText(frameFont, "|");
frameFont.draw(batch, "|",
(this.editTextFrame.getFramePointX(FramePoint.LEFT) + cursorXOffset) - (glyphLayout.width / 2),
this.editTextFrame.getFramePointY(FramePoint.LEFT) + ((frameFont.getCapHeight()) / 2));
}
}
}
public void setEditTextFrame(final StringFrame editTextFrame) {
this.editTextFrame = editTextFrame;
}
@Override
public boolean isFocusable() {
return true;
}
@Override
public void onFocusGained() {
this.focused = true;
}
@Override
public void onFocusLost() {
this.focused = false;
}
@Override
public boolean keyDown(final int keycode) {
switch (keycode) {
case Input.Keys.LEFT: {
this.cursorIndex = Math.max(0, this.cursorIndex - 1);
break;
}
case Input.Keys.RIGHT: {
final String text = this.editTextFrame.getText();
this.cursorIndex = Math.min(text.length(), this.cursorIndex + 1);
break;
}
case Input.Keys.BACKSPACE: {
final String prevText = this.editTextFrame.getText();
final int prevTextLength = prevText.length();
final int cursorIndex = Math.min(this.cursorIndex, prevTextLength);
if (cursorIndex >= 1) {
this.cursorIndex = cursorIndex - 1;
final String newText = prevText.substring(0, cursorIndex - 1)
+ prevText.substring(cursorIndex, prevTextLength);
this.editTextFrame.setText(newText, this.gameUI, this.viewport);
if (this.onChange != null) {
this.onChange.run();
}
}
break;
}
}
return false;
}
@Override
public boolean keyUp(final int keycode) {
return false;
}
@Override
public boolean keyTyped(final char character) {
if (Character.isAlphabetic(character) || Character.isDigit(character)) {
final String prevText = this.editTextFrame.getText();
final int prevTextLength = prevText.length();
final int cursorIndex = Math.min(this.cursorIndex, prevTextLength);
final String newText = prevText.substring(0, cursorIndex) + character
+ prevText.substring(cursorIndex, prevTextLength);
this.editTextFrame.setText(newText, this.gameUI, this.viewport);
this.cursorIndex++;
if (this.onChange != null) {
this.onChange.run();
}
}
return false;
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
final String text = this.editTextFrame.getText();
int indexFound = -1;
final float fpXOfEditText = this.editTextFrame.getFramePointX(FramePoint.LEFT);
float lastX = 0;
for (int i = 0; i < text.length(); i++) {
final BitmapFont frameFont = this.editTextFrame.getFrameFont();
this.glyphLayout.setText(frameFont, this.editTextFrame.getText().substring(0, i));
final float x = fpXOfEditText + this.glyphLayout.width;
if (((x + lastX) / 2) > screenX) {
indexFound = i - 1;
break;
}
lastX = x;
}
if (indexFound == -1) {
indexFound = text.length();
}
this.cursorIndex = indexFound;
return this;
}
return super.touchDown(screenX, screenY, button);
}
public String getText() {
return this.editTextFrame.getText();
}
public void setOnChange(final Runnable onChange) {
this.onChange = onChange;
}
}

View File

@ -0,0 +1,33 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
import com.hiveworkshop.rms.parsers.mdlx.MdlxLayer.FilterMode;
public class FilterModeTextureFrame extends TextureFrame {
private int blendSrc;
private int blendDst;
public FilterModeTextureFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
final Vector4Definition texCoord) {
super(name, parent, decorateFileNames, texCoord);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
final int blendDstFunc = batch.getBlendDstFunc();
final int blendSrcFunc = batch.getBlendSrcFunc();
batch.setBlendFunction(this.blendSrc, this.blendDst);
super.internalRender(batch, baseFont, glyphLayout);
batch.setBlendFunction(blendSrcFunc, blendDstFunc);
}
public void setFilterMode(final FilterMode filterMode) {
final int[] layerFilterMode = com.etheller.warsmash.viewer5.handlers.mdx.FilterMode.layerFilterMode(filterMode);
this.blendSrc = layerFilterMode[0];
this.blendDst = layerFilterMode[1];
}
}

View File

@ -0,0 +1,10 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
public interface FramePointAssignment {
float getX(GameUI gameUI, Viewport uiViewport);
float getY(GameUI gameUI, Viewport uiViewport);
}

View File

@ -0,0 +1,166 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.ClickableFrame;
public class GlueButtonFrame extends AbstractRenderableFrame implements ClickableFrame {
private UIFrame controlBackdrop;
private UIFrame controlPushedBackdrop;
private UIFrame controlDisabledBackdrop;
private UIFrame controlMouseOverHighlight;
private boolean enabled = true;
private boolean highlightOnMouseOver;
private boolean mouseOver = false;
private UIFrame activeChild;
private Runnable onClick;
public GlueButtonFrame(final String name, final UIFrame parent) {
super(name, parent);
}
public void setControlBackdrop(final UIFrame controlBackdrop) {
this.controlBackdrop = controlBackdrop;
if (this.activeChild == null) {
this.activeChild = controlBackdrop;
}
}
public void setControlPushedBackdrop(final UIFrame controlPushedBackdrop) {
this.controlPushedBackdrop = controlPushedBackdrop;
}
public void setControlDisabledBackdrop(final UIFrame controlDisabledBackdrop) {
this.controlDisabledBackdrop = controlDisabledBackdrop;
}
public void setControlMouseOverHighlight(final UIFrame controlMouseOverHighlight) {
this.controlMouseOverHighlight = controlMouseOverHighlight;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
if (this.enabled) {
this.activeChild = this.controlBackdrop;
}
else {
this.activeChild = this.controlDisabledBackdrop;
}
}
public boolean isEnabled() {
return this.enabled;
}
public void setHighlightOnMouseOver(final boolean highlightOnMouseOver) {
this.highlightOnMouseOver = highlightOnMouseOver;
}
public void setOnClick(final Runnable onClick) {
this.onClick = onClick;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
if (this.controlBackdrop != null) {
this.controlBackdrop.positionBounds(gameUI, viewport);
}
if (this.controlPushedBackdrop != null) {
this.controlPushedBackdrop.positionBounds(gameUI, viewport);
}
if (this.controlDisabledBackdrop != null) {
this.controlDisabledBackdrop.positionBounds(gameUI, viewport);
}
if (this.controlMouseOverHighlight != null) {
this.controlMouseOverHighlight.positionBounds(gameUI, viewport);
}
if (this.enabled) {
this.activeChild = this.controlBackdrop;
}
else {
this.activeChild = this.controlDisabledBackdrop;
}
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
if (this.activeChild != null) {
this.activeChild.render(batch, baseFont, glyphLayout);
}
if (this.mouseOver) {
this.controlMouseOverHighlight.render(batch, baseFont, glyphLayout);
}
}
@Override
public void mouseDown(final GameUI gameUI, final Viewport uiViewport) {
if (this.enabled) {
this.activeChild = this.controlPushedBackdrop;
}
}
@Override
public void mouseUp(final GameUI gameUI, final Viewport uiViewport) {
if (this.enabled) {
this.activeChild = this.controlBackdrop;
}
}
@Override
public void mouseEnter(final GameUI gameUI, final Viewport uiViewport) {
if (this.highlightOnMouseOver) {
this.mouseOver = true;
onMouseEnter();
}
}
protected void onMouseEnter() {
}
@Override
public void mouseExit(final GameUI gameUI, final Viewport uiViewport) {
this.mouseOver = false;
onMouseExit();
}
protected void onMouseExit() {
}
@Override
public void onClick(final int button) {
if (this.onClick != null) {
this.onClick.run();
}
}
@Override
public UIFrame touchUp(final float screenX, final float screenY, final int button) {
if (isVisible() && this.enabled && this.renderBounds.contains(screenX, screenY)) {
return this;
}
return super.touchUp(screenX, screenY, button);
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (isVisible() && this.enabled && this.renderBounds.contains(screenX, screenY)) {
return this;
}
return super.touchDown(screenX, screenY, button);
}
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
if (isVisible() && this.enabled && this.renderBounds.contains(screenX, screenY)) {
return this;
}
return super.getFrameChildUnderMouse(screenX, screenY);
}
}

View File

@ -0,0 +1,77 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
public class GlueTextButtonFrame extends GlueButtonFrame {
private UIFrame buttonText;
public GlueTextButtonFrame(final String name, final UIFrame parent) {
super(name, parent);
}
public void setButtonText(final UIFrame buttonText) {
this.buttonText = buttonText;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
super.innerPositionBounds(gameUI, viewport);
if (this.buttonText != null) {
this.buttonText.positionBounds(gameUI, viewport);
}
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
super.internalRender(batch, baseFont, glyphLayout);
if (this.buttonText != null) {
this.buttonText.render(batch, baseFont, glyphLayout);
}
}
@Override
public void setEnabled(final boolean enabled) {
super.setEnabled(enabled);
if (this.buttonText instanceof StringFrame) {
final StringFrame stringButtonText = (StringFrame) this.buttonText;
final Color fontColor = enabled ? stringButtonText.getFontOriginalColor()
: stringButtonText.getFontDisabledColor();
if (fontColor != null) {
stringButtonText.setColor(fontColor);
}
}
}
@Override
protected void onMouseEnter() {
super.onMouseEnter();
if (isEnabled()) {
if (this.buttonText instanceof StringFrame) {
final StringFrame stringFrame = (StringFrame) this.buttonText;
final Color fontHighlightColor = stringFrame.getFontHighlightColor();
if (fontHighlightColor != null) {
stringFrame.setColor(fontHighlightColor);
}
}
}
}
@Override
protected void onMouseExit() {
super.onMouseExit();
if (isEnabled()) {
if (this.buttonText instanceof StringFrame) {
final StringFrame stringFrame = (StringFrame) this.buttonText;
final Color fontOriginalColor = stringFrame.getFontOriginalColor();
if (fontOriginalColor != null) {
stringFrame.setColor(fontOriginalColor);
}
}
}
}
}

View File

@ -0,0 +1,202 @@
package com.etheller.warsmash.parsers.fdf.frames;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.datamodel.TextJustify;
public class ListBoxFrame extends ControlFrame {
// TODO where are these colors in the UI definition files?
private static final Color SELECT_COLOR = Color.BLUE;
private static final Color MOUSE_OVER_HIGHLIGHT_COLOR = new Color(0.3f, 0.3f, 1.0f, 0.25f);
private final List<String> listItems = new ArrayList<>();
private final List<SingleStringFrame> stringFrames = new ArrayList<>();
private BitmapFont frameFont;
private float listBoxBorder;
private int selectedIndex = -1;
private int mouseOverIndex = -1;
private final TextureFrame selectionFrame;
private final TextureFrame mouseHighlightFrame;
private GameUI gameUI;
private Viewport viewport;
private Runnable onSelect;
public ListBoxFrame(final String name, final UIFrame parent, final Viewport viewport) {
super(name, parent);
this.listBoxBorder = GameUI.convertX(viewport, 0.01f);
this.selectionFrame = new TextureFrame(null, this, false, null);
this.mouseHighlightFrame = new TextureFrame(null, this, false, null);
final Pixmap pixmap = new Pixmap(1, 1, Format.RGBA8888);
pixmap.setColor(SELECT_COLOR);
pixmap.fill();
this.selectionFrame.setTexture(new Texture(pixmap));
final Pixmap mousePixmap = new Pixmap(1, 1, Format.RGBA8888);
mousePixmap.setColor(MOUSE_OVER_HIGHLIGHT_COLOR);
mousePixmap.fill();
this.mouseHighlightFrame.setTexture(new Texture(mousePixmap));
}
public void setListBoxBorder(final float listBoxBorder) {
this.listBoxBorder = listBoxBorder;
}
public float getListBoxBorder() {
return this.listBoxBorder;
}
public void setFrameFont(final BitmapFont frameFont) {
this.frameFont = frameFont;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
this.gameUI = gameUI;
this.viewport = viewport;
super.innerPositionBounds(gameUI, viewport);
updateUI(gameUI, viewport);
}
private void positionChildren(final GameUI gameUI, final Viewport viewport) {
for (final SingleStringFrame frame : this.stringFrames) {
frame.positionBounds(gameUI, viewport);
}
this.selectionFrame.positionBounds(gameUI, viewport);
this.mouseHighlightFrame.positionBounds(gameUI, viewport);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
super.internalRender(batch, baseFont, glyphLayout);
this.selectionFrame.render(batch, baseFont, glyphLayout);
this.mouseHighlightFrame.render(batch, baseFont, glyphLayout);
for (final SingleStringFrame frame : this.stringFrames) {
frame.render(batch, baseFont, glyphLayout);
}
}
public void addItem(final String item, final GameUI gameUI, final Viewport viewport) {
this.listItems.add(item);
updateUI(gameUI, viewport);
}
public void setItems(final List<String> items, final GameUI gameUI, final Viewport viewport) {
this.listItems.clear();
this.listItems.addAll(items);
updateUI(gameUI, viewport);
}
public void removeItem(final String item, final GameUI gameUI, final Viewport viewport) {
this.listItems.remove(item);
updateUI(gameUI, viewport);
}
public void removeItem(final int index, final GameUI gameUI, final Viewport viewport) {
this.listItems.remove(index);
updateUI(gameUI, viewport);
}
public void setSelectedIndex(final int selectedIndex) {
this.selectedIndex = selectedIndex;
}
public int getSelectedIndex() {
return this.selectedIndex;
}
private void updateUI(final GameUI gameUI, final Viewport viewport) {
this.stringFrames.clear();
SingleStringFrame prev = null;
int i = 0;
boolean foundSelected = false;
boolean foundMouseOver = false;
for (final String string : this.listItems) {
final boolean selected = (i == this.selectedIndex);
final boolean mousedOver = (i == this.mouseOverIndex);
final SingleStringFrame stringFrame = new SingleStringFrame("LISTY" + i++, this, Color.WHITE,
TextJustify.LEFT, TextJustify.MIDDLE, this.frameFont);
stringFrame.setText(string);
stringFrame.setWidth(this.renderBounds.width - (this.listBoxBorder * 2));
stringFrame.setHeight(this.frameFont.getLineHeight());
if (prev != null) {
stringFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, prev, FramePoint.BOTTOMLEFT, 0, 0));
}
else {
stringFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this, FramePoint.TOPLEFT, this.listBoxBorder,
-this.listBoxBorder));
}
this.stringFrames.add(stringFrame);
prev = stringFrame;
if (selected) {
this.selectionFrame
.addSetPoint(new SetPoint(FramePoint.TOPLEFT, stringFrame, FramePoint.TOPLEFT, 0, 0));
this.selectionFrame
.addSetPoint(new SetPoint(FramePoint.BOTTOMRIGHT, stringFrame, FramePoint.BOTTOMRIGHT, 0, 0));
foundSelected = true;
}
else if (mousedOver) {
this.mouseHighlightFrame
.addSetPoint(new SetPoint(FramePoint.TOPLEFT, stringFrame, FramePoint.TOPLEFT, 0, 0));
this.mouseHighlightFrame
.addSetPoint(new SetPoint(FramePoint.BOTTOMRIGHT, stringFrame, FramePoint.BOTTOMRIGHT, 0, 0));
foundMouseOver = true;
}
}
this.selectionFrame.setVisible(foundSelected);
this.mouseHighlightFrame.setVisible(foundMouseOver);
positionChildren(gameUI, viewport);
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
int index = 0;
for (final SingleStringFrame stringFrame : this.stringFrames) {
if (stringFrame.getRenderBounds().contains(screenX, screenY)) {
this.selectedIndex = index;
}
index++;
}
updateUI(this.gameUI, this.viewport);
if (this.onSelect != null) {
this.onSelect.run();
}
return this;
}
return super.touchDown(screenX, screenY, button);
}
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
int index = 0;
int mouseOverIndex = -1;
for (final SingleStringFrame stringFrame : this.stringFrames) {
if (stringFrame.getRenderBounds().contains(screenX, screenY)) {
mouseOverIndex = index;
}
index++;
}
if (this.mouseOverIndex != mouseOverIndex) {
this.mouseOverIndex = mouseOverIndex;
updateUI(this.gameUI, this.viewport);
}
}
return super.getFrameChildUnderMouse(screenX, screenY);
}
public void setOnSelect(final Runnable onSelect) {
this.onSelect = onSelect;
}
}

View File

@ -0,0 +1,58 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
public class SetPoint implements FramePointAssignment {
private final FramePoint myPoint;
private final UIFrame other;
private final FramePoint otherPoint;
private final float x;
private final float y;
public SetPoint(final FramePoint myPoint, final UIFrame other, final FramePoint otherPoint, final float x,
final float y) {
this.myPoint = myPoint;
this.other = other;
this.otherPoint = otherPoint;
this.x = x;
this.y = y;
}
public FramePoint getMyPoint() {
return this.myPoint;
}
public UIFrame getOther() {
return this.other;
}
public FramePoint getOtherPoint() {
return this.otherPoint;
}
public float getX() {
return this.x;
}
public float getY() {
return this.y;
}
@Override
public float getX(final GameUI gameUI, final Viewport uiViewport) {
return this.other.getFramePointX(this.otherPoint) + this.x;
}
@Override
public float getY(final GameUI gameUI, final Viewport uiViewport) {
return this.other.getFramePointY(this.otherPoint) + this.y;
}
@Override
public String toString() {
return "SetPoint [myPoint=" + this.myPoint + ", other=" + this.other + ", otherPoint=" + this.otherPoint
+ ", x=" + this.x + ", y=" + this.y + "]";
}
}

View File

@ -0,0 +1,217 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.ClickableFrame;
public class SimpleButtonFrame extends AbstractRenderableFrame implements ClickableFrame {
private UIFrame controlBackdrop;
private UIFrame controlPushedBackdrop;
private UIFrame controlDisabledBackdrop;
private UIFrame controlMouseOverHighlight;
private boolean enabled = true;
private boolean highlightOnMouseOver;
private boolean mouseOver = false;
private boolean pushed = false;
private UIFrame activeChild;
private UIFrame activeTextChild;
private UIFrame buttonText;
private UIFrame disabledText;
private UIFrame highlightText;
private UIFrame pushedText;
private UIFrame pushedHighlightText;
private Runnable onClick;
public SimpleButtonFrame(final String name, final UIFrame parent) {
super(name, parent);
}
public void setControlBackdrop(final UIFrame controlBackdrop) {
this.controlBackdrop = controlBackdrop;
if (this.activeChild == null) {
this.activeChild = controlBackdrop;
}
}
public void setControlPushedBackdrop(final UIFrame controlPushedBackdrop) {
this.controlPushedBackdrop = controlPushedBackdrop;
}
public void setControlDisabledBackdrop(final UIFrame controlDisabledBackdrop) {
this.controlDisabledBackdrop = controlDisabledBackdrop;
}
public void setControlMouseOverHighlight(final UIFrame controlMouseOverHighlight) {
this.controlMouseOverHighlight = controlMouseOverHighlight;
this.highlightOnMouseOver |= controlMouseOverHighlight != null;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
if (this.enabled) {
this.activeChild = this.controlBackdrop;
this.activeTextChild = this.buttonText;
}
else {
this.activeChild = this.controlDisabledBackdrop;
this.activeTextChild = this.disabledText;
}
}
public void setHighlightOnMouseOver(final boolean highlightOnMouseOver) {
this.highlightOnMouseOver = highlightOnMouseOver;
}
public void setOnClick(final Runnable onClick) {
this.onClick = onClick;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
if (this.controlBackdrop != null) {
this.controlBackdrop.positionBounds(gameUI, viewport);
}
if (this.controlPushedBackdrop != null) {
this.controlPushedBackdrop.positionBounds(gameUI, viewport);
}
if (this.controlDisabledBackdrop != null) {
this.controlDisabledBackdrop.positionBounds(gameUI, viewport);
}
if (this.controlMouseOverHighlight != null) {
this.controlMouseOverHighlight.positionBounds(gameUI, viewport);
}
if (this.buttonText != null) {
this.buttonText.positionBounds(gameUI, viewport);
}
if (this.pushedText != null) {
this.pushedText.positionBounds(gameUI, viewport);
}
if (this.disabledText != null) {
this.disabledText.positionBounds(gameUI, viewport);
}
if (this.highlightText != null) {
this.highlightText.positionBounds(gameUI, viewport);
}
if (this.pushedHighlightText != null) {
this.pushedHighlightText.positionBounds(gameUI, viewport);
}
if (this.enabled) {
this.activeChild = this.controlBackdrop;
this.activeTextChild = this.buttonText;
}
else {
this.activeChild = this.controlDisabledBackdrop;
this.activeTextChild = this.disabledText;
}
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
if (this.activeChild != null) {
this.activeChild.render(batch, baseFont, glyphLayout);
}
if (this.activeTextChild != null) {
this.activeTextChild.render(batch, baseFont, glyphLayout);
}
if (this.mouseOver) {
this.controlMouseOverHighlight.render(batch, baseFont, glyphLayout);
}
}
@Override
public void mouseDown(final GameUI gameUI, final Viewport uiViewport) {
if (this.enabled) {
this.activeChild = this.controlPushedBackdrop;
this.pushed = true;
this.activeTextChild = this.mouseOver ? this.pushedHighlightText : this.pushedText;
}
}
@Override
public void mouseUp(final GameUI gameUI, final Viewport uiViewport) {
if (this.enabled) {
this.activeChild = this.controlBackdrop;
this.activeTextChild = this.mouseOver ? this.highlightText : this.buttonText;
}
this.pushed = false;
}
@Override
public void mouseEnter(final GameUI gameUI, final Viewport uiViewport) {
if (this.highlightOnMouseOver) {
this.mouseOver = true;
if (this.enabled) {
this.activeTextChild = this.pushed ? this.pushedHighlightText : this.highlightText;
}
}
}
@Override
public void mouseExit(final GameUI gameUI, final Viewport uiViewport) {
this.mouseOver = false;
if (this.enabled) {
this.activeTextChild = this.pushed ? this.pushedText : this.buttonText;
}
}
@Override
public void onClick(final int button) {
if (this.onClick != null) {
this.onClick.run();
}
}
@Override
public UIFrame touchUp(final float screenX, final float screenY, final int button) {
if (isVisible() && this.enabled && this.renderBounds.contains(screenX, screenY)) {
return this;
}
return super.touchUp(screenX, screenY, button);
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (isVisible() && this.enabled && this.renderBounds.contains(screenX, screenY)) {
return this;
}
return super.touchDown(screenX, screenY, button);
}
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
if (isVisible() && this.enabled && this.renderBounds.contains(screenX, screenY)) {
return this;
}
return super.getFrameChildUnderMouse(screenX, screenY);
}
public void setButtonText(final UIFrame buttonText) {
this.buttonText = buttonText;
}
public void setPushedHighlightText(final UIFrame pushedHighlightText) {
this.pushedHighlightText = pushedHighlightText;
}
public void setPushedText(final UIFrame pushedText) {
this.pushedText = pushedText;
}
public void setHighlightText(final UIFrame highlightText) {
this.highlightText = highlightText;
this.highlightOnMouseOver |= highlightText != null;
}
public void setDisabledText(final UIFrame disabledText) {
this.disabledText = disabledText;
}
}

View File

@ -0,0 +1,9 @@
package com.etheller.warsmash.parsers.fdf.frames;
public class SimpleFrame extends AbstractUIFrame {
public SimpleFrame(final String name, final UIFrame parent) {
super(name, parent);
}
}

View File

@ -0,0 +1,41 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
public class SimpleStatusBarFrame extends AbstractUIFrame {
private final boolean decorateFileNames;
private final TextureFrame barFrame;
private final TextureFrame borderFrame;
public SimpleStatusBarFrame(final String name, final UIFrame parent, final boolean decorateFileNames) {
super(name, parent);
this.decorateFileNames = decorateFileNames;
this.barFrame = new TextureFrame(name + "Bar", this, decorateFileNames, new Vector4Definition(0, 1, 0, 1));
this.borderFrame = new TextureFrame(name + "Border", this, decorateFileNames,
new Vector4Definition(0, 1, 0, 1));
this.borderFrame.setSetAllPoints(true);
this.barFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this, FramePoint.TOPLEFT, 0, 0));
this.barFrame.addSetPoint(new SetPoint(FramePoint.BOTTOMLEFT, this, FramePoint.BOTTOMLEFT, 0, 0));
this.barFrame.setSetAllPoints(true);
add(this.barFrame);
add(this.borderFrame);
}
public boolean isDecorateFileNames() {
return this.decorateFileNames;
}
public void setValue(final float value) {
this.barFrame.setTexCoord(0, value, 0, 1);
this.barFrame.setWidth(this.renderBounds.width * value);
}
public TextureFrame getBarFrame() {
return this.barFrame;
}
public TextureFrame getBorderFrame() {
return this.borderFrame;
}
}

View File

@ -0,0 +1,106 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.TextJustify;
public class SingleStringFrame extends AbstractRenderableFrame {
private Color color;
private String text = "Default string";
private final TextJustify justifyH;
private final TextJustify justifyV;
private final BitmapFont frameFont;
private Color fontShadowColor;
private float fontShadowOffsetX;
private float fontShadowOffsetY;
private float alpha = 1.0f;
public SingleStringFrame(final String name, final UIFrame parent, final Color color, final TextJustify justifyH,
final TextJustify justifyV, final BitmapFont frameFont) {
super(name, parent);
this.color = color;
this.justifyH = justifyH;
this.justifyV = justifyV;
this.frameFont = frameFont;
this.text = name;
}
public void setText(final String text) {
if (text == null) {
throw new IllegalArgumentException();
}
this.text = text;
}
public void setColor(final Color color) {
this.color = color;
}
public Color getColor() {
return this.color;
}
public void setFontShadowColor(final Color fontShadowColor) {
this.fontShadowColor = fontShadowColor;
}
public void setFontShadowOffsetX(final float fontShadowOffsetX) {
this.fontShadowOffsetX = fontShadowOffsetX;
}
public void setFontShadowOffsetY(final float fontShadowOffsetY) {
this.fontShadowOffsetY = fontShadowOffsetY;
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
glyphLayout.setText(this.frameFont, this.text);
final float x;
switch (this.justifyH) {
case CENTER:
x = this.renderBounds.x + ((this.renderBounds.width - glyphLayout.width) / 2);
break;
case RIGHT:
x = (this.renderBounds.x + this.renderBounds.width) - glyphLayout.width;
break;
case LEFT:
default:
x = this.renderBounds.x;
break;
}
final float y;
switch (this.justifyV) {
case MIDDLE:
y = this.renderBounds.y + ((this.renderBounds.height + this.frameFont.getLineHeight()) / 2);
break;
case TOP:
y = (this.renderBounds.y + this.renderBounds.height);
break;
case BOTTOM:
default:
y = this.renderBounds.y + this.frameFont.getLineHeight();
break;
}
if (this.fontShadowColor != null) {
this.frameFont.setColor(this.fontShadowColor.r, this.fontShadowColor.g, this.fontShadowColor.b,
this.fontShadowColor.a * this.alpha);
this.frameFont.draw(batch, this.text, x + this.fontShadowOffsetX, y + this.fontShadowOffsetY);
}
this.frameFont.setColor(this.color.r, this.color.g, this.color.b, this.color.a * this.alpha);
this.frameFont.draw(batch, this.text, x, y);
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
}
public void setAlpha(final float alpha) {
this.alpha = alpha;
}
}

View File

@ -0,0 +1,77 @@
package com.etheller.warsmash.parsers.fdf.frames;
import java.util.EnumSet;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.BackdropCornerFlags;
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
import com.etheller.warsmash.viewer5.Scene;
import com.hiveworkshop.rms.parsers.mdlx.MdlxGeoset;
import com.hiveworkshop.rms.parsers.mdlx.MdlxLayer;
import com.hiveworkshop.rms.parsers.mdlx.MdlxLayer.FilterMode;
import com.hiveworkshop.rms.parsers.mdlx.MdlxMaterial;
import com.hiveworkshop.rms.parsers.mdlx.MdlxModel;
import com.hiveworkshop.rms.parsers.mdlx.MdlxTexture;
import com.hiveworkshop.rms.parsers.mdlx.MdlxTexture.WrapMode;
public class SmartBackdropFrame extends SpriteFrame {
private final boolean decorateFileNames;
private final boolean tileBackground;
private final String backgroundString;
private final EnumSet<BackdropCornerFlags> cornerFlags;
private final float cornerSize;
private final float backgroundSize;
private final Vector4Definition backgroundInsets;
private final String edgeFileString;
public SmartBackdropFrame(final String name, final UIFrame parent, final Scene scene, final Viewport uiViewport,
final boolean decorateFileNames, final boolean tileBackground, final String backgroundString,
final EnumSet<BackdropCornerFlags> cornerFlags, final float cornerSize, final float backgroundSize,
final Vector4Definition backgroundInsets, final String edgeFileString) {
super(name, parent, scene, uiViewport);
this.decorateFileNames = decorateFileNames;
this.tileBackground = tileBackground;
this.backgroundString = backgroundString;
this.cornerFlags = cornerFlags;
this.cornerSize = cornerSize;
this.backgroundSize = backgroundSize;
this.backgroundInsets = backgroundInsets;
this.edgeFileString = edgeFileString;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
generateBackdropModel();
super.innerPositionBounds(gameUI, viewport);
}
private MdlxModel generateBackdropModel() {
final MdlxModel model = new MdlxModel();
final int edgeFileMaterialId = generateMaterial(model, this.edgeFileString, true);
final int backgroundMaterialId = generateMaterial(model, this.backgroundString, this.tileBackground);
final MdlxGeoset edgeGeoset = new MdlxGeoset();
final float[] edgeGeosetVertices = new float[32 * 4];
return model;
}
private int generateMaterial(final MdlxModel model, final String path, final boolean wrap) {
final MdlxTexture edgeFileReference = new MdlxTexture();
if (wrap) {
edgeFileReference.setWrapMode(WrapMode.REPEAT_BOTH);
}
edgeFileReference.setPath(path);
final int textureId = model.getTextures().size();
model.getTextures().add(edgeFileReference);
final MdlxMaterial edgeFileMaterial = new MdlxMaterial();
final MdlxLayer edgeFileMaterialLayer = new MdlxLayer();
edgeFileMaterialLayer.setAlpha(1.0f);
edgeFileMaterialLayer.setFilterMode(FilterMode.BLEND);
edgeFileMaterialLayer.setTextureId(textureId);
edgeFileMaterial.getLayers().add(edgeFileMaterialLayer);
final int materialId = model.getMaterials().size();
model.getMaterials().add(edgeFileMaterial);
return materialId;
}
}

View File

@ -0,0 +1,138 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
public class SpriteFrame extends AbstractUIFrame {
protected final Scene scene;
protected final Viewport uiViewport;
private MdxComplexInstance instance;
private float zDepth;
public SpriteFrame(final String name, final UIFrame parent, final Scene scene, final Viewport uiViewport) {
super(name, parent);
this.scene = scene;
this.uiViewport = uiViewport;
}
public void setModel(final MdxModel model) {
if (this.instance != null) {
this.scene.removeInstance(this.instance);
}
if (model != null) {
this.instance = (MdxComplexInstance) model.addInstance();
this.instance.setSequenceLoopMode(SequenceLoopMode.MODEL_LOOP);
this.instance.setScene(this.scene);
this.instance.setLocation(this.renderBounds.x, this.renderBounds.y, this.zDepth);
}
else {
this.instance = null;
}
}
@Override
public void setVisible(final boolean visible) {
super.setVisible(visible);
updateInstanceLocation(this.uiViewport);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
super.internalRender(batch, baseFont, glyphLayout);
}
@Override
public void setFramePointX(final FramePoint framePoint, final float x) {
super.setFramePointX(framePoint, x);
updateInstanceLocation(this.uiViewport);
}
@Override
public void setFramePointY(final FramePoint framePoint, final float y) {
super.setFramePointY(framePoint, y);
updateInstanceLocation(this.uiViewport);
}
public void setZDepth(final float depth) {
this.zDepth = depth;
updateInstanceLocation(this.uiViewport);
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
super.innerPositionBounds(gameUI, viewport);
updateInstanceLocation(viewport);
}
public void setSequence(final int index) {
if (this.instance != null) {
this.instance.setSequence(index);
}
}
public void setSequence(final String animationName) {
if (this.instance != null) {
SequenceUtils.randomSequence(this.instance, animationName.toLowerCase());
}
}
public void setSequence(final PrimaryTag animationName) {
if (this.instance != null) {
SequenceUtils.randomSequence(this.instance, animationName);
}
}
public void setAnimationSpeed(final float speedRatio) {
if (this.instance != null) {
this.instance.setAnimationSpeed(speedRatio);
}
}
public void setFrame(final int animationFrame) {
if (this.instance != null) {
this.instance.setFrame(animationFrame);
}
}
public void setFrameByRatio(final float ratioOfAnimationCompleted) {
if (this.instance != null) {
this.instance.setFrameByRatio(ratioOfAnimationCompleted);
}
}
private void updateInstanceLocation(final Viewport viewport) {
if (this.instance != null) {
this.instance.setLocation(GameUI.unconvertX(viewport, this.renderBounds.x),
GameUI.unconvertY(viewport, this.renderBounds.y), this.zDepth);
if (isVisible()) {
this.instance.show();
}
else {
this.instance.hide();
}
}
}
public boolean isSequenceEnded() {
return this.instance.sequenceEnded;
}
public void setReplaceableId(final int replaceableId, final String blpPath) {
if (this.instance != null) {
this.instance.setReplaceableTexture(replaceableId, blpPath);
}
}
}

View File

@ -0,0 +1,496 @@
package com.etheller.warsmash.parsers.fdf.frames;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.datamodel.TextJustify;
public class StringFrame extends AbstractRenderableFrame {
private final List<SingleStringFrame> internalFrames = new ArrayList<>();
private Color color;
private String text = "Default string";
private final TextJustify justifyH;
private final TextJustify justifyV;
private final BitmapFont frameFont;
private Color fontShadowColor;
private float fontShadowOffsetX;
private float fontShadowOffsetY;
private float alpha = 1.0f;
private final SimpleFrame internalFramesContainer;
private float predictedViewportHeight;
static ShapeRenderer shapeRenderer = new ShapeRenderer();
private final Color fontHighlightColor;
private final Color fontDisabledColor;
private final Color fontColor;
public StringFrame(final String name, final UIFrame parent, final Color color, final TextJustify justifyH,
final TextJustify justifyV, final BitmapFont frameFont, final String text, final Color fontHighlightColor,
final Color fontDisabledColor) {
super(name, parent);
this.fontColor = color;
this.color = color;
this.justifyH = justifyH;
this.justifyV = justifyV;
this.frameFont = frameFont;
this.text = text;
this.fontHighlightColor = fontHighlightColor;
this.fontDisabledColor = fontDisabledColor;
this.internalFramesContainer = new SimpleFrame(null, this);
}
public String getText() {
return this.text;
}
public void setText(final String text, final GameUI gameUI, final Viewport viewport) {
if (text == null) {
throw new IllegalArgumentException();
}
this.text = text;
positionBounds(gameUI, viewport);
}
public void setColor(final Color color) {
for (final SingleStringFrame internalFrame : this.internalFrames) {
if (internalFrame.getColor() == this.color) {
internalFrame.setColor(color);
}
}
this.color = color;
}
public Color getColor() {
return this.color;
}
public Color getFontOriginalColor() {
return this.fontColor;
}
public Color getFontDisabledColor() {
return this.fontDisabledColor;
}
public Color getFontHighlightColor() {
return this.fontHighlightColor;
}
public void setFontShadowColor(final Color fontShadowColor) {
this.fontShadowColor = fontShadowColor;
for (final SingleStringFrame internalFrame : this.internalFrames) {
internalFrame.setFontShadowColor(fontShadowColor);
}
}
public void setFontShadowOffsetX(final float fontShadowOffsetX) {
this.fontShadowOffsetX = fontShadowOffsetX;
for (final SingleStringFrame internalFrame : this.internalFrames) {
internalFrame.setFontShadowOffsetX(fontShadowOffsetX);
}
}
public void setFontShadowOffsetY(final float fontShadowOffsetY) {
this.fontShadowOffsetY = fontShadowOffsetY;
for (final SingleStringFrame internalFrame : this.internalFrames) {
internalFrame.setFontShadowOffsetY(fontShadowOffsetY);
}
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
this.internalFramesContainer.render(batch, baseFont, glyphLayout);
if (GameUI.DEBUG) {
batch.end();
shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
shapeRenderer.setColor(1f, 1f, 1f, 1f);
shapeRenderer.begin(ShapeType.Line);
shapeRenderer.rect(this.renderBounds.x, this.renderBounds.y, this.renderBounds.width,
this.renderBounds.height);
shapeRenderer.end();
batch.begin();
}
}
@Override
public void positionBounds(final GameUI gameUI, final Viewport viewport) {
createInternalFrames(gameUI.getGlyphLayout());
if (this.renderBounds.height == 0) {
this.renderBounds.height = getPredictedViewportHeight();
}
super.positionBounds(gameUI, viewport);
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
this.internalFramesContainer.positionBounds(gameUI, viewport);
}
private void createInternalFrames(final GlyphLayout glyphLayout) {
for (final SingleStringFrame internalFrame : this.internalFrames) {
this.internalFramesContainer.remove(internalFrame);
}
this.internalFrames.clear();
final StringBuilder currentLine = new StringBuilder();
final StringBuilder currentWord = new StringBuilder();
float currentXCoordForWord = 0;
float currentXCoordForFrames = 0;
final float usedWidth = 0;
float usedHeight = 0;
float usedWidthMax = 0;
final float startingBoundsWidth = this.renderBounds.width;
final boolean firstInLine = false;
Color currentColor = this.color;
for (int i = 0; i < this.text.length(); i++) {
final char c = this.text.charAt(i);
switch (c) {
case '|': {
// special control character
if ((i + 1) < this.text.length()) {
final char escapedCharacter = this.text.charAt(i + 1);
switch (escapedCharacter) {
case 'c':
case 'C':
if ((i + 9) < this.text.length()) {
int colorInt;
try {
final String upperCase = this.text.substring(i + 2, i + 10).toUpperCase();
colorInt = (int) Long.parseLong(upperCase, 16);
}
catch (final NumberFormatException exc) {
currentWord.append(c);
break;
}
i += 9;
{
final String wordString = currentWord.toString();
currentWord.setLength(0);
glyphLayout.setText(this.frameFont, wordString);
final float wordWidth = glyphLayout.width;
if ((startingBoundsWidth > 0)
&& ((currentXCoordForWord + wordWidth) >= startingBoundsWidth)) {
final String currentLineString = currentLine.toString();
currentLine.setLength(0);
glyphLayout.setText(this.frameFont, currentLineString);
usedWidthMax = Math.max(currentXCoordForFrames + glyphLayout.width, usedWidthMax);
final SingleStringFrame singleStringFrame = new SingleStringFrame(currentLineString,
this.internalFramesContainer, currentColor, TextJustify.LEFT,
TextJustify.TOP, this.frameFont);
singleStringFrame.setHeight(this.frameFont.getLineHeight());
singleStringFrame.setWidth(glyphLayout.width);
singleStringFrame.setAlpha(this.alpha);
singleStringFrame.setFontShadowColor(this.fontShadowColor);
singleStringFrame.setFontShadowOffsetX(this.fontShadowOffsetX);
singleStringFrame.setFontShadowOffsetY(this.fontShadowOffsetY);
singleStringFrame.addAnchor(new AnchorDefinition(FramePoint.TOPLEFT,
currentXCoordForFrames, usedHeight));
this.internalFrames.add(singleStringFrame);
usedHeight += this.frameFont.getLineHeight();
currentXCoordForWord = 0;
currentXCoordForFrames = 0;
}
currentXCoordForWord += wordWidth;
currentLine.append(wordString);
final String currentLineString = currentLine.toString();
currentLine.setLength(0);
glyphLayout.setText(this.frameFont, currentLineString);
usedWidthMax = Math.max(currentXCoordForFrames + glyphLayout.width, usedWidthMax);
final SingleStringFrame singleStringFrame = new SingleStringFrame(currentLineString,
this.internalFramesContainer, currentColor, TextJustify.LEFT, TextJustify.TOP,
this.frameFont);
singleStringFrame.setHeight(this.frameFont.getLineHeight());
singleStringFrame.setWidth(glyphLayout.width);
singleStringFrame.setAlpha(this.alpha);
singleStringFrame.setFontShadowColor(this.fontShadowColor);
singleStringFrame.setFontShadowOffsetX(this.fontShadowOffsetX);
singleStringFrame.setFontShadowOffsetY(this.fontShadowOffsetY);
singleStringFrame.addAnchor(
new AnchorDefinition(FramePoint.TOPLEFT, currentXCoordForFrames, -usedHeight));
this.internalFrames.add(singleStringFrame);
currentXCoordForFrames = currentXCoordForWord;
currentColor = new Color((colorInt << 8) | (colorInt >>> 24));
}
}
break;
case 'r':
case 'R':
i++; {
final String wordString = currentWord.toString();
currentWord.setLength(0);
glyphLayout.setText(this.frameFont, wordString);
final float wordWidth = glyphLayout.width;
if ((startingBoundsWidth > 0) && ((currentXCoordForWord + wordWidth) >= startingBoundsWidth)) {
final String currentLineString = currentLine.toString();
currentLine.setLength(0);
glyphLayout.setText(this.frameFont, currentLineString);
usedWidthMax = Math.max(currentXCoordForFrames + glyphLayout.width, usedWidthMax);
final SingleStringFrame singleStringFrame = new SingleStringFrame(currentLineString,
this.internalFramesContainer, currentColor, TextJustify.LEFT, TextJustify.TOP,
this.frameFont);
singleStringFrame.setHeight(this.frameFont.getLineHeight());
singleStringFrame.setWidth(glyphLayout.width);
singleStringFrame.setAlpha(this.alpha);
singleStringFrame.setFontShadowColor(this.fontShadowColor);
singleStringFrame.setFontShadowOffsetX(this.fontShadowOffsetX);
singleStringFrame.setFontShadowOffsetY(this.fontShadowOffsetY);
singleStringFrame.addAnchor(
new AnchorDefinition(FramePoint.TOPLEFT, currentXCoordForFrames, -usedHeight));
this.internalFrames.add(singleStringFrame);
usedHeight += this.frameFont.getLineHeight();
currentXCoordForWord = 0;
currentXCoordForFrames = 0;
}
currentXCoordForWord += wordWidth;
currentLine.append(wordString);
final String currentLineString = currentLine.toString();
currentLine.setLength(0);
glyphLayout.setText(this.frameFont, currentLineString);
usedWidthMax = Math.max(currentXCoordForFrames + glyphLayout.width, usedWidthMax);
final SingleStringFrame singleStringFrame = new SingleStringFrame(currentLineString,
this.internalFramesContainer, currentColor, TextJustify.LEFT, TextJustify.TOP,
this.frameFont);
singleStringFrame.setHeight(this.frameFont.getLineHeight());
singleStringFrame.setWidth(glyphLayout.width);
singleStringFrame.setAlpha(this.alpha);
singleStringFrame.setFontShadowColor(this.fontShadowColor);
singleStringFrame.setFontShadowOffsetX(this.fontShadowOffsetX);
singleStringFrame.setFontShadowOffsetY(this.fontShadowOffsetY);
singleStringFrame.addAnchor(
new AnchorDefinition(FramePoint.TOPLEFT, currentXCoordForFrames, -usedHeight));
this.internalFrames.add(singleStringFrame);
currentXCoordForFrames = currentXCoordForWord;
}
currentColor = this.color;
break;
case 'n':
case 'N': {
final String wordString = currentWord.toString();
currentWord.setLength(0);
glyphLayout.setText(this.frameFont, wordString);
final float wordWidth = glyphLayout.width;
if ((startingBoundsWidth > 0) && ((currentXCoordForWord + wordWidth) >= startingBoundsWidth)) {
final String currentLineString = currentLine.toString();
currentLine.setLength(0);
glyphLayout.setText(this.frameFont, currentLineString);
usedWidthMax = Math.max(currentXCoordForFrames + glyphLayout.width, usedWidthMax);
final SingleStringFrame singleStringFrame = new SingleStringFrame(currentLineString,
this.internalFramesContainer, currentColor, TextJustify.LEFT, TextJustify.TOP,
this.frameFont);
singleStringFrame.setHeight(this.frameFont.getLineHeight());
singleStringFrame.setWidth(glyphLayout.width);
singleStringFrame.setAlpha(this.alpha);
singleStringFrame.setFontShadowColor(this.fontShadowColor);
singleStringFrame.setFontShadowOffsetX(this.fontShadowOffsetX);
singleStringFrame.setFontShadowOffsetY(this.fontShadowOffsetY);
singleStringFrame.addAnchor(
new AnchorDefinition(FramePoint.TOPLEFT, currentXCoordForFrames, -usedHeight));
this.internalFrames.add(singleStringFrame);
usedHeight += this.frameFont.getLineHeight();
currentXCoordForWord = 0;
currentXCoordForFrames = 0;
}
currentXCoordForWord += wordWidth;
currentLine.append(wordString);
final String currentLineString = currentLine.toString();
currentLine.setLength(0);
glyphLayout.setText(this.frameFont, currentLineString);
usedWidthMax = Math.max(currentXCoordForFrames + glyphLayout.width, usedWidthMax);
final SingleStringFrame singleStringFrame = new SingleStringFrame(currentLineString,
this.internalFramesContainer, currentColor, TextJustify.LEFT, TextJustify.TOP,
this.frameFont);
singleStringFrame.setHeight(this.frameFont.getLineHeight());
singleStringFrame.setWidth(glyphLayout.width);
singleStringFrame.setAlpha(this.alpha);
singleStringFrame.setFontShadowColor(this.fontShadowColor);
singleStringFrame.setFontShadowOffsetX(this.fontShadowOffsetX);
singleStringFrame.setFontShadowOffsetY(this.fontShadowOffsetY);
singleStringFrame.addAnchor(
new AnchorDefinition(FramePoint.TOPLEFT, currentXCoordForFrames, -usedHeight));
this.internalFrames.add(singleStringFrame);
usedHeight += this.frameFont.getLineHeight();
currentXCoordForWord = 0;
currentXCoordForFrames = 0;
}
i++;
break;
default:
currentWord.append(c);
break;
}
}
}
break;
case ' ':
currentWord.append(' ');
final String wordString = currentWord.toString();
currentWord.setLength(0);
glyphLayout.setText(this.frameFont, wordString);
final float wordWidth = glyphLayout.width;
if ((startingBoundsWidth > 0) && ((currentXCoordForWord + wordWidth) >= startingBoundsWidth)) {
final String currentLineString = currentLine.toString();
currentLine.setLength(0);
glyphLayout.setText(this.frameFont, currentLineString);
usedWidthMax = Math.max(currentXCoordForFrames + glyphLayout.width, usedWidthMax);
final SingleStringFrame singleStringFrame = new SingleStringFrame(currentLineString,
this.internalFramesContainer, currentColor, TextJustify.LEFT, TextJustify.TOP,
this.frameFont);
singleStringFrame.setHeight(this.frameFont.getLineHeight());
singleStringFrame.setWidth(glyphLayout.width);
singleStringFrame.setAlpha(this.alpha);
singleStringFrame.setFontShadowColor(this.fontShadowColor);
singleStringFrame.setFontShadowOffsetX(this.fontShadowOffsetX);
singleStringFrame.setFontShadowOffsetY(this.fontShadowOffsetY);
singleStringFrame
.addAnchor(new AnchorDefinition(FramePoint.TOPLEFT, currentXCoordForFrames, -usedHeight));
this.internalFrames.add(singleStringFrame);
usedHeight += this.frameFont.getLineHeight();
currentXCoordForWord = 0;
currentXCoordForFrames = 0;
}
currentXCoordForWord += wordWidth;
currentLine.append(wordString);
break;
default:
currentWord.append(c);
break;
}
}
{
final String wordString = currentWord.toString();
currentWord.setLength(0);
glyphLayout.setText(this.frameFont, wordString);
final float wordWidth = glyphLayout.width;
if ((startingBoundsWidth > 0) && ((currentXCoordForWord + wordWidth) >= startingBoundsWidth)) {
final String currentLineString = currentLine.toString();
currentLine.setLength(0);
glyphLayout.setText(this.frameFont, currentLineString);
usedWidthMax = Math.max(currentXCoordForFrames + glyphLayout.width, usedWidthMax);
final SingleStringFrame singleStringFrame = new SingleStringFrame(currentLineString,
this.internalFramesContainer, currentColor, TextJustify.LEFT, TextJustify.TOP, this.frameFont);
singleStringFrame.setHeight(this.frameFont.getLineHeight());
singleStringFrame.setWidth(glyphLayout.width);
singleStringFrame.setAlpha(this.alpha);
singleStringFrame.setFontShadowColor(this.fontShadowColor);
singleStringFrame.setFontShadowOffsetX(this.fontShadowOffsetX);
singleStringFrame.setFontShadowOffsetY(this.fontShadowOffsetY);
singleStringFrame
.addAnchor(new AnchorDefinition(FramePoint.TOPLEFT, currentXCoordForFrames, -usedHeight));
this.internalFrames.add(singleStringFrame);
usedHeight += this.frameFont.getLineHeight();
currentXCoordForWord = 0;
currentXCoordForFrames = 0;
}
currentXCoordForWord += wordWidth;
currentLine.append(wordString);
final String currentLineString = currentLine.toString();
currentLine.setLength(0);
glyphLayout.setText(this.frameFont, currentLineString);
usedWidthMax = Math.max(currentXCoordForFrames + glyphLayout.width, usedWidthMax);
final SingleStringFrame singleStringFrame = new SingleStringFrame(currentLineString,
this.internalFramesContainer, currentColor, TextJustify.LEFT, TextJustify.TOP, this.frameFont);
singleStringFrame.setHeight(this.frameFont.getLineHeight());
singleStringFrame.setWidth(glyphLayout.width);
singleStringFrame.setAlpha(this.alpha);
singleStringFrame.setFontShadowColor(this.fontShadowColor);
singleStringFrame.setFontShadowOffsetX(this.fontShadowOffsetX);
singleStringFrame.setFontShadowOffsetY(this.fontShadowOffsetY);
singleStringFrame.addAnchor(new AnchorDefinition(FramePoint.TOPLEFT, currentXCoordForFrames, -usedHeight));
this.internalFrames.add(singleStringFrame);
currentXCoordForFrames = currentXCoordForWord;
usedHeight += this.frameFont.getCapHeight();
}
this.internalFramesContainer.setWidth(usedWidthMax);
this.internalFramesContainer.setHeight(usedHeight);
this.predictedViewportHeight = (usedHeight - this.frameFont.getCapHeight()) + this.frameFont.getLineHeight();
this.internalFramesContainer.clearFramePointAssignments();
switch (this.justifyH) {
case CENTER:
switch (this.justifyV) {
case MIDDLE:
this.internalFramesContainer.addAnchor(new AnchorDefinition(FramePoint.CENTER, 0, 0));
break;
case BOTTOM:
this.internalFramesContainer.addAnchor(new AnchorDefinition(FramePoint.BOTTOM, 0, 0));
break;
case TOP:
default:
this.internalFramesContainer.addAnchor(new AnchorDefinition(FramePoint.TOP, 0, 0));
break;
}
break;
case RIGHT:
switch (this.justifyV) {
case MIDDLE:
this.internalFramesContainer.addAnchor(new AnchorDefinition(FramePoint.RIGHT, 0, 0));
break;
case BOTTOM:
this.internalFramesContainer.addAnchor(new AnchorDefinition(FramePoint.BOTTOMRIGHT, 0, 0));
break;
case TOP:
default:
this.internalFramesContainer.addAnchor(new AnchorDefinition(FramePoint.TOPRIGHT, 0, 0));
break;
}
break;
case LEFT:
default:
switch (this.justifyV) {
case MIDDLE:
this.internalFramesContainer.addAnchor(new AnchorDefinition(FramePoint.LEFT, 0, 0));
break;
case BOTTOM:
this.internalFramesContainer.addAnchor(new AnchorDefinition(FramePoint.BOTTOMLEFT, 0, 0));
break;
case TOP:
default:
this.internalFramesContainer.addAnchor(new AnchorDefinition(FramePoint.TOPLEFT, 0, 0));
break;
}
break;
}
for (final SingleStringFrame internalFrame : this.internalFrames) {
this.internalFramesContainer.add(internalFrame);
}
}
public void setAlpha(final float alpha) {
this.alpha = alpha;
for (final SingleStringFrame internalFrame : this.internalFrames) {
internalFrame.setAlpha(alpha);
}
}
public float getPredictedViewportHeight() {
return this.predictedViewportHeight;
}
public BitmapFont getFrameFont() {
return this.frameFont;
}
}

View File

@ -0,0 +1,18 @@
package com.etheller.warsmash.parsers.fdf.frames;
public class TextButtonFrame extends GlueTextButtonFrame {
private float buttonPushedTextOffsetX;
private float buttonPushedTextOffsetY;
public TextButtonFrame(final String name, final UIFrame parent) {
super(name, parent);
}
public void setButtonPushedTextOffsetX(final float buttonPushedTextOffsetX) {
this.buttonPushedTextOffsetX = buttonPushedTextOffsetX;
}
public void setButtonPushedTextOffsetY(final float buttonPushedTextOffsetY) {
this.buttonPushedTextOffsetY = buttonPushedTextOffsetY;
}
}

View File

@ -0,0 +1,86 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
public class TextureFrame extends AbstractRenderableFrame {
private TextureRegion texture;
private final boolean decorateFileNames;
private final Vector4Definition texCoord;
private Color color;
public TextureFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
final Vector4Definition texCoord) {
super(name, parent);
this.decorateFileNames = decorateFileNames;
this.texCoord = texCoord;
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
if (this.texture == null) {
return;
}
if (this.color != null) {
batch.setColor(this.color);
}
batch.draw(this.texture, this.renderBounds.x, this.renderBounds.y, this.renderBounds.width,
this.renderBounds.height);
if (this.color != null) {
batch.setColor(1f, 1f, 1f, 1f);
}
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
}
public void setColor(final Color color) {
this.color = color;
}
public void setTexture(String file, final GameUI gameUI) {
if (this.decorateFileNames) {
file = gameUI.trySkinField(file);
}
final Texture texture = gameUI.loadTexture(file);
if (texture != null) {
setTexture(texture);
}
}
public void setTexCoord(final float x, final float y, final float z, final float w) {
this.texCoord.set(x, y, z, w);
if (this.texture != null) {
this.texture.setRegion(this.texCoord.getX(), this.texCoord.getZ(), this.texCoord.getY(),
this.texCoord.getW());
}
}
public void setTexture(final Texture texture) {
if (texture == null) {
this.texture = null;
return;
}
final TextureRegion texRegion;
if (this.texCoord != null) {
texRegion = new TextureRegion(texture, this.texCoord.getX(), this.texCoord.getZ(), this.texCoord.getY(),
this.texCoord.getW());
}
else {
texRegion = new TextureRegion(texture);
}
this.texture = texRegion;
}
public void setTexture(final TextureRegion texture) {
this.texture = texture;
}
}

View File

@ -0,0 +1,55 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
public interface UIFrame {
public void render(SpriteBatch batch, BitmapFont baseFont, GlyphLayout glyphLayout);
public float getFramePointX(FramePoint framePoint);
public float getFramePointY(FramePoint framePoint);
void setFramePointX(final FramePoint framePoint, final float x);
void setFramePointY(final FramePoint framePoint, final float y);
void positionBounds(GameUI gameUI, final Viewport viewport);
void addAnchor(final AnchorDefinition anchorDefinition);
void addSetPoint(SetPoint setPointDefinition);
void setWidth(final float width);
void setHeight(final float height);
float getAssignedWidth();
float getAssignedHeight();
void setSetAllPoints(boolean setAllPoints);
void setSetAllPoints(boolean setAllPoints, float inset);
void setVisible(boolean visible);
UIFrame getParent();
boolean isVisible();
boolean isVisibleOnScreen();
UIFrame touchDown(float screenX, float screenY, int button);
UIFrame touchUp(float screenX, float screenY, int button);
UIFrame getFrameChildUnderMouse(float screenX, float screenY);
String getName();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
package com.etheller.warsmash.parsers.jass;
import java.io.IOException;
import java.util.Arrays;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import com.etheller.interpreter.JassLexer;
import com.etheller.interpreter.JassParser;
import com.etheller.interpreter.ast.visitors.JassProgramVisitor;
import com.etheller.warsmash.datasources.CompoundDataSourceDescriptor;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.datasources.DataSourceDescriptor;
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
public class JassTest {
public static final boolean REPORT_SYNTAX_ERRORS = true;
public static void main(final String[] args) {
final JassProgramVisitor jassProgramVisitor = new JassProgramVisitor();
try {
final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor(
"E:\\Backups\\Warcraft\\Data\\127");
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor(
"E:\\Backups\\Warsmash\\Data");
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
final DataSource dataSource = new CompoundDataSourceDescriptor(
Arrays.<DataSourceDescriptor>asList(war3mpq, testingFolder, currentFolder)).createDataSource();
JassLexer lexer;
try {
lexer = new JassLexer(CharStreams.fromStream(dataSource.getResourceAsStream("Scripts\\common.j")));
}
catch (final IOException e) {
throw new RuntimeException(e);
}
final JassParser parser = new JassParser(new CommonTokenStream(lexer));
parser.addErrorListener(new BaseErrorListener() {
@Override
public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line,
final int charPositionInLine, final String msg, final RecognitionException e) {
if (!REPORT_SYNTAX_ERRORS) {
return;
}
String sourceName = recognizer.getInputStream().getSourceName();
if (!sourceName.isEmpty()) {
sourceName = String.format("%s:%d:%d: ", sourceName, line, charPositionInLine);
}
System.err.println(sourceName + "line " + line + ":" + charPositionInLine + " " + msg);
}
});
jassProgramVisitor.visit(parser.program());
}
catch (final Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,22 @@
package com.etheller.warsmash.parsers.jass;
import java.util.Scanner;
public class Tmpgen {
public static void main(final String[] args) {
// final HandleJassType eventType = globals.registerHandleType("event");
final Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
final String line = scanner.nextLine();
if (line.startsWith("type ")) {
final String[] splitLine = line.split("\\s+");
System.out.println("final HandleJassType " + splitLine[1] + "Type = globals.registerHandleType(\""
+ splitLine[1] + "\");");
}
}
}
}

View File

@ -0,0 +1,29 @@
package com.etheller.warsmash.parsers.jass;
import java.util.Scanner;
public class Tmpgen2 {
public static void main(final String[] args) {
// final HandleJassType eventType = globals.registerHandleType("event");
final Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
final String line = scanner.nextLine();
final String[] splitLine = line.trim().split("\\s+");
if (line.trim().startsWith("//")) {
System.out.println(line);
}
else {
if (splitLine.length > 3) {
System.out.println(splitLine[2] + ",");
}
else {
System.out.println();
}
}
}
}
}

View File

@ -0,0 +1,64 @@
package com.etheller.warsmash.parsers.jass.scope;
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayerJass;
public class CommonTriggerExecutionScope extends TriggerExecutionScope {
private final CUnit triggeringUnit;
private final CUnit filterUnit;
private final CUnit enumUnit;
private final CPlayerJass filterPlayer;
private final CPlayerJass enumPlayer;
public CommonTriggerExecutionScope(final TriggerExecutionScope parentScope, final CUnit triggeringUnit,
final CUnit filterUnit, final CUnit enumUnit, final CPlayerJass filterPlayer,
final CPlayerJass enumPlayer) {
super(parentScope.getTriggeringTrigger());
this.triggeringUnit = triggeringUnit;
this.filterUnit = filterUnit;
this.enumUnit = enumUnit;
this.filterPlayer = filterPlayer;
this.enumPlayer = enumPlayer;
}
public CUnit getEnumUnit() {
return this.enumUnit;
}
public CUnit getTriggeringUnit() {
return this.triggeringUnit;
}
public CUnit getFilterUnit() {
return this.filterUnit;
}
public CPlayerJass getFilterPlayer() {
return this.filterPlayer;
}
public CPlayerJass getEnumPlayer() {
return this.enumPlayer;
}
public static CommonTriggerExecutionScope filterScope(final TriggerExecutionScope parentScope,
final CUnit filterUnit) {
return new CommonTriggerExecutionScope(parentScope, null, filterUnit, null, null, null);
}
public static CommonTriggerExecutionScope enumScope(final TriggerExecutionScope parentScope, final CUnit enumUnit) {
return new CommonTriggerExecutionScope(parentScope, null, null, enumUnit, null, null);
}
public static CommonTriggerExecutionScope filterScope(final TriggerExecutionScope parentScope,
final CPlayerJass filterPlayer) {
return new CommonTriggerExecutionScope(parentScope, null, null, null, filterPlayer, null);
}
public static CommonTriggerExecutionScope enumScope(final TriggerExecutionScope parentScope,
final CPlayerJass enumPlayer) {
return new CommonTriggerExecutionScope(parentScope, null, null, null, null, enumPlayer);
}
}

View File

@ -0,0 +1,21 @@
package com.etheller.warsmash.parsers.jass.triggers;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
import com.etheller.interpreter.ast.scope.trigger.TriggerBooleanExpression;
public class BoolExprAnd implements TriggerBooleanExpression {
private final TriggerBooleanExpression operandA;
private final TriggerBooleanExpression operandB;
public BoolExprAnd(final TriggerBooleanExpression operandA, final TriggerBooleanExpression operandB) {
this.operandA = operandA;
this.operandB = operandB;
}
@Override
public boolean evaluate(final GlobalScope globalScope, final TriggerExecutionScope triggerScope) {
return this.operandA.evaluate(globalScope, triggerScope) && this.operandB.evaluate(globalScope, triggerScope);
}
}

View File

@ -0,0 +1,27 @@
package com.etheller.warsmash.parsers.jass.triggers;
import java.util.Collections;
import com.etheller.interpreter.ast.function.JassFunction;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
import com.etheller.interpreter.ast.scope.trigger.TriggerBooleanExpression;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.visitor.BooleanJassValueVisitor;
public class BoolExprCondition implements TriggerBooleanExpression {
private final JassFunction takesNothingReturnsBooleanFunction;
public BoolExprCondition(final JassFunction returnsBooleanFunction) {
this.takesNothingReturnsBooleanFunction = returnsBooleanFunction;
}
@Override
public boolean evaluate(final GlobalScope globalScope, final TriggerExecutionScope triggerScope) {
final JassValue booleanJassReturnValue = this.takesNothingReturnsBooleanFunction.call(Collections.EMPTY_LIST,
globalScope, triggerScope);
final Boolean booleanReturnValue = booleanJassReturnValue.visit(BooleanJassValueVisitor.getInstance());
return booleanReturnValue.booleanValue();
}
}

View File

@ -0,0 +1,27 @@
package com.etheller.warsmash.parsers.jass.triggers;
import java.util.Collections;
import com.etheller.interpreter.ast.function.JassFunction;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
import com.etheller.interpreter.ast.scope.trigger.TriggerBooleanExpression;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.visitor.BooleanJassValueVisitor;
public class BoolExprFilter implements TriggerBooleanExpression {
private final JassFunction takesNothingReturnsBooleanFunction;
public BoolExprFilter(final JassFunction returnsBooleanFunction) {
this.takesNothingReturnsBooleanFunction = returnsBooleanFunction;
}
@Override
public boolean evaluate(final GlobalScope globalScope, final TriggerExecutionScope triggerScope) {
final JassValue booleanJassReturnValue = this.takesNothingReturnsBooleanFunction.call(Collections.EMPTY_LIST,
globalScope, triggerScope);
final Boolean booleanReturnValue = booleanJassReturnValue.visit(BooleanJassValueVisitor.getInstance());
return booleanReturnValue.booleanValue();
}
}

View File

@ -0,0 +1,19 @@
package com.etheller.warsmash.parsers.jass.triggers;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
import com.etheller.interpreter.ast.scope.trigger.TriggerBooleanExpression;
public class BoolExprNot implements TriggerBooleanExpression {
private final TriggerBooleanExpression operand;
public BoolExprNot(final TriggerBooleanExpression operand) {
this.operand = operand;
}
@Override
public boolean evaluate(final GlobalScope globalScope, final TriggerExecutionScope triggerScope) {
return this.operand.evaluate(globalScope, triggerScope);
}
}

View File

@ -0,0 +1,21 @@
package com.etheller.warsmash.parsers.jass.triggers;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
import com.etheller.interpreter.ast.scope.trigger.TriggerBooleanExpression;
public class BoolExprOr implements TriggerBooleanExpression {
private final TriggerBooleanExpression operandA;
private final TriggerBooleanExpression operandB;
public BoolExprOr(final TriggerBooleanExpression operandA, final TriggerBooleanExpression operandB) {
this.operandA = operandA;
this.operandB = operandB;
}
@Override
public boolean evaluate(final GlobalScope globalScope, final TriggerExecutionScope triggerScope) {
return this.operandA.evaluate(globalScope, triggerScope) || this.operandB.evaluate(globalScope, triggerScope);
}
}

View File

@ -0,0 +1,28 @@
package com.etheller.warsmash.parsers.jass.triggers;
import com.etheller.interpreter.ast.function.JassFunction;
import com.etheller.interpreter.ast.scope.trigger.Trigger;
public class TriggerAction {
private final Trigger trigger;
private final JassFunction actionFunc;
private final int actionIndex;
public TriggerAction(final Trigger trigger, final JassFunction actionFunc, final int actionIndex) {
this.trigger = trigger;
this.actionFunc = actionFunc;
this.actionIndex = actionIndex;
}
public Trigger getTrigger() {
return this.trigger;
}
public JassFunction getActionFunc() {
return this.actionFunc;
}
public int getActionIndex() {
return this.actionIndex;
}
}

View File

@ -0,0 +1,28 @@
package com.etheller.warsmash.parsers.jass.triggers;
import com.etheller.interpreter.ast.scope.trigger.Trigger;
import com.etheller.interpreter.ast.scope.trigger.TriggerBooleanExpression;
public class TriggerCondition {
private final TriggerBooleanExpression boolexpr;
private final Trigger trigger;
private final int conditionIndex;
public TriggerCondition(final TriggerBooleanExpression boolexpr, final Trigger trigger, final int index) {
this.boolexpr = boolexpr;
this.trigger = trigger;
this.conditionIndex = index;
}
public TriggerBooleanExpression getBoolexpr() {
return this.boolexpr;
}
public Trigger getTrigger() {
return this.trigger;
}
public int getConditionIndex() {
return this.conditionIndex;
}
}

View File

@ -0,0 +1,27 @@
package com.etheller.warsmash.parsers.terrain;
public class Corner {
boolean mapEdge;
int groundTexture;
float height;
float waterHeight;
boolean ramp;
boolean blight;
boolean water;
boolean boundary;
boolean cliff;
boolean romp;
int groundVariation;
int cliffVariation;
int cliffTexture;
int layerHeight;
public float finalGroundHeight() {
return 0;
}
public float finalWaterHeight() {
return 0;
}
}

View File

@ -0,0 +1,13 @@
package com.etheller.warsmash.parsers.terrain;
import com.badlogic.gdx.utils.FloatArray;
public class Terrain {
private FloatArray groundHeights;
private FloatArray groundCornerHeights;
private FloatArray waterHeights;
public Terrain() {
}
}

View File

@ -0,0 +1,15 @@
package com.etheller.warsmash.parsers.terrain;
public class TilePathing {
boolean unwalkable = false;
boolean unflyable = false;
boolean unbuildable = false;
public byte mask() {
byte mask = 0;
mask |= this.unwalkable ? 0b00000010 : 0;
mask |= this.unflyable ? 0b00000100 : 0;
mask |= this.unbuildable ? 0b00001000 : 0;
return mask;
}
}

View File

@ -0,0 +1,147 @@
package com.etheller.warsmash.parsers.w3x;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.util.Arrays;
import java.util.Collection;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
import com.etheller.warsmash.datasources.CompoundDataSource;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.datasources.MpqDataSource;
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.War3MapW3e;
import com.etheller.warsmash.parsers.w3x.w3i.War3MapW3i;
import com.etheller.warsmash.parsers.w3x.wpm.War3MapWpm;
import com.etheller.warsmash.units.custom.WTS;
import com.google.common.io.LittleEndianDataInputStream;
import mpq.MPQArchive;
import mpq.MPQException;
/**
* Warcraft 3 map (W3X and W3M).
*/
public class War3Map implements DataSource {
private CompoundDataSource dataSource;
private MpqDataSource internalMpqContentsDataSource;
public War3Map(final DataSource dataSource, final String mapFileName) {
try {
// Slightly complex. Here's the theory:
// 1.) Copy map into RAM
// 2.) Setup a Data Source that will read assets
// from either the map or the game, giving the map priority.
SeekableByteChannel sbc;
try (InputStream mapStream = dataSource.getResourceAsStream(mapFileName)) {
final byte[] mapData = IOUtils.toByteArray(mapStream);
sbc = new SeekableInMemoryByteChannel(mapData);
this.internalMpqContentsDataSource = new MpqDataSource(new MPQArchive(sbc), sbc);
this.dataSource = new CompoundDataSource(Arrays.asList(dataSource, this.internalMpqContentsDataSource));
}
}
catch (final IOException e) {
throw new RuntimeException(e);
}
catch (final MPQException e) {
throw new RuntimeException(e);
}
}
public War3MapW3i readMapInformation() throws IOException {
War3MapW3i mapInfo;
try (LittleEndianDataInputStream stream = new LittleEndianDataInputStream(
this.dataSource.getResourceAsStream("war3map.w3i"))) {
mapInfo = new War3MapW3i(stream);
}
return mapInfo;
}
public War3MapW3e readEnvironment() throws IOException {
War3MapW3e environment;
try (LittleEndianDataInputStream stream = new LittleEndianDataInputStream(
this.dataSource.getResourceAsStream("war3map.w3e"))) {
environment = new War3MapW3e(stream);
}
return environment;
}
public War3MapWpm readPathing() throws IOException {
War3MapWpm pathingMap;
try (LittleEndianDataInputStream stream = new LittleEndianDataInputStream(
this.dataSource.getResourceAsStream("war3map.wpm"))) {
pathingMap = new War3MapWpm(stream);
}
return pathingMap;
}
public War3MapDoo readDoodads() throws IOException {
War3MapDoo doodadsFile;
try (LittleEndianDataInputStream stream = new LittleEndianDataInputStream(
this.dataSource.getResourceAsStream("war3map.doo"))) {
doodadsFile = new War3MapDoo(stream);
}
return doodadsFile;
}
public War3MapUnitsDoo readUnits() throws IOException {
War3MapUnitsDoo unitsFile;
try (LittleEndianDataInputStream stream = new LittleEndianDataInputStream(
this.dataSource.getResourceAsStream("war3mapUnits.doo"))) {
unitsFile = new War3MapUnitsDoo(stream);
}
return unitsFile;
}
public Warcraft3MapObjectData readModifications() throws IOException {
final Warcraft3MapObjectData changes = Warcraft3MapObjectData.load(this.dataSource, true);
return changes;
}
public Warcraft3MapObjectData readModifications(final WTS preloadedWTS) throws IOException {
final Warcraft3MapObjectData changes = Warcraft3MapObjectData.load(this.dataSource, true, preloadedWTS);
return changes;
}
@Override
public InputStream getResourceAsStream(final String filepath) throws IOException {
return this.dataSource.getResourceAsStream(filepath);
}
@Override
public File getFile(final String filepath) throws IOException {
return this.dataSource.getFile(filepath);
}
@Override
public boolean has(final String filepath) {
return this.dataSource.has(filepath);
}
@Override
public ByteBuffer read(final String path) throws IOException {
return this.dataSource.read(path);
}
@Override
public Collection<String> getListfile() {
return this.internalMpqContentsDataSource.getListfile();
}
@Override
public void close() throws IOException {
this.dataSource.close();
}
public CompoundDataSource getCompoundDataSource() {
return this.dataSource;
}
}

View File

@ -0,0 +1,157 @@
package com.etheller.warsmash.parsers.w3x.doo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.etheller.warsmash.util.ParseUtils;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
public class Doodad {
private War3ID id;
private int variation;
private final float[] location = new float[3];
private float angle;
private final float[] scale = { 1f, 1f, 1f };
private short flags; // short to store unsigned byte, java problem
private short life; // short to store unsigned byte, java problem
private long itemTable = -1; // long to store unsigned int32, java problem
private final List<RandomItemSet> itemSets = new ArrayList<>();
private int editorId;
private final short[] u1 = new short[8]; // short to store unsigned byte, java problem
public void load(final LittleEndianDataInputStream stream, final int version) throws IOException {
this.id = ParseUtils.readWar3ID(stream);
this.variation = stream.readInt();
ParseUtils.readFloatArray(stream, this.location);
this.angle = stream.readFloat();
ParseUtils.readFloatArray(stream, this.scale);
this.flags = ParseUtils.readUInt8(stream);
this.life = ParseUtils.readUInt8(stream);
if (version > 7) {
this.itemTable = ParseUtils.readUInt32(stream);
for (long i = 0, l = ParseUtils.readUInt32(stream); i < l; i++) {
final RandomItemSet itemSet = new RandomItemSet();
itemSet.load(stream);
this.itemSets.add(itemSet);
}
}
this.editorId = stream.readInt();
}
public void save(final LittleEndianDataOutputStream stream, final int version) throws IOException {
ParseUtils.writeWar3ID(stream, this.id);
;
stream.writeInt(this.variation);
ParseUtils.writeFloatArray(stream, this.location);
stream.writeFloat(this.angle);
ParseUtils.writeFloatArray(stream, this.scale);
ParseUtils.writeUInt8(stream, this.flags);
ParseUtils.writeUInt8(stream, this.life);
if (version > 7) {
ParseUtils.writeUInt32(stream, this.itemTable);
ParseUtils.writeUInt32(stream, this.itemSets.size());
for (final RandomItemSet itemSet : this.itemSets) {
itemSet.save(stream);
}
}
stream.writeInt(this.editorId);
}
public int getByteLength(final int version) {
int size = 42;
if (version > 7) {
size += 8;
for (final RandomItemSet itemSet : this.itemSets) {
size += itemSet.getByteLength();
}
}
return size;
}
public War3ID getId() {
return this.id;
}
public void setId(final War3ID id) {
this.id = id;
}
public int getVariation() {
return this.variation;
}
public void setVariation(final int variation) {
this.variation = variation;
}
public float getAngle() {
return this.angle;
}
public void setAngle(final float angle) {
this.angle = angle;
}
public short getFlags() {
return this.flags;
}
public void setFlags(final short flags) {
this.flags = flags;
}
public short getLife() {
return this.life;
}
public void setLife(final short life) {
this.life = life;
}
public long getItemTable() {
return this.itemTable;
}
public void setItemTable(final long itemTable) {
this.itemTable = itemTable;
}
public int getEditorId() {
return this.editorId;
}
public void setEditorId(final int editorId) {
this.editorId = editorId;
}
public float[] getLocation() {
return this.location;
}
public float[] getScale() {
return this.scale;
}
public List<RandomItemSet> getItemSets() {
return this.itemSets;
}
public short[] getU1() {
return this.u1;
}
}

View File

@ -0,0 +1,23 @@
package com.etheller.warsmash.parsers.w3x.doo;
import java.io.IOException;
import com.etheller.warsmash.util.ParseUtils;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
public class RandomItem {
private War3ID id;
private int chance;
public void load(final LittleEndianDataInputStream stream) throws IOException {
this.id = ParseUtils.readWar3ID(stream);
this.chance = stream.readInt();
}
public void save(final LittleEndianDataOutputStream stream) throws IOException {
ParseUtils.writeWar3ID(stream, this.id);
stream.writeInt(this.chance);
}
}

View File

@ -0,0 +1,34 @@
package com.etheller.warsmash.parsers.w3x.doo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.etheller.warsmash.util.ParseUtils;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
public class RandomItemSet {
private final List<RandomItem> items = new ArrayList<>();
public void load(final LittleEndianDataInputStream stream) throws IOException {
for (long i = 0, l = ParseUtils.readUInt32(stream); i < l; i++) {
final RandomItem item = new RandomItem();
item.load(stream);
this.items.add(item);
}
}
public void save(final LittleEndianDataOutputStream stream) throws IOException {
ParseUtils.writeUInt32(stream, this.items.size());
for (final RandomItem item : this.items) {
item.save(stream);
}
}
public int getByteLength() {
return 4 + (this.items.size() * 8);
}
}

View File

@ -0,0 +1,54 @@
package com.etheller.warsmash.parsers.w3x.doo;
import java.io.IOException;
import com.etheller.warsmash.util.ParseUtils;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
/**
* A terrain doodad.
*
* This type of doodad works much like cliffs. It uses the height of the
* terrain, and gets affected by the ground heightmap. It cannot be manipulated
* in any way in the World Editor once placed. Indeed, the only way to change it
* is to remove it by changing cliffs around it.
*/
public class TerrainDoodad {
private War3ID id;
private long u1;
private final long[] location = new long[2];
public void load(final LittleEndianDataInputStream stream, final int version) throws IOException {
this.id = ParseUtils.readWar3ID(stream);
this.u1 = ParseUtils.readUInt32(stream);
ParseUtils.readUInt32Array(stream, this.location);
}
public void save(final LittleEndianDataOutputStream stream, final int version) throws IOException {
ParseUtils.writeWar3ID(stream, this.id);
ParseUtils.writeUInt32(stream, this.u1);
ParseUtils.writeUInt32Array(stream, this.location);
}
public War3ID getId() {
return this.id;
}
public long getU1() {
return this.u1;
}
public long[] getLocation() {
return this.location;
}
public void setId(final War3ID id) {
this.id = id;
}
public void setU1(final long u1) {
this.u1 = u1;
}
}

View File

@ -0,0 +1,108 @@
package com.etheller.warsmash.parsers.w3x.doo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.etheller.warsmash.util.ParseUtils;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
/**
* war3map.doo - the doodad and destructible file.
*/
public class War3MapDoo {
private static final War3ID MAGIC_NUMBER = War3ID.fromString("W3do");
private int version = 0;
private final short[] u1 = new short[4];
private final List<Doodad> doodads = new ArrayList<>();
private final short[] u2 = new short[4];
private final List<TerrainDoodad> terrainDoodads = new ArrayList<>();
public War3MapDoo(final LittleEndianDataInputStream stream) throws IOException {
if (stream != null) {
this.load(stream);
}
}
private boolean load(final LittleEndianDataInputStream stream) throws IOException {
final War3ID firstId = ParseUtils.readWar3ID(stream);
if (!MAGIC_NUMBER.equals(firstId)) {
return false;
}
this.version = stream.readInt();
ParseUtils.readUInt8Array(stream, this.u1);
for (int i = 0, l = stream.readInt(); i < l; i++) {
final Doodad doodad = new Doodad();
doodad.load(stream, this.version);
this.doodads.add(doodad);
}
ParseUtils.readUInt8Array(stream, this.u2);
for (int i = 0, l = stream.readInt(); i < l; i++) {
final TerrainDoodad terrainDoodad = new TerrainDoodad();
terrainDoodad.load(stream, this.version);
this.terrainDoodads.add(terrainDoodad);
}
return true;
}
public void save(final LittleEndianDataOutputStream stream) throws IOException {
ParseUtils.writeWar3ID(stream, MAGIC_NUMBER);
stream.writeInt(this.version);
ParseUtils.writeUInt8Array(stream, this.u1);
ParseUtils.writeUInt32(stream, this.doodads.size());
for (final Doodad doodad : this.doodads) {
doodad.save(stream, this.version);
}
ParseUtils.writeUInt8Array(stream, this.u2);
ParseUtils.writeUInt32(stream, this.terrainDoodads.size());
for (final TerrainDoodad terrainDoodad : this.terrainDoodads) {
terrainDoodad.save(stream, this.version);
}
}
public int getByteLength() {
int size = 24 + (this.terrainDoodads.size() * 16);
for (final Doodad doodad : this.doodads) {
size += doodad.getByteLength(this.version);
}
return size;
}
public int getVersion() {
return this.version;
}
public short[] getU1() {
return this.u1;
}
public List<Doodad> getDoodads() {
return this.doodads;
}
public short[] getU2() {
return this.u2;
}
public List<TerrainDoodad> getTerrainDoodads() {
return this.terrainDoodads;
}
}

View File

@ -0,0 +1,98 @@
package com.etheller.warsmash.parsers.w3x.objectdata;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.etheller.warsmash.datasources.CompoundDataSourceDescriptor;
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
import com.etheller.warsmash.datasources.MpqDataSourceDescriptor;
import com.etheller.warsmash.units.GameObject;
import com.etheller.warsmash.units.ObjectData;
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataOutputStream;
public class MakeMeTFTBeROC {
public static void main(final String[] args) {
try {
final MpqDataSourceDescriptor reignOfChaosData = new MpqDataSourceDescriptor(
"E:\\Games\\Warcraft III Patch 1.14\\war3.mpq");
final Warcraft3MapObjectData reignOfChaosUnitData = Warcraft3MapObjectData
.load(reignOfChaosData.createDataSource(), true);
final FolderDataSourceDescriptor tftDesc1 = new FolderDataSourceDescriptor(
"D:\\NEEDS_ORGANIZING\\Reforged Beta 13991\\war3.w3mod");
final FolderDataSourceDescriptor tftDesc2 = new FolderDataSourceDescriptor(
"D:\\NEEDS_ORGANIZING\\Reforged Beta 13991\\war3.w3mod\\_balance\\custom_v1.w3mod");
final FolderDataSourceDescriptor tftDesc3 = new FolderDataSourceDescriptor(
"D:\\NEEDS_ORGANIZING\\Reforged Beta 13991\\war3.w3mod\\_locales\\enus.w3mod");
final CompoundDataSourceDescriptor frozenThroneData = new CompoundDataSourceDescriptor(
Arrays.asList(tftDesc1, tftDesc2, tftDesc3));
final Warcraft3MapObjectData frozenThroneUnitData = Warcraft3MapObjectData
.load(frozenThroneData.createDataSource(), true);
for (final War3ID unitId : reignOfChaosUnitData.getUnits().keySet()) {
final MutableGameObject reignOfChaosUnit = reignOfChaosUnitData.getUnits().get(unitId);
final MutableGameObject frozenThroneEquivalentUnit = frozenThroneUnitData.getUnits().get(unitId);
if (frozenThroneEquivalentUnit == null) {
System.err.println("No TFT equivalent for: " + reignOfChaosUnit.getName());
continue;
}
final ObjectData metaDataSlk = reignOfChaosUnitData.getUnits().getSourceSLKMetaData();
for (final String fieldTypeId : metaDataSlk.keySet()) {
final War3ID fieldTypeIdCode = War3ID.fromString(fieldTypeId);
final GameObject unitFieldInformation = metaDataSlk.get(fieldTypeId);
if (unitFieldInformation.getFieldValue("useItem") == 1) {
continue;
}
final String fieldType = unitFieldInformation.getField("type");
switch (fieldType) {
case "int":
frozenThroneEquivalentUnit.setField(fieldTypeIdCode, 0,
reignOfChaosUnit.getFieldAsInteger(fieldTypeIdCode, 0));
break;
case "real":
case "unreal":
frozenThroneEquivalentUnit.setField(fieldTypeIdCode, 0,
reignOfChaosUnit.getFieldAsFloat(fieldTypeIdCode, 0));
break;
case "bool":
frozenThroneEquivalentUnit.setField(fieldTypeIdCode, 0,
reignOfChaosUnit.getFieldAsBoolean(fieldTypeIdCode, 0));
break;
case "string":
case "abilityList":
case "stringList":
case "soundLabel":
case "unitList":
case "itemList":
case "techList":
case "intList":
case "model":
case "char":
case "icon":
frozenThroneEquivalentUnit.setField(fieldTypeIdCode, 0,
reignOfChaosUnit.getFieldAsString(fieldTypeIdCode, 0));
break;
default: // treat as string
break;
}
}
}
try (LittleEndianDataOutputStream outputStream = new LittleEndianDataOutputStream(
new FileOutputStream("C:\\Users\\micro\\OneDrive\\Documents\\Warcraft III\\Data\\roc.w3u"))) {
frozenThroneUnitData.getUnits().getEditorData().save(outputStream, false);
}
}
catch (final IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,184 @@
package com.etheller.warsmash.parsers.w3x.objectdata;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.StandardObjectData;
import com.etheller.warsmash.units.StandardObjectData.WarcraftData;
import com.etheller.warsmash.units.custom.WTS;
import com.etheller.warsmash.units.custom.WTSFile;
import com.etheller.warsmash.units.custom.War3ObjectDataChangeset;
import com.etheller.warsmash.units.manager.MutableObjectData;
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
import com.etheller.warsmash.util.WorldEditStrings;
import com.google.common.io.LittleEndianDataInputStream;
public final class Warcraft3MapObjectData {
private final MutableObjectData units;
private final MutableObjectData items;
private final MutableObjectData destructibles;
private final MutableObjectData doodads;
private final MutableObjectData abilities;
private final MutableObjectData buffs;
private final MutableObjectData upgrades;
private final List<MutableObjectData> datas;
private transient Map<WorldEditorDataType, MutableObjectData> typeToData = new HashMap<>();
private final WTS wts;
public Warcraft3MapObjectData(final MutableObjectData units, final MutableObjectData items,
final MutableObjectData destructibles, final MutableObjectData doodads, final MutableObjectData abilities,
final MutableObjectData buffs, final MutableObjectData upgrades, final WTS wts) {
this.units = units;
this.items = items;
this.destructibles = destructibles;
this.doodads = doodads;
this.abilities = abilities;
this.buffs = buffs;
this.upgrades = upgrades;
this.datas = new ArrayList<>();
this.datas.add(units);
this.datas.add(items);
this.datas.add(destructibles);
this.datas.add(doodads);
this.datas.add(abilities);
this.datas.add(buffs);
this.datas.add(upgrades);
for (final MutableObjectData data : this.datas) {
this.typeToData.put(data.getWorldEditorDataType(), data);
}
this.wts = wts;
}
public MutableObjectData getDataByType(final WorldEditorDataType type) {
return this.typeToData.get(type);
}
public MutableObjectData getUnits() {
return this.units;
}
public MutableObjectData getItems() {
return this.items;
}
public MutableObjectData getDestructibles() {
return this.destructibles;
}
public MutableObjectData getDoodads() {
return this.doodads;
}
public MutableObjectData getAbilities() {
return this.abilities;
}
public MutableObjectData getBuffs() {
return this.buffs;
}
public MutableObjectData getUpgrades() {
return this.upgrades;
}
public List<MutableObjectData> getDatas() {
return this.datas;
}
public WTS getWts() {
return this.wts;
}
public static WTS loadWTS(final DataSource dataSource) throws IOException {
final WTS wts = dataSource.has("war3map.wts") ? new WTSFile(dataSource.getResourceAsStream("war3map.wts"))
: WTS.DO_NOTHING;
return wts;
}
public static Warcraft3MapObjectData load(final DataSource dataSource, final boolean inlineWTS) throws IOException {
final WTS wts = loadWTS(dataSource);
return load(dataSource, inlineWTS, wts);
}
public static Warcraft3MapObjectData load(final DataSource dataSource, final boolean inlineWTS, final WTS wts)
throws IOException {
final StandardObjectData standardObjectData = new StandardObjectData(dataSource);
final WarcraftData standardUnits = standardObjectData.getStandardUnits();
final WarcraftData standardItems = standardObjectData.getStandardItems();
final WarcraftData standardDoodads = standardObjectData.getStandardDoodads();
final WarcraftData standardDestructables = standardObjectData.getStandardDestructables();
final WarcraftData abilities = standardObjectData.getStandardAbilities();
final WarcraftData standardAbilityBuffs = standardObjectData.getStandardAbilityBuffs();
final WarcraftData standardUpgrades = standardObjectData.getStandardUpgrades();
final DataTable standardUnitMeta = standardObjectData.getStandardUnitMeta();
final DataTable standardDoodadMeta = standardObjectData.getStandardDoodadMeta();
final DataTable standardDestructableMeta = standardObjectData.getStandardDestructableMeta();
final DataTable abilityMeta = standardObjectData.getStandardAbilityMeta();
final DataTable standardAbilityBuffMeta = standardObjectData.getStandardAbilityBuffMeta();
final DataTable standardUpgradeMeta = standardObjectData.getStandardUpgradeMeta();
final War3ObjectDataChangeset unitChangeset = new War3ObjectDataChangeset('u');
final War3ObjectDataChangeset itemChangeset = new War3ObjectDataChangeset('t');
final War3ObjectDataChangeset doodadChangeset = new War3ObjectDataChangeset('d');
final War3ObjectDataChangeset destructableChangeset = new War3ObjectDataChangeset('b');
final War3ObjectDataChangeset abilityChangeset = new War3ObjectDataChangeset('a');
final War3ObjectDataChangeset buffChangeset = new War3ObjectDataChangeset('h');
final War3ObjectDataChangeset upgradeChangeset = new War3ObjectDataChangeset('q');
if (dataSource.has("war3map.w3u")) {
unitChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3u")), wts,
inlineWTS);
}
if (dataSource.has("war3map.w3t")) {
itemChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3t")), wts,
inlineWTS);
}
if (dataSource.has("war3map.w3d")) {
doodadChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3d")), wts,
inlineWTS);
}
if (dataSource.has("war3map.w3b")) {
destructableChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3b")),
wts, inlineWTS);
}
if (dataSource.has("war3map.w3a")) {
abilityChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3a")), wts,
inlineWTS);
}
if (dataSource.has("war3map.w3h")) {
buffChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3h")), wts,
inlineWTS);
}
if (dataSource.has("war3map.w3q")) {
upgradeChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3q")), wts,
inlineWTS);
}
final WorldEditStrings worldEditStrings = standardObjectData.getWorldEditStrings();
final MutableObjectData unitData = new MutableObjectData(worldEditStrings, WorldEditorDataType.UNITS,
standardUnits, standardUnitMeta, unitChangeset);
final MutableObjectData itemData = new MutableObjectData(worldEditStrings, WorldEditorDataType.ITEM,
standardItems, standardUnitMeta, itemChangeset);
final MutableObjectData doodadData = new MutableObjectData(worldEditStrings, WorldEditorDataType.DOODADS,
standardDoodads, standardDoodadMeta, doodadChangeset);
final MutableObjectData destructableData = new MutableObjectData(worldEditStrings,
WorldEditorDataType.DESTRUCTIBLES, standardDestructables, standardDestructableMeta,
destructableChangeset);
final MutableObjectData abilityData = new MutableObjectData(worldEditStrings, WorldEditorDataType.ABILITIES,
abilities, abilityMeta, abilityChangeset);
final MutableObjectData buffData = new MutableObjectData(worldEditStrings, WorldEditorDataType.BUFFS_EFFECTS,
standardAbilityBuffs, standardAbilityBuffMeta, buffChangeset);
final MutableObjectData upgradeData = new MutableObjectData(worldEditStrings, WorldEditorDataType.UPGRADES,
standardUpgrades, standardUpgradeMeta, upgradeChangeset);
return new Warcraft3MapObjectData(unitData, itemData, destructableData, doodadData, abilityData, buffData,
upgradeData, wts);
}
}

View File

@ -0,0 +1,26 @@
package com.etheller.warsmash.parsers.w3x.unitsdoo;
import java.io.IOException;
import com.etheller.warsmash.util.ParseUtils;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
/**
* A dropped item.
*/
public class DroppedItem {
private War3ID id;
private int chance;
public void load(final LittleEndianDataInputStream stream) throws IOException {
this.id = ParseUtils.readWar3ID(stream);
this.chance = stream.readInt();
}
public void save(final LittleEndianDataOutputStream stream) throws IOException {
ParseUtils.writeWar3ID(stream, this.id);
stream.writeInt(this.chance);
}
}

View File

@ -0,0 +1,38 @@
package com.etheller.warsmash.parsers.w3x.unitsdoo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.etheller.warsmash.util.ParseUtils;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
/**
* A dropped item set.
*/
public class DroppedItemSet {
private final List<DroppedItem> items = new ArrayList<>();
public void load(final LittleEndianDataInputStream stream) throws IOException {
for (long i = 0, l = ParseUtils.readUInt32(stream); i < l; i++) {
final DroppedItem item = new DroppedItem();
item.load(stream);
this.items.add(item);
}
}
public void save(final LittleEndianDataOutputStream stream) throws IOException {
ParseUtils.writeUInt32(stream, this.items.size());
for (final DroppedItem item : this.items) {
item.save(stream);
}
}
public int getByteLength() {
return 4 + (this.items.size() * 8);
}
}

View File

@ -0,0 +1,26 @@
package com.etheller.warsmash.parsers.w3x.unitsdoo;
import java.io.IOException;
import com.etheller.warsmash.util.ParseUtils;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
/**
* An inventory item.
*/
public class InventoryItem {
private int slot;
private War3ID id;
public void load(final LittleEndianDataInputStream stream) throws IOException {
this.slot = stream.readInt();
this.id = ParseUtils.readWar3ID(stream);
}
public void save(final LittleEndianDataOutputStream stream) throws IOException {
stream.writeInt(this.slot);
ParseUtils.writeWar3ID(stream, this.id);
}
}

View File

@ -0,0 +1,26 @@
package com.etheller.warsmash.parsers.w3x.unitsdoo;
import java.io.IOException;
import com.etheller.warsmash.util.ParseUtils;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
public class ModifiedAbility {
private War3ID id;
private int activeForAutocast = 0;
private int heroLevel = 1;
public void load(final LittleEndianDataInputStream stream) throws IOException {
this.id = ParseUtils.readWar3ID(stream);
this.activeForAutocast = stream.readInt();
this.heroLevel = stream.readInt();
}
public void save(final LittleEndianDataOutputStream stream) throws IOException {
ParseUtils.writeWar3ID(stream, this.id);
stream.writeInt(this.activeForAutocast);
stream.writeInt(this.heroLevel);
}
}

Some files were not shown because too many files have changed in this diff Show More