Updates for HD models render support

This commit is contained in:
Retera 2022-02-03 01:58:50 -05:00
parent 35a489b1f8
commit 1eb0fdf168
25 changed files with 741 additions and 187 deletions

View File

@ -821,6 +821,12 @@ public class WarsmashGdxFDFTestRenderScreen implements InputProcessor, Screen, S
}
@Override
public void setReplaceableTextureHD(final int replaceableTextureId, final String replaceableTextureFile) {
// TODO Auto-generated method stub
}
}
private class LibGDXContentLayerModel extends Model {

View File

@ -452,6 +452,12 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
}
@Override
public void setReplaceableTextureHD(final int replaceableTextureId, final String replaceableTextureFile) {
// TODO Auto-generated method stub
}
}
private class LibGDXContentLayerModel extends Model {

View File

@ -857,6 +857,12 @@ public class WarsmashGdxMenuScreen implements InputProcessor, Screen, SingleMode
}
@Override
public void setReplaceableTextureHD(final int replaceableTextureId, final String replaceableTextureFile) {
// TODO Auto-generated method stub
}
}
private class LibGDXContentLayerModel extends Model {

View File

@ -3112,48 +3112,6 @@ public class Jass2 {
throw new JassException(globalScope, "Needs to sleep " + time, null);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetPlayerNeutralAggressive", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS - 4);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetBJPlayerNeutralVictim", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS - 3);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetBJPlayerNeutralExtra", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS - 2);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetPlayerNeutralPassive", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS - 1);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetBJMaxPlayers", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS - 4);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetBJMaxPlayerSlots", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS);
}
});
jassProgramVisitor.getJassNativeManager().createNative("AddSpecialEffectTarget", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
@ -4890,6 +4848,49 @@ public class Jass2 {
return new IntegerJassValue(whichPlayer.getId());
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetPlayerNeutralAggressive", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS - 4);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetBJPlayerNeutralVictim", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS - 3);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetBJPlayerNeutralExtra", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS - 2);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetPlayerNeutralPassive", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS - 1);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetBJMaxPlayers", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS - 4);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetBJMaxPlayerSlots", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(WarsmashConstants.MAX_PLAYERS);
}
});
}
public static void registerTypingNatives(final JassProgramVisitor jassProgramVisitor, final HandleJassType raceType,

View File

@ -38,7 +38,7 @@ public class Camera {
/**
* World -> View.
*/
private final Matrix4 viewMatrix;
public final Matrix4 viewMatrix;
/**
* View -> Clip.
*/

View File

@ -225,5 +225,7 @@ public abstract class ModelInstance extends Node {
public abstract void setReplaceableTexture(int replaceableTextureId, String replaceableTextureFile);
public abstract void setReplaceableTextureHD(int replaceableTextureId, String replaceableTextureFile);
protected abstract void removeLights(Scene scene2);
}

View File

@ -22,6 +22,63 @@ public class Shaders {
" texture2D(u_boneMap, vec2(column + u_vectorSize * 2.0, row)),\r\n" + //
" texture2D(u_boneMap, vec2(column + u_vectorSize * 3.0, row)));\r\n" + //
" }";
public static final String transforms = "#ifdef SKIN\r\n" + //
"attribute vec4 a_bones;\r\n" + //
"attribute vec4 a_weights;\r\n" + //
"void transformSkin(inout vec3 position, inout vec3 normal, inout vec3 tangent, inout vec3 binormal) {\r\n"
+ //
" mat4 bone = mat4(0);\r\n" + //
" bone += fetchMatrix(a_bones[0], 0.0) * a_weights[0];\r\n" + //
" bone += fetchMatrix(a_bones[1], 0.0) * a_weights[1];\r\n" + //
" bone += fetchMatrix(a_bones[2], 0.0) * a_weights[2];\r\n" + //
" bone += fetchMatrix(a_bones[3], 0.0) * a_weights[3];\r\n" + //
" mat3 rotation = mat3(bone);\r\n" + //
" position = vec3(bone * vec4(position, 1.0));\r\n" + //
" normal = rotation * normal;\r\n" + //
" tangent = rotation * tangent;\r\n" + //
" binormal = rotation * binormal;\r\n" + //
"}\r\n" + //
"#else\r\n" + //
"attribute vec4 a_bones;\r\n" + //
"#ifdef EXTENDED_BONES\r\n" + //
"attribute vec4 a_extendedBones;\r\n" + //
"#endif\r\n" + //
"attribute float a_boneNumber;\r\n" + //
"mat4 getVertexGroupMatrix() {\r\n" + //
" mat4 bone;\r\n" + //
" // For the broken models out there, since the game supports this.\r\n" + //
" if (a_boneNumber > 0.0) {\r\n" + //
" for (int i = 0; i < 4; i++) {\r\n" + //
" if (a_bones[i] > 0.0) {\r\n" + //
" bone += fetchMatrix(a_bones[i] - 1.0, 0.0);\r\n" + //
" }\r\n" + //
" }\r\n" + //
" #ifdef EXTENDED_BONES\r\n" + //
" for (int i = 0; i < 4; i++) {\r\n" + //
" if (a_extendedBones[i] > 0.0) {\r\n" + //
" bone += fetchMatrix(a_extendedBones[i] - 1.0, 0.0);\r\n" + //
" }\r\n" + //
" }\r\n" + //
" #endif\r\n" + //
" }\r\n" + //
" return bone / a_boneNumber;\r\n" + //
"}\r\n" + //
"void transformVertexGroups(inout vec3 position, inout vec3 normal) {\r\n" + //
" mat4 bone = getVertexGroupMatrix();\r\n" + //
" mat3 rotation = mat3(bone);\r\n" + //
" position = vec3(bone * vec4(position, 1.0));\r\n" + //
" normal = normalize(rotation * normal);\r\n" + //
"}\r\n" + //
"void transformVertexGroupsHD(inout vec3 position, inout vec3 normal, inout vec3 tangent, inout vec3 binormal) {\r\n"
+ //
" mat4 bone = getVertexGroupMatrix();\r\n" + //
" mat3 rotation = mat3(bone);\r\n" + //
" position = vec3(bone * vec4(position, 1.0));\r\n" + //
" normal = normalize(rotation * normal);\r\n" + //
" tangent = normalize(rotation * tangent);\r\n" + //
" binormal = normalize(rotation * binormal);\r\n" + //
"}\r\n" + //
"#endif";
public static final String decodeFloat = "\r\n" + //
" vec2 decodeFloat2(float f) {\r\n" + //

View File

@ -4,13 +4,26 @@ public class Batch implements GenericIndexed {
public int index;
public Geoset geoset;
public Layer layer;
public boolean isExtended;
public Material material;
public final SkinningType skinningType;
public final boolean hd;
public Batch(final int index, final Geoset geoset, final Layer layer, final boolean isExtended) {
public Batch(final int index, final Geoset geoset, final Layer layer, final SkinningType skinningType) {
this.index = index;
this.geoset = geoset;
this.layer = layer;
this.isExtended = isExtended;
this.material = null;
this.skinningType = skinningType;
this.hd = false;
}
public Batch(final int index, final Geoset geoset, final Material material, final SkinningType skinningType) {
this.index = index;
this.geoset = geoset;
this.material = material;
this.layer = material.layers.get(0);
this.skinningType = skinningType;
this.hd = true;
}
@Override

View File

@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Matrix4;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.Camera;
import com.etheller.warsmash.viewer5.ModelViewer;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.Texture;
@ -15,18 +16,22 @@ import com.etheller.warsmash.viewer5.handlers.w3x.DynamicShadowManager;
import com.etheller.warsmash.viewer5.handlers.w3x.W3xSceneLightManager;
public class BatchGroup extends GenericGroup {
private static float[] tempFloat3Array = new float[3];
private final MdxModel model;
public final boolean isExtended;
public final SkinningType skinningType;
public final boolean hd;
public BatchGroup(final MdxModel model, final boolean isExtended) {
public BatchGroup(final MdxModel model, final SkinningType skinningType, final boolean hd) {
this.model = model;
this.isExtended = isExtended;
this.skinningType = skinningType;
this.hd = hd;
}
@Override
public void render(final MdxComplexInstance instance, final Matrix4 mvp) {
final Scene scene = instance.scene;
final Camera camera = scene.camera;
final MdxModel model = this.model;
final List<Texture> textures = model.getTextures();
final MdxHandler handler = model.handler;
@ -35,11 +40,15 @@ public class BatchGroup extends GenericGroup {
final ModelViewer viewer = model.viewer;
final GL20 gl = viewer.gl;
final WebGL webGL = viewer.webGL;
final boolean isExtended = this.isExtended;
final SkinningType skinningType = this.skinningType;
final boolean hd = this.hd;
final ShaderProgram shader;
final W3xSceneLightManager lightManager = (W3xSceneLightManager) scene.getLightManager();
if (isExtended) {
if (hd) {
shader = handler.shaders.hd;
}
else if (skinningType == SkinningType.ExtendedVertexGroups) {
if (DynamicShadowManager.IS_SHADOW_MAPPING) {
shader = handler.shaders.extendedShadowMap;
}
@ -58,7 +67,7 @@ public class BatchGroup extends GenericGroup {
webGL.useShaderProgram(shader);
shader.setUniformMatrix("u_mvp", mvp);
shader.setUniformMatrix(hd ? "u_VP" : "u_mvp", mvp);
final DataTexture boneTexture = instance.boneTexture;
final DataTexture unitLightsTexture = lightManager.getUnitLightsTexture();
@ -81,79 +90,185 @@ public class BatchGroup extends GenericGroup {
shader.setUniformf("u_hasBones", 0);
}
shader.setUniformi("u_texture", 0);
gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, model.arrayBuffer);
gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, model.elementBuffer);
shader.setUniform4fv("u_vertexColor", instance.vertexColor, 0, instance.vertexColor.length);
if (hd) {
shader.setUniformi("u_diffuseMap", 0);
shader.setUniformi("u_normalsMap", 1);
shader.setUniformi("u_ormMap", 2);
shader.setUniformi("u_emissiveMap", 3);
shader.setUniformi("u_teamColorMap", 4);
shader.setUniformi("u_environmentMap", 5);
for (final int index : this.objects) {
final Batch batch = batches.get(index);
final Geoset geoset = batch.geoset;
final Layer layer = batch.layer;
final int geosetIndex = geoset.index;
final int layerIndex = layer.index;
final float[] geosetColor = instance.geosetColors[geosetIndex];
final float layerAlpha = instance.layerAlphas[layerIndex];
gl.glEnable(GL20.GL_BLEND);
gl.glEnable(GL20.GL_DEPTH_TEST);
gl.glDepthMask(true);
if ((geosetColor[3] > 0.01) && (layerAlpha > 0.01)) {
// BELOW: I updated it to "Math.max(0," because MDL and MDX parser for PRSCMOD
// menu screen behaved differently,
// the MDL case was getting "no data" for default value when unanimated, and "no
// data" resolved to -1,
// whereas MDX binary contained an "unused" 0 value.
final int layerTexture = Math.max(0, instance.layerTextures[layerIndex]);
final float[] uvAnim = instance.uvAnims[layerIndex];
shader.setUniformMatrix("u_MV", camera.viewMatrix);
shader.setUniform4fv("u_geosetColor", geosetColor, 0, geosetColor.length);
tempFloat3Array[0] = camera.location.x;
tempFloat3Array[1] = camera.location.y;
tempFloat3Array[2] = camera.location.z;
shader.setUniform3fv("u_eyePos", tempFloat3Array, 0, 3);
shader.setUniformf("u_layerAlpha", layerAlpha);
shader.setUniformf("u_unshaded", layer.unshaded);
for (final int index : this.objects) {
final Batch batch = batches.get(index);
final Geoset geoset = batch.geoset;
final Material material = batch.material;
final Layer diffuseLayer = material.layers.get(0);
final Layer normalsLayer = material.layers.get(1);
final Layer ormLayer = material.layers.get(2);
final Layer emissiveLayer = material.layers.get(3);
final Layer teamColorLayer = material.layers.get(4);
final Layer environmentMapLayer = material.layers.get(5);
final float layerAlpha = instance.layerAlphas[diffuseLayer.index];
shader.setUniform2fv("u_uvTrans", uvAnim, 0, 2);
shader.setUniform2fv("u_uvRot", uvAnim, 2, 2);
shader.setUniform1fv("u_uvScale", uvAnim, 4, 1);
if (layerAlpha > 0) {
shader.setUniformf("u_layerAlpha", layerAlpha);
shader.setUniformf("u_filterMode", diffuseLayer.filterMode);
if (instance.additiveOverrideMeshMode) {
layer.bindBlended(shader);
gl.glBlendFunc(FilterMode.ADDITIVE_ALPHA[0], FilterMode.ADDITIVE_ALPHA[1]);
}
else if (instance.vertexColor[3] < 1.0f) {
layer.bindBlended(shader);
}
else {
layer.bind(shader);
}
final int diffuseId = Math.max(0, instance.layerTextures[diffuseLayer.index]);
final int normalsId = Math.max(0, instance.layerTextures[normalsLayer.index]);
final int ormId = Math.max(0, instance.layerTextures[ormLayer.index]);
final int emissiveId = Math.max(0, instance.layerTextures[emissiveLayer.index]);
final int teamColorId = Math.max(0, instance.layerTextures[teamColorLayer.index]);
final int environmentMapId = Math.max(0, instance.layerTextures[environmentMapLayer.index]);
final Integer replaceable = replaceables.get(layerTexture); // TODO is this OK?
Texture texture;
final Texture diffuseTexture;
final Texture normalsTexture;
final Texture ormTexture;
final Texture emissiveTexture = textures.get(emissiveId);
final Texture teamColorTexture;
final Texture environmentMapTexture = textures.get(environmentMapId);
if ((replaceable > 0) && (replaceable < WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT)
&& (instance.replaceableTextures[replaceable] != null)) {
texture = instance.replaceableTextures[replaceable];
}
else {
texture = textures.get(layerTexture);
Texture textureLookup = instance.textureMapper.get(texture);
if (textureLookup == null) {
textureLookup = texture;
{
final Integer replaceable = replaceables.get(diffuseId);
if ((replaceable > 0) && (replaceable < WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT)
&& (instance.replaceableTextures_diffuse[replaceable] != null)) {
diffuseTexture = instance.replaceableTextures_diffuse[replaceable];
}
else {
diffuseTexture = textures.get(diffuseId);
}
}
texture = textureLookup;
}
viewer.webGL.bindTexture(texture, 0);
{
final Integer replaceable = replaceables.get(normalsId);
if ((replaceable > 0) && (replaceable < WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT)
&& (instance.replaceableTextures_normal[replaceable] != null)) {
normalsTexture = instance.replaceableTextures_normal[replaceable];
}
else {
normalsTexture = textures.get(normalsId);
}
}
if (isExtended) {
geoset.bindExtended(shader, layer.coordId);
}
else {
geoset.bind(shader, layer.coordId);
}
{
final Integer replaceable = replaceables.get(ormId);
if ((replaceable > 0) && (replaceable < WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT)
&& (instance.replaceableTextures_orm[replaceable] != null)) {
ormTexture = instance.replaceableTextures_orm[replaceable];
}
else {
ormTexture = textures.get(ormId);
}
}
geoset.render();
final Integer replaceable = replaceables.get(teamColorId);
if ((replaceable > 0) && (replaceable < WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT)
&& (instance.replaceableTextures[replaceable] != null)) {
teamColorTexture = instance.replaceableTextures[replaceable];
}
else {
teamColorTexture = textures.get(teamColorId);
}
webGL.bindTexture(diffuseTexture, 0);
webGL.bindTexture(normalsTexture, 1);
webGL.bindTexture(ormTexture, 2);
webGL.bindTexture(emissiveTexture, 3);
webGL.bindTexture(teamColorTexture, 4);
webGL.bindTexture(environmentMapTexture, 5);
geoset.bindHd(shader, batch.skinningType, diffuseLayer.coordId);
geoset.render();
}
}
}
else {
shader.setUniformi("u_texture", 0);
shader.setUniform4fv("u_vertexColor", instance.vertexColor, 0, instance.vertexColor.length);
for (final int index : this.objects) {
final Batch batch = batches.get(index);
final Geoset geoset = batch.geoset;
final Layer layer = batch.layer;
final int geosetIndex = geoset.index;
final int layerIndex = layer.index;
final float[] geosetColor = instance.geosetColors[geosetIndex];
final float layerAlpha = instance.layerAlphas[layerIndex];
if ((geosetColor[3] > 0.01) && (layerAlpha > 0.01)) {
// BELOW: I updated it to "Math.max(0," because MDL and MDX parser for PRSCMOD
// menu screen behaved differently,
// the MDL case was getting "no data" for default value when unanimated, and "no
// data" resolved to -1,
// whereas MDX binary contained an "unused" 0 value.
final int layerTexture = Math.max(0, instance.layerTextures[layerIndex]);
final float[] uvAnim = instance.uvAnims[layerIndex];
shader.setUniform4fv("u_geosetColor", geosetColor, 0, geosetColor.length);
shader.setUniformf("u_layerAlpha", layerAlpha);
shader.setUniformf("u_unshaded", layer.unshaded);
shader.setUniform2fv("u_uvTrans", uvAnim, 0, 2);
shader.setUniform2fv("u_uvRot", uvAnim, 2, 2);
shader.setUniform1fv("u_uvScale", uvAnim, 4, 1);
if (instance.additiveOverrideMeshMode) {
layer.bindBlended(shader);
gl.glBlendFunc(FilterMode.ADDITIVE_ALPHA[0], FilterMode.ADDITIVE_ALPHA[1]);
}
else if (instance.vertexColor[3] < 1.0f) {
layer.bindBlended(shader);
}
else {
layer.bind(shader);
}
final Integer replaceable = replaceables.get(layerTexture); // TODO is this OK?
Texture texture;
if ((replaceable > 0) && (replaceable < WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT)
&& (instance.replaceableTextures[replaceable] != null)) {
texture = instance.replaceableTextures[replaceable];
}
else {
texture = textures.get(layerTexture);
Texture textureLookup = instance.textureMapper.get(texture);
if (textureLookup == null) {
textureLookup = texture;
}
texture = textureLookup;
}
viewer.webGL.bindTexture(texture, 0);
if (skinningType == SkinningType.ExtendedVertexGroups) {
geoset.bindExtended(shader, layer.coordId);
}
else {
geoset.bind(shader, layer.coordId);
}
geoset.render();
}
}
}
}
}

View File

@ -13,6 +13,7 @@ public class Geoset {
public int positionOffset;
public int normalOffset;
public int uvOffset;
public final int tangentOffset;
public int skinOffset;
public int faceOffset;
public int vertices;
@ -29,14 +30,15 @@ public class Geoset {
public final MdlxGeoset mdlxGeoset;
public Geoset(final MdxModel model, final int index, final int positionOffset, final int normalOffset,
final int uvOffset, final int skinOffset, final int faceOffset, final int vertices, final int elements,
final int openGLSkinType, final int skinStride, final int boneCountOffsetBytes, final boolean unselectable,
final MdlxGeoset mdlxGeoset) {
final int uvOffset, final int tangentOffset, final int skinOffset, final int faceOffset, final int vertices,
final int elements, final int openGLSkinType, final int skinStride, final int boneCountOffsetBytes,
final boolean unselectable, final MdlxGeoset mdlxGeoset) {
this.model = model;
this.index = index;
this.positionOffset = positionOffset;
this.normalOffset = normalOffset;
this.uvOffset = uvOffset;
this.tangentOffset = tangentOffset;
this.skinOffset = skinOffset;
this.faceOffset = faceOffset;
this.vertices = vertices;
@ -143,12 +145,16 @@ public class Geoset {
this.faceOffset, instances);
}
public void bindHd(final ShaderProgram shader, final int coordId) {
public void bindHd(final ShaderProgram shader, final SkinningType skinningType, final int coordId) {
shader.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, this.positionOffset);
shader.setVertexAttribute("a_normal", 3, GL20.GL_FLOAT, false, 0, this.positionOffset);
shader.setVertexAttribute("a_normal", 3, GL20.GL_FLOAT, false, 0, this.normalOffset);
shader.setVertexAttribute("a_uv", 2, GL20.GL_FLOAT, false, 0, this.uvOffset + (coordId * this.vertices * 8));
shader.setVertexAttribute("a_tangent", 4, GL20.GL_FLOAT, false, 0, this.tangentOffset);
// TODO ghostwolf splits here and allows HD with non-skin, or SD with skin
shader.setVertexAttribute("a_bones", 4, GL20.GL_UNSIGNED_BYTE, false, 8, this.skinOffset);
shader.setVertexAttribute("a_weights", 4, GL20.GL_UNSIGNED_BYTE, false, 8, this.skinOffset + 4);
shader.setVertexAttribute("a_weights", 4, GL20.GL_UNSIGNED_BYTE, true, 8, this.skinOffset + 4);
}
private static final class Variants {

View File

@ -70,6 +70,9 @@ public class MdxComplexInstance extends ModelInstance {
public FloatBuffer worldMatricesCopyHeap;
public DataTexture boneTexture;
public Texture[] replaceableTextures = new Texture[WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT];
public Texture[] replaceableTextures_diffuse = new Texture[WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT];
public Texture[] replaceableTextures_normal = new Texture[WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT];
public Texture[] replaceableTextures_orm = new Texture[WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT];
private float animationSpeed = 1.0f;
private float blendTime;
private float blendTimeRemaining;
@ -681,6 +684,16 @@ public class MdxComplexInstance extends ModelInstance {
PathSolver.DEFAULT, null);
}
@Override
public void setReplaceableTextureHD(final int replaceableTextureId, final String replaceableTextureFile) {
this.replaceableTextures_diffuse[replaceableTextureId] = (Texture) this.model.viewer
.load(replaceableTextureFile + "_diffuse.dds", PathSolver.DEFAULT, null);
this.replaceableTextures_normal[replaceableTextureId] = (Texture) this.model.viewer
.load(replaceableTextureFile + "_normal.dds", PathSolver.DEFAULT, null);
this.replaceableTextures_orm[replaceableTextureId] = (Texture) this.model.viewer
.load(replaceableTextureFile + "_orm.dds", PathSolver.DEFAULT, null);
}
/**
* Set the vertex color of this instance.
*/

View File

@ -44,7 +44,7 @@ public class MdxHandler extends ModelHandler {
this.shaders.particles = viewer.webGL.createShaderProgram(MdxShaders.vsParticles(), MdxShaders.fsParticles);
// Shaders.simple = viewer.webGL.createShaderProgram(MdxShaders.vsSimple,
// MdxShaders.fsSimple);
// Shaders.hd = viewer.webGL.createShaderProgram(MdxShaders.vsHd, MdxShaders.fsHd);
this.shaders.hd = viewer.webGL.createShaderProgram(MdxShaders.vsHd, MdxShaders.fsHd());
// TODO HD reforged
// If a shader failed to compile, don't allow the handler to be registered, and

View File

@ -144,9 +144,9 @@ public class MdxModel extends com.etheller.warsmash.viewer5.Model<MdxHandler> {
this.layers.add(vLayer);
}
this.materials.add(new Material(this, "" /* material.shader */, layers));
this.materials.add(new Material(this, material.shader, layers));
if (false /* !"".equals(material.shader) */) {
if (!"".equals(material.shader)) {
this.hd = true;
}
}

View File

@ -1,59 +1,353 @@
package com.etheller.warsmash.viewer5.handlers.mdx;
import com.etheller.warsmash.viewer5.Shaders;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler.ShaderEnvironmentType;
public class MdxShaders {
public static final String vsHd = Shaders.boneTexture + "\r\n" + //
" uniform mat4 u_mvp;\r\n" + //
public static final String vsHd = "#version 120\r\n" + Shaders.boneTexture + "\r\n" + //
" uniform mat4 u_VP;\r\n" + //
" uniform mat4 u_MV;\r\n" + //
" uniform vec3 u_eyePos;\r\n" + //
" uniform sampler2D u_lightTexture;\r\n" + //
" uniform float u_lightTextureHeight;\r\n" + //
" uniform float u_layerAlpha;\r\n" + //
" uniform bool u_hasBones;\r\n" + //
" " + //
" attribute vec3 a_position;\r\n" + //
" attribute vec3 a_normal;\r\n" + //
" attribute vec2 a_uv;\r\n" + //
" attribute vec4 a_bones;\r\n" + //
" attribute vec4 a_weights;\r\n" + //
" varying vec3 v_normal;\r\n" + //
" attribute vec4 a_tangent;\r\n" + //
// TODO ONLY_TANGENTS
" \r\n" + //
" \r\n" + //
"#define SKIN\r\n" + // TODO make this conditional
Shaders.transforms + //
" \r\n" + //
" \r\n" + //
"vec3 TBN(vec3 vector, vec3 tangent, vec3 binormal, vec3 normal) {\r\n" + //
" return vec3(dot(vector, tangent), dot(vector, binormal), dot(vector, normal));\r\n" + //
"}\r\n" + //
" \r\n" + //
" \r\n" + //
" varying vec2 v_uv;\r\n" + //
" varying float v_layerAlpha;\r\n" + //
" void transform(inout vec3 position, inout vec3 normal) {\r\n" + //
" mat4 bone;\r\n" + //
" bone += fetchMatrix(a_bones[0], 0.0) * a_weights[0];\r\n" + //
" bone += fetchMatrix(a_bones[1], 0.0) * a_weights[1];\r\n" + //
" bone += fetchMatrix(a_bones[2], 0.0) * a_weights[2];\r\n" + //
" bone += fetchMatrix(a_bones[3], 0.0) * a_weights[3];\r\n" + //
" position = vec3(bone * vec4(position, 1.0));\r\n" + //
" normal = mat3(bone) * normal;\r\n" + //
" }\r\n" + //
" varying vec3 v_lightDir;\r\n" + //
" varying vec3 v_eyeVec;\r\n" + //
" varying vec3 v_normal;\r\n" + //
" \r\n" + //
" \r\n" + //
" void main() {\r\n" + //
" vec3 position = a_position;\r\n" + //
" vec3 normal = a_normal;\r\n" + //
" transform(position, normal);\r\n" + //
" v_normal = normal;\r\n" + //
" vec3 tangent = a_tangent.xyz;\r\n" + //
" \r\n" + //
// Re-orthogonalize the tangent in case it wasnt normalized.
// See "One last thing" at
// https://learnopengl.com/Advanced-Lighting/Normal-Mapping
" \r\n" + //
" tangent = normalize(tangent - dot(tangent, normal) * normal);\r\n" + //
" \r\n" + //
" vec3 binormal = cross(normal, tangent) * a_tangent.w;\r\n" + //
" \r\n" + //
" if (u_hasBones) {\r\n" + //
" #ifdef SKIN\r\n" + //
" transformSkin(position, normal, tangent, binormal);\r\n" + //
" #else\r\n" + //
" transformVertexGroupsHD(position, normal, tangent, binormal);\r\n" + //
" #endif\r\n" + //
" }\r\n" + //
" \r\n" + //
" vec3 position_mv = vec3(u_MV * vec4(position, 1));\r\n" + //
" \r\n" + //
" mat3 mv = mat3(u_MV);\r\n" + //
" vec3 t = normalize(mv * tangent);\r\n" + //
" vec3 b = normalize(mv * binormal);\r\n" + //
" vec3 n = normalize(mv * normal);\r\n" + //
" \r\n" + //
" v_eyeVec = normalize(u_eyePos - position_mv);\r\n" + //
" \r\n" + //
// TODO fix giant hack on lighting
" float rowPos = (0.5) / u_lightTextureHeight;\r\n" + //
" vec4 lightPosition = texture2D(u_lightTexture, vec2(0.125, rowPos));\r\n" + //
" vec3 u_lightPos = lightPosition.xyz;\r\n" + //
" vec3 lightDir = normalize(u_lightPos - position_mv);\r\n" + //
" v_lightDir = normalize(TBN(lightDir, t, b, n));\r\n" + //
" \r\n" + //
" v_uv = a_uv;\r\n" + //
" v_layerAlpha = u_layerAlpha;\r\n" + //
" gl_Position = u_mvp * vec4(position, 1.0);\r\n" + //
" \r\n" + //
" v_normal = normal;\r\n" + //
" // v_lightDirWorld = normalize(lightDir);\r\n" + //
" \r\n" + //
// TODO ONLY_TANGENTS
" gl_Position = u_VP * vec4(position, 1.0);\r\n" + //
" }";
public static final String fsHd = "\r\n" + //
" uniform sampler2D u_diffuseMap;\r\n" + //
" uniform sampler2D u_ormMap;\r\n" + //
" uniform sampler2D u_teamColorMap;\r\n" + //
" uniform float u_filterMode;\r\n" + //
" varying vec3 v_normal;\r\n" + //
" varying vec2 v_uv;\r\n" + //
" varying float v_layerAlpha;\r\n" + //
" void main() {\r\n" + //
" vec4 texel = texture2D(u_diffuseMap, v_uv);\r\n" + //
" vec4 color = vec4(texel.rgb, texel.a * v_layerAlpha);\r\n" + //
" vec4 orma = texture2D(u_ormMap, v_uv);\r\n" + //
" if (orma.a > 0.1) {\r\n" + //
" color *= texture2D(u_teamColorMap, v_uv) * orma.a;\r\n" + //
" }\r\n" + //
" // 1bit Alpha\r\n" + //
" if (u_filterMode == 1.0 && color.a < 0.75) {\r\n" + //
" discard;\r\n" + //
" }\r\n" + //
" gl_FragColor = color;\r\n" + //
" }";
public static final String fsHd() {
return "#version 120\r\n" + //
"\r\n" + //
"\r\n" + //
"\r\n" + //
"uniform sampler2D u_diffuseMap;\r\n" + //
"uniform sampler2D u_normalsMap;\r\n" + //
"uniform sampler2D u_ormMap;\r\n" + //
"uniform sampler2D u_emissiveMap;\r\n" + //
"uniform sampler2D u_teamColorMap;\r\n" + //
"uniform sampler2D u_environmentMap;\r\n" + //
"uniform float u_filterMode;\r\n" + //
"// uniform sampler2D u_lutMap;\r\n" + //
"// uniform sampler2D u_envDiffuseMap;\r\n" + //
"// uniform sampler2D u_envSpecularMap;\r\n" + //
"varying vec2 v_uv;\r\n" + //
"varying float v_layerAlpha;\r\n" + //
"varying vec3 v_lightDir;\r\n" + //
"varying vec3 v_eyeVec;\r\n" + //
"varying vec3 v_normal;\r\n" + //
"// varying vec3 v_lightDirWorld;\r\n" + //
"#if defined(ONLY_TANGENTS)\r\n" + //
"varying vec3 v_tangent;\r\n" + //
"#endif\r\n" + //
"vec3 decodeNormal() {\r\n" + //
" vec2 xy = texture2D(u_normalsMap, v_uv).xy * 2.0 - 1.0;\r\n" + //
" \r\n" + //
" return vec3(xy, sqrt(1.0 - dot(xy, xy)));\r\n" + //
"}\r\n" + //
"const vec2 invAtan = vec2(0.1591, 0.3183);\r\n" + //
"vec2 sampleEnvironmentMap(vec3 normal) {\r\n" + //
" vec2 uv = vec2(atan(normal.x, normal.y), -asin(normal.z));\r\n" + //
" uv *= invAtan;\r\n" + //
" uv += 0.5;\r\n" + //
" return uv;\r\n" + //
"}\r\n" + //
"vec4 getDiffuseColor() {\r\n" + //
" vec4 color = texture2D(u_diffuseMap, v_uv);\r\n" + //
" // 1bit Alpha\r\n" + //
" if (u_filterMode == 1.0 && color.a < 0.75) {\r\n" + //
" discard;\r\n" + //
" }\r\n" + //
" return color;\r\n" + //
"}\r\n" + //
"vec4 getOrmColor() {\r\n" + //
" return texture2D(u_ormMap, v_uv);\r\n" + //
"}\r\n" + //
"vec3 getEmissiveColor() {\r\n" + //
" return texture2D(u_emissiveMap, v_uv).rgb;\r\n" + //
"}\r\n" + //
"vec3 getTeamColor() {\r\n" + //
" return texture2D(u_teamColorMap, v_uv).rgb;\r\n" + //
"}\r\n" + //
"// const float PI = 3.14159265359;\r\n" + //
"// const float RECIPROCAL_PI = 0.31830988618;\r\n" + //
"// const float RECIPROCAL_PI2 = 0.15915494;\r\n" + //
"// const float LN2 = 0.6931472;\r\n" + //
"// const float ENV_LODS = 6.0;\r\n" + //
"// vec4 SRGBtoLinear(vec4 srgb) {\r\n" + //
"// vec3 linOut = pow(srgb.xyz, vec3(2.2));\r\n" + //
"// return vec4(linOut, srgb.w);;\r\n" + //
"// }\r\n" + //
"// vec4 RGBMToLinear(in vec4 value) {\r\n" + //
"// float maxRange = 6.0;\r\n" + //
"// return vec4(value.xyz * value.w * maxRange, 1.0);\r\n" + //
"// }\r\n" + //
"// vec3 linearToSRGB(vec3 color) {\r\n" + //
"// return pow(color, vec3(1.0 / 2.2));\r\n" + //
"// }\r\n" + //
"// // vec3 getNormal() {\r\n" + //
"// // vec3 pos_dx = dFdx(vMPos.xyz);\r\n" + //
"// // vec3 pos_dy = dFdy(vMPos.xyz);\r\n" + //
"// // vec2 tex_dx = dFdx(vUv);\r\n" + //
"// // vec2 tex_dy = dFdy(vUv);\r\n" + //
"// // vec3 t = normalize(pos_dx * tex_dy.t - pos_dy * tex_dx.t);\r\n" + //
"// // vec3 b = normalize(-pos_dx * tex_dy.s + pos_dy * tex_dx.s);\r\n" + //
"// // mat3 tbn = mat3(t, b, normalize(vNormal));\r\n" + //
"// // vec3 n = texture2D(tNormal, vUv * uNormalUVScale).rgb * 2.0 - 1.0;\r\n" + //
"// // n.xy *= uNormalScale;\r\n" + //
"// // vec3 normal = normalize(tbn * n);\r\n" + //
"// // // Get world normal from view normal (normalMatrix * normal)\r\n" + //
"// // return normalize((vec4(normal, 0.0) * viewMatrix).xyz);\r\n" + //
"// // }\r\n" + //
"// vec3 specularReflection(vec3 specularEnvR0, vec3 specularEnvR90, float VdH) {\r\n" + //
"// return specularEnvR0 + (specularEnvR90 - specularEnvR0) * pow(clamp(1.0 - VdH, 0.0, 1.0), 5.0);\r\n"
+ //
"// }\r\n" + //
"// float geometricOcclusion(float NdL, float NdV, float roughness) {\r\n" + //
"// float r = roughness;\r\n" + //
"// float attenuationL = 2.0 * NdL / (NdL + sqrt(r * r + (1.0 - r * r) * (NdL * NdL)));\r\n" + //
"// float attenuationV = 2.0 * NdV / (NdV + sqrt(r * r + (1.0 - r * r) * (NdV * NdV)));\r\n" + //
"// return attenuationL * attenuationV;\r\n" + //
"// }\r\n" + //
"// float microfacetDistribution(float roughness, float NdH) {\r\n" + //
"// float roughnessSq = roughness * roughness;\r\n" + //
"// float f = (NdH * roughnessSq - NdH) * NdH + 1.0;\r\n" + //
"// return roughnessSq / (PI * f * f);\r\n" + //
"// }\r\n" + //
"// vec2 cartesianToPolar(vec3 n) {\r\n" + //
"// vec2 uv;\r\n" + //
"// uv.x = atan(n.z, n.x) * RECIPROCAL_PI2 + 0.5;\r\n" + //
"// uv.y = asin(n.y) * RECIPROCAL_PI + 0.5;\r\n" + //
"// return uv;\r\n" + //
"// }\r\n" + //
"// void getIBLContribution(inout vec3 diffuse, inout vec3 specular, float NdV, float roughness, vec3 n, vec3 reflection, vec3 diffuseColor, vec3 specularColor) {\r\n"
+ //
"// vec3 brdf = SRGBtoLinear(texture2D(u_lutMap, vec2(NdV, roughness))).rgb;\r\n" + //
"// vec3 diffuseLight = RGBMToLinear(texture2D(u_envDiffuseMap, sampleEnvironmentMap(n))).rgb;\r\n" + //
"// // Sample 2 levels and mix between to get smoother degradation\r\n" + //
"// float blend = roughness * ENV_LODS;\r\n" + //
"// float level0 = floor(blend);\r\n" + //
"// float level1 = min(ENV_LODS, level0 + 1.0);\r\n" + //
"// blend -= level0;\r\n" + //
" \r\n" + //
"// // Sample the specular env map atlas depending on the roughness value\r\n" + //
"// vec2 uvSpec = sampleEnvironmentMap(reflection);\r\n" + //
"// uvSpec.y /= 2.0;\r\n" + //
"// vec2 uv0 = uvSpec;\r\n" + //
"// vec2 uv1 = uvSpec;\r\n" + //
"// uv0 /= pow(2.0, level0);\r\n" + //
"// uv0.y += 1.0 - exp(-LN2 * level0);\r\n" + //
"// uv1 /= pow(2.0, level1);\r\n" + //
"// uv1.y += 1.0 - exp(-LN2 * level1);\r\n" + //
"// vec3 specular0 = RGBMToLinear(texture2D(u_envSpecularMap, uv0)).rgb;\r\n" + //
"// vec3 specular1 = RGBMToLinear(texture2D(u_envSpecularMap, uv1)).rgb;\r\n" + //
"// vec3 specularLight = mix(specular0, specular1, blend);\r\n" + //
"// diffuse = diffuseLight * diffuseColor;\r\n" + //
" \r\n" + //
"// // Bit of extra reflection for smooth materials\r\n" + //
"// float reflectivity = pow((1.0 - roughness), 2.0) * 0.05;\r\n" + //
"// specular = specularLight * (specularColor * brdf.x + brdf.y + reflectivity);\r\n" + //
"// // specular *= uEnvSpecular;\r\n" + //
"// }\r\n" + //
"// void PBR() {\r\n" + //
"// vec4 baseDiffuseColor = getDiffuseColor();\r\n" + //
"// vec3 baseColor = baseDiffuseColor.rgb;\r\n" + //
"// vec4 orm = getOrmColor();\r\n" + //
"// vec3 tc = getTeamColor();\r\n" + //
"// float tcFactor = getOrmColor().a;\r\n" + //
"// if (tcFactor > 0.1) {\r\n" + //
"// baseColor *= tc * tcFactor;\r\n" + //
"// }\r\n" + //
"// float roughness = clamp(orm.g, 0.04, 1.0);\r\n" + //
"// float metallic = clamp(orm.b, 0.04, 1.0);\r\n" + //
"// vec3 f0 = vec3(0.04);\r\n" + //
"// vec3 diffuseColor = baseColor * (vec3(1.0) - f0) * (1.0 - metallic);\r\n" + //
"// vec3 specularColor = mix(f0, baseColor, metallic);\r\n" + //
"// vec3 specularEnvR0 = specularColor;\r\n" + //
"// vec3 specularEnvR90 = vec3(clamp(max(max(specularColor.r, specularColor.g), specularColor.b) * 25.0, 0.0, 1.0));\r\n"
+ //
"// vec3 N = v_normal;\r\n" + //
"// vec3 V = normalize(v_eyeVec);\r\n" + //
"// vec3 L = normalize(v_lightDirWorld);\r\n" + //
"// vec3 H = normalize(L + V);\r\n" + //
"// vec3 reflection = normalize(reflect(-V, N));\r\n" + //
"// float NdL = clamp(dot(N, L), 0.001, 1.0);\r\n" + //
"// float NdV = clamp(abs(dot(N, V)), 0.001, 1.0);\r\n" + //
"// float NdH = clamp(dot(N, H), 0.0, 1.0);\r\n" + //
"// float LdH = clamp(dot(L, H), 0.0, 1.0);\r\n" + //
"// float VdH = clamp(dot(V, H), 0.0, 1.0);\r\n" + //
"// vec3 F = specularReflection(specularEnvR0, specularEnvR90, VdH);\r\n" + //
"// float G = geometricOcclusion(NdL, NdV, roughness);\r\n" + //
"// float D = microfacetDistribution(roughness, NdH);\r\n" + //
"// vec3 diffuseContrib = (1.0 - F) * (diffuseColor / PI);\r\n" + //
"// vec3 specContrib = F * G * D / (4.0 * NdL * NdV);\r\n" + //
" \r\n" + //
"// // Shading based off lights\r\n" + //
"// // vec3 color = NdL * uLightColor * (diffuseContrib + specContrib);\r\n" + //
"// vec3 color = NdL * (diffuseContrib + specContrib);\r\n" + //
"// // Calculate IBL lighting\r\n" + //
"// vec3 diffuseIBL;\r\n" + //
"// vec3 specularIBL;\r\n" + //
"// getIBLContribution(diffuseIBL, specularIBL, NdV, roughness, N, reflection, diffuseColor, specularColor);\r\n"
+ //
"// // Add IBL on top of color\r\n" + //
"// color += specularIBL;\r\n" + //
"// color *= orm.r;\r\n" + //
"// color += getEmissiveColor();\r\n" + //
"// // Convert to sRGB to display\r\n" + //
"// gl_FragColor.rgb = color;\r\n" + //
"// gl_FragColor.a = baseDiffuseColor.a;\r\n" + //
"// }\r\n" + //
"void onlyDiffuse() {\r\n" + //
" vec4 baseColor = getDiffuseColor();\r\n" + //
" vec3 tc = getTeamColor();\r\n" + //
" float tcFactor = getOrmColor().a;\r\n" + //
" if (tcFactor > 0.1) {\r\n" + //
" baseColor.rgb *= tc * tcFactor;\r\n" + //
" }\r\n" + //
" gl_FragColor = baseColor;\r\n" + //
"}\r\n" + //
"void onlyNormalMap() {\r\n" + //
" gl_FragColor = vec4(decodeNormal(), 1.0);\r\n" + //
"}\r\n" + //
"void onlyOcclusion() {\r\n" + //
" gl_FragColor = vec4(getOrmColor().rrr, 1.0);\r\n" + //
"}\r\n" + //
"void onlyRoughness() {\r\n" + //
" gl_FragColor = vec4(getOrmColor().ggg, 1.0);\r\n" + //
"}\r\n" + //
"void onlyMetallic() {\r\n" + //
" gl_FragColor = vec4(getOrmColor().bbb, 1.0);\r\n" + //
"}\r\n" + //
"void onlyTeamColorFactor() {\r\n" + //
" gl_FragColor = vec4(getOrmColor().aaa, 1.0);\r\n" + //
"}\r\n" + //
"void onlyEmissiveMap() {\r\n" + //
" gl_FragColor = vec4(getEmissiveColor(), 1.0);\r\n" + //
"}\r\n" + //
"void onlyTexCoords() {\r\n" + //
" gl_FragColor = vec4(v_uv, 0.0, 1.0);\r\n" + //
"}\r\n" + //
"void onlyNormals() {\r\n" + //
" gl_FragColor = vec4(v_normal, 1.0);\r\n" + //
"}\r\n" + //
"#if defined(ONLY_TANGENTS)\r\n" + //
"void onlyTangents() {\r\n" + //
" gl_FragColor = vec4(v_tangent, 1.0);\r\n" + //
"}\r\n" + //
"#endif\r\n" + //
"void lambert() {\r\n" + //
" vec4 baseColor = getDiffuseColor();\r\n" + //
" vec3 normal = decodeNormal();\r\n" + //
" vec4 orm = getOrmColor();\r\n" + //
" vec3 emissive = getEmissiveColor();\r\n" + //
" vec3 tc = getTeamColor();\r\n" + //
" float aoFactor = orm.r;\r\n" + //
" float tcFactor = orm.a;\r\n" + //
" float lambertFactor = clamp(dot(normal, v_lightDir), 0.0, 1.0);\r\n" + //
" vec3 color = baseColor.rgb;\r\n" + //
(MdxHandler.CURRENT_SHADER_TYPE != ShaderEnvironmentType.MENU ? " if (tcFactor > 0.1) {\r\n" + //
" color = color * (1.0 - tcFactor) + color * tc * tcFactor;\r\n" + //
" }\r\n" : "\r\n")
+ //
" \r\n" + //
" color *= clamp(lambertFactor * aoFactor + 0.1, 0.0, 1.0);\r\n" + //
" color += emissive;\r\n" + //
" gl_FragColor = vec4(color, baseColor.a);\r\n" + //
"}\r\n" + //
"void main() {\r\n" + //
" #if defined(ONLY_DIFFUSE)\r\n" + //
" onlyDiffuse();\r\n" + //
" #elif defined(ONLY_NORMAL_MAP)\r\n" + //
" onlyNormalMap();\r\n" + //
" #elif defined(ONLY_OCCLUSION)\r\n" + //
" onlyOcclusion();\r\n" + //
" #elif defined(ONLY_ROUGHNESS)\r\n" + //
" onlyRoughness();\r\n" + //
" #elif defined(ONLY_METALLIC)\r\n" + //
" onlyMetallic();\r\n" + //
" #elif defined(ONLY_TC_FACTOR)\r\n" + //
" onlyTeamColorFactor();\r\n" + //
" #elif defined(ONLY_EMISSIVE)\r\n" + //
" onlyEmissiveMap();\r\n" + //
" #elif defined(ONLY_TEXCOORDS)\r\n" + //
" onlyTexCoords();\r\n" + //
" #elif defined(ONLY_NORMALS)\r\n" + //
" onlyNormals();\r\n" + //
" #elif defined(ONLY_TANGENTS)\r\n" + //
" onlyTangents();\r\n" + //
" #else\r\n" + //
" lambert();\r\n" + //
" #endif\r\n" + //
"}";
}
public static final String vsSimple = "\r\n" + //
" uniform mat4 u_VP;\r\n" + //

View File

@ -55,4 +55,9 @@ public class MdxSimpleInstance extends BatchedInstance {
this.replaceableTextures[replaceableTextureId] = (Texture) this.model.viewer.load(replaceableTextureFile,
PathSolver.DEFAULT, null);
}
@Override
public void setReplaceableTextureHD(final int replaceableTextureId, final String replaceableTextureFile) {
throw new UnsupportedOperationException();
}
}

View File

@ -11,13 +11,14 @@ import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler.ShaderEnvironmentTy
import com.etheller.warsmash.viewer5.handlers.w3x.W3xScenePortraitLightManager;
public class MdxViewer extends AbstractMdxModelViewer {
public static ShaderEnvironmentType DEFAULT_SHADER_ENV = ShaderEnvironmentType.MENU;
private final WorldEditStrings worldEditStrings;
private final Vector3 defaultLighting;
public MdxViewer(final DataSource dataSource, final CanvasProvider canvas, final Vector3 defaultLighting) {
super(dataSource, canvas);
MdxHandler.CURRENT_SHADER_TYPE = ShaderEnvironmentType.MENU;
MdxHandler.CURRENT_SHADER_TYPE = DEFAULT_SHADER_ENV;
this.defaultLighting = defaultLighting;
this.worldEditStrings = new WorldEditStrings(this.dataSource);
}

View File

@ -9,9 +9,6 @@ import com.etheller.warsmash.util.RenderMathUtils;
import com.hiveworkshop.rms.parsers.mdlx.MdlxGeoset;
public class SetupGeosets {
private static final int NORMAL_BATCH = 0;
private static final int EXTENDED_BATCH = 1;
private static final int REFORGED_BATCH = 2;
public static void setupGeosets(final MdxModel model, final List<MdlxGeoset> geosets, final boolean bigNodeSpace) {
if (geosets.size() > 0) {
@ -19,9 +16,10 @@ public class SetupGeosets {
int positionBytes = 0;
int normalBytes = 0;
int uvBytes = 0;
int tangentBytes = 0;
int skinBytes = 0;
int faceBytes = 0;
final int[] batchTypes = new int[geosets.size()];
final SkinningType[] batchTypes = new SkinningType[geosets.size()];
final int extendedBatchStride = bigNodeSpace ? 36 : 9;
final int normalBatchStride = bigNodeSpace ? 20 : 5;
@ -32,17 +30,21 @@ public class SetupGeosets {
for (int i = 0, l = geosets.size(); i < l; i++) {
final MdlxGeoset geoset = geosets.get(i);
if (true /* geoset.getLod() == 0 */) {
if ((geoset.lod == 0) || (geoset.lod == -1)) {
final int vertices = geoset.getVertices().length / 3;
positionBytes += vertices * 12;
normalBytes += vertices * 12;
uvBytes += geoset.getUvSets().length * vertices * 8;
if (false /* geoset.skin.length */) {
if (geoset.tangents != null) {
tangentBytes += vertices * 16;
}
if (geoset.skin != null) {
skinBytes += vertices * 8;
batchTypes[i] = REFORGED_BATCH;
batchTypes[i] = SkinningType.Skin;
}
else {
long biggestGroup = 0;
@ -56,12 +58,12 @@ public class SetupGeosets {
if (biggestGroup > 4) {
skinBytes += vertices * extendedBatchStride;
batchTypes[i] = EXTENDED_BATCH;
batchTypes[i] = SkinningType.ExtendedVertexGroups;
}
else {
skinBytes += vertices * normalBatchStride;
batchTypes[i] = NORMAL_BATCH;
batchTypes[i] = SkinningType.VertexGroups;
}
}
@ -72,7 +74,8 @@ public class SetupGeosets {
int positionOffset = 0;
int normalOffset = positionOffset + positionBytes;
int uvOffset = normalOffset + normalBytes;
int skinOffset = uvOffset + uvBytes;
int tangentOffset = uvOffset + uvBytes;
int skinOffset = tangentOffset + tangentBytes;
int faceOffset = 0;
model.arrayBuffer = gl.glGenBuffer();
@ -86,11 +89,12 @@ public class SetupGeosets {
for (int i = 0, l = geosets.size(); i < l; i++) {
final MdlxGeoset geoset = geosets.get(i);
final int batchType = batchTypes[i];
if (true /* geoset.lod == 0 */) {
final SkinningType batchType = batchTypes[i];
if ((geoset.lod == 0) || (geoset.lod == -1)) {
final float[] positions = geoset.getVertices();
final float[] normals = geoset.getNormals();
final float[][] uvSets = geoset.getUvSets();
final float[] tangents = geoset.getTangents();
final int[] faces = geoset.getFaces();
int[] skin = null;
final int vertices = geoset.getVertices().length / 3;
@ -98,7 +102,7 @@ public class SetupGeosets {
int maxBones;
int skinStride;
int boneCountOffsetBytes;
if (batchType == EXTENDED_BATCH) {
if (batchType == SkinningType.ExtendedVertexGroups) {
maxBones = 8;
skinStride = extendedBatchStride;
boneCountOffsetBytes = extendedBatchBoneCountOffsetBytes;
@ -109,8 +113,11 @@ public class SetupGeosets {
boneCountOffsetBytes = normalBatchBoneCountOffsetBytes;
}
if (batchType == REFORGED_BATCH) {
// skin = geoset.skin; // THIS IS NOT IMPLEMENTED
if (batchType == SkinningType.Skin) {
skin = new int[geoset.skin.length];
for (int j = 0; j < geoset.skin.length; j++) {
skin[j] = geoset.skin[j];
}
}
else {
final long[] matrixIndices = geoset.getMatrixIndices();
@ -157,20 +164,20 @@ public class SetupGeosets {
final boolean unselectable = geoset.getSelectionFlags() == 4;
final Geoset vGeoset = new Geoset(model, model.getGeosets().size(), positionOffset, normalOffset,
uvOffset, skinOffset, faceOffset, vertices, faces.length, openGLSkinType, skinStride,
boneCountOffsetBytes, unselectable, geoset);
uvOffset, tangentOffset, skinOffset, faceOffset, vertices, faces.length, openGLSkinType,
skinStride, boneCountOffsetBytes, unselectable, geoset);
model.getGeosets().add(vGeoset);
if (batchType == REFORGED_BATCH) {
throw new UnsupportedOperationException("NYI");
// model.batches.add(new Reforged)
final Material material = model.materials.get((int) geoset.getMaterialId());
final boolean isHd = "Shader_HD_DefaultUnit".equals(material.shader);
if (isHd) {
model.batches.add(new Batch(model.batches.size(), vGeoset, material, batchType));
}
else {
final boolean isExtended = batchType == EXTENDED_BATCH;
for (final Layer layer : model.getMaterials().get((int) geoset.getMaterialId()).layers) {
model.batches.add(new Batch(model.batches.size(), vGeoset, layer, isExtended));
model.batches.add(new Batch(model.batches.size(), vGeoset, layer, batchType));
}
}
@ -190,6 +197,12 @@ public class SetupGeosets {
uvOffset += uvSet.length * 4;
}
if (tangents != null) {
gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, tangentOffset, tangents.length,
RenderMathUtils.wrap(tangents));
tangentOffset += tangents.length * 4;
}
// Skin.
gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, skinOffset, skin.length,
bigNodeSpace ? RenderMathUtils.wrap(skin) : RenderMathUtils.wrapAsBytes(skin));

View File

@ -64,7 +64,8 @@ public class SetupGroups {
public static boolean matchingGroup(final Object group, final Object object) {
if (group instanceof BatchGroup) {
return (object instanceof Batch) && (((Batch) object).isExtended == ((BatchGroup) group).isExtended);
return (object instanceof Batch) && (((Batch) object).skinningType == ((BatchGroup) group).skinningType)
&& (((Batch) object).hd == ((BatchGroup) group).hd);
// } else if(group instanceof ReforgedBatch) { TODO
// return (object instanceof ReforgedBatch) && (object.material.shader === group.shader);
}
@ -76,7 +77,7 @@ public class SetupGroups {
public static GenericGroup createMatchingGroup(final MdxModel model, final Object object) {
if (object instanceof Batch) {
return new BatchGroup(model, ((Batch) object).isExtended);
return new BatchGroup(model, ((Batch) object).skinningType, ((Batch) object).hd);
// } else if(object instanceof ReforgedBatch) { TODO
// return new ReforgedBatchGroup(model, ((ReforgedBatch)object).material.shader);
}

View File

@ -43,7 +43,7 @@ public class SetupSimpleGroups {
GenericGroup simpleGroup;
if (group instanceof BatchGroup) {
simpleGroup = new BatchGroup(model, ((BatchGroup) group).isExtended);
simpleGroup = new BatchGroup(model, ((BatchGroup) group).skinningType, ((BatchGroup) group).hd);
}
else {
throw new IllegalStateException("reforged?"); // TODO

View File

@ -0,0 +1,7 @@
package com.etheller.warsmash.viewer5.handlers.mdx;
public enum SkinningType {
Skin,
ExtendedVertexGroups,
VertexGroups;
}

View File

@ -55,6 +55,7 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
this.replaceableTextureFile += "Blight";
}
this.instance.setReplaceableTexture(this.replaceableTextureId, this.replaceableTextureFile + ".blp");
this.instance.setReplaceableTextureHD(this.replaceableTextureId, this.replaceableTextureFile);
}
this.selectionScale *= row.getFieldAsFloat(SEL_CIRCLE_SIZE, 0);
this.unitAnimationListenerImpl = new UnitAnimationListenerImpl((MdxComplexInstance) this.instance, 0, 0);

View File

@ -6,11 +6,14 @@ import javax.swing.UIManager;
import com.etheller.warsmash.desktop.DesktopLauncher;
import com.etheller.warsmash.desktop.editor.mdx.ui.YseraFrame;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler.ShaderEnvironmentType;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxViewer;
public class MdxEditorMain {
public static void main(final String[] args) {
DesktopLauncher.loadExtensions();
MdxViewer.DEFAULT_SHADER_ENV = ShaderEnvironmentType.GAME;
try {
// UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");

View File

@ -38,7 +38,7 @@ public class JassArrayedAssignmentStatement implements JassStatement {
if (arrayValue != null) {
final Integer indexInt = index.visit(IntegerJassValueVisitor.getInstance());
if ((indexInt != null) && (indexInt >= 0)) {
arrayValue.set(indexInt, this.expression.evaluate(globalScope, localScope, triggerScope));
arrayValue.set(globalScope, indexInt, this.expression.evaluate(globalScope, localScope, triggerScope));
}
else {
throw new JassException(globalScope,

View File

@ -1,7 +1,6 @@
package com.etheller.interpreter.ast.statement;
import com.etheller.interpreter.ast.Assignable;
import com.etheller.interpreter.ast.debug.JassException;
import com.etheller.interpreter.ast.expression.JassExpression;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.LocalScope;
@ -11,7 +10,6 @@ import com.etheller.interpreter.ast.value.JassValue;
public class JassSetStatement implements JassStatement {
private final String identifier;
private final JassExpression expression;
private static JassException zeroGuy = null;
public JassSetStatement(final String identifier, final JassExpression expression) {
this.identifier = identifier;

View File

@ -2,6 +2,8 @@ package com.etheller.interpreter.ast.value;
import java.util.Arrays;
import com.etheller.interpreter.ast.debug.JassException;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.util.JassSettings;
import com.etheller.interpreter.ast.value.visitor.JassTypeGettingValueVisitor;
@ -33,7 +35,7 @@ public class ArrayJassValue implements JassValue {
return visitor.accept(this);
}
public void set(final int index, JassValue value) {
public void set(final GlobalScope globalScope, final int index, JassValue value) {
final JassType primitiveType = this.type.getPrimitiveType();
if (value == null) {
if (primitiveType.isNullable()) {
@ -49,6 +51,10 @@ public class ArrayJassValue implements JassValue {
throw new IllegalStateException("Illegal type for assignment to " + primitiveType.getName() + " array: "
+ (valueType == null ? "null" : valueType.getName()));
}
if (index >= this.data.length) {
throw new JassException(globalScope, "Max jass array size exceeded",
new ArrayIndexOutOfBoundsException(index));
}
this.data[index] = value;
}