Skip to content

Commit

Permalink
Add BTK support
Browse files Browse the repository at this point in the history
Yes I did steal from myself.
So far this is only used for the PowerStarRenderer, but TexChange supports BTK as well so we can apply it there.
  • Loading branch information
SuperHackio committed Mar 9, 2024
1 parent 4cfbec2 commit 00bfd77
Show file tree
Hide file tree
Showing 6 changed files with 428 additions and 46 deletions.
92 changes: 64 additions & 28 deletions src/whitehole/rendering/BmdRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,20 @@
import java.io.IOException;
import java.nio.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;
import whitehole.Settings;
import whitehole.Whitehole;
import whitehole.io.ExternalFile;
import whitehole.io.FileBase;
import whitehole.io.RarcFile;
import whitehole.smg.Bmd;
import whitehole.smg.animation.Bva;
import whitehole.smg.ImageUtils.FilterMode;
import whitehole.smg.ImageUtils.WrapMode;
import whitehole.smg.ImageUtils.*;
import whitehole.smg.animation.*;
import whitehole.util.Color4;
import whitehole.math.Matrix4;
import whitehole.util.SuperFastHash;
import whitehole.math.Vec2f;
import whitehole.math.Vec3f;
import whitehole.smg.animation.Btp;
import whitehole.math.Matrix4;

public class BmdRenderer extends GLRenderer {
private void uploadTexture(GL2 gl, int id) {
Expand Down Expand Up @@ -227,6 +222,32 @@ public void generateShaders(GL2 gl, int matid, int...customColors) throws GLExce
if(model == null)
return;

// This MUST occur before the shader hash is calculated
Bmd.Material mat = this.model.materials[matid];

if (texMatrixAnim != null)
{
int Frame = texMatrixAnimIndex;
if (Frame < 0)
Frame = 0;
if (Frame > texMatrixAnim.Duration)
Frame = texMatrixAnim.Duration;

var anim = texMatrixAnim.getAnimByName(mat.name);
if (anim != null)
{
mat.texMtx[anim.TextureGeneratorId].centerS = anim.Center[0];
mat.texMtx[anim.TextureGeneratorId].centerT = anim.Center[1];
mat.texMtx[anim.TextureGeneratorId].centerU = anim.Center[2];
mat.texMtx[anim.TextureGeneratorId].scaleS = anim.ScaleU.getValueAtFrame((short)texMatrixAnimIndex);
mat.texMtx[anim.TextureGeneratorId].scaleT = anim.ScaleV.getValueAtFrame((short)texMatrixAnimIndex);
mat.texMtx[anim.TextureGeneratorId].rotate = anim.RotationW.getValueAtFrame((short)texMatrixAnimIndex);
mat.texMtx[anim.TextureGeneratorId].transS = anim.TranslationU.getValueAtFrame((short)texMatrixAnimIndex);
mat.texMtx[anim.TextureGeneratorId].transT = anim.TranslationV.getValueAtFrame((short)texMatrixAnimIndex);
mat.texMtx[anim.TextureGeneratorId].doCalc();
}
}

if(shaders == null)
shaders = new Shader[1];
shaders[matid] = new Shader();
Expand Down Expand Up @@ -293,7 +314,6 @@ public void generateShaders(GL2 gl, int matid, int...customColors) throws GLExce
String[] tevscale = { "1.0", "2.0", "4.0", "0.5" };
String[] alphacompare = { "0 == 1", "%1$s < %2$f", "%1$s == %2$f", "%1$s <= %2$f", "%1$s > %2$f", "%1$s != %2$f", "%1$s >= %2$f", "1 == 1" };
String[] alphacombine = { "(%1$s) && (%2$s)", "(%1$s) || (%2$s)", "((%1$s) && (!(%2$s))) || ((!(%1$s)) && (%2$s))", "((%1$s) && (%2$s)) || ((!(%1$s)) && (!(%2$s)))" };
Bmd.Material mat = this.model.materials[matid];
StringBuilder vert = new StringBuilder();
vert.append("#version 120\n");
vert.append("\n");
Expand Down Expand Up @@ -617,17 +637,21 @@ else if(mat.alphaComp.mergeFunc == 0)

protected RarcFile archive = null;
protected Bmd model = null;
protected Btp texpattern = null;
protected int texpatternIndex = 0;
protected Bva visible = null;
protected int visibleIndex = 0;

protected Shader[] shaders = null;
protected int[] textures = null;
protected boolean hasShaders = false;
protected Vec3f translation = DEFAULT_TRANSLATION;
protected Vec3f rotation = DEFAULT_ROTATION;
protected Vec3f scale = DEFAULT_SCALE;

protected Btk texMatrixAnim = null;
protected int texMatrixAnimIndex = 0;
protected Btp texPatternAnim = null;
protected int texPatternAnimIndex = 0;
protected Bva shapeVisibleAnim = null;
protected int shapeVisibleAnimIndex = 0;

public BmdRenderer() {

}
Expand Down Expand Up @@ -686,10 +710,10 @@ protected final void ctor_loadModelDefault(RenderInfo info, String modelName) {
}

//Some default BVA files for things like Thwomps
if (visible == null)
visible = ctor_tryLoadBVA(modelName, "Wait", archive);
if (visible == null)
visible = ctor_tryLoadBVA(modelName, "Normal", archive);
if (shapeVisibleAnim == null)
shapeVisibleAnim = ctor_tryLoadBVA(modelName, "Wait", archive);
if (shapeVisibleAnim == null)
shapeVisibleAnim = ctor_tryLoadBVA(modelName, "Normal", archive);

if (isValidBmdModel())
ctor_uploadData(info);
Expand Down Expand Up @@ -793,6 +817,18 @@ protected final void ctor_uploadData(RenderInfo info) throws GLException {
}
}

protected final Btk ctor_tryLoadBTK(String modelName, String animName, RarcFile archive) {
try
{
String path = "/" + modelName + "/" + animName + ".btk";
FileBase fi = ctor_tryLoadFile(path, archive);
if(fi != null)
return new Btk(fi);
}
catch(IOException ex) {}
return null;
}

protected final Btp ctor_tryLoadBTP(String modelName, String animName, RarcFile archive) {
try
{
Expand Down Expand Up @@ -879,11 +915,11 @@ public void close(RenderInfo info) throws GLException {
public void releaseStorage() {
try
{
if(visible != null)
visible.close();
if(shapeVisibleAnim != null)
shapeVisibleAnim.close();

if (texpattern != null)
texpattern.close();
if (texPatternAnim != null)
texPatternAnim.close();

if (model != null)
model.close();
Expand All @@ -892,8 +928,8 @@ public void releaseStorage() {
archive.close();

model = null;
visible = null;
texpattern = null;
shapeVisibleAnim = null;
texPatternAnim = null;
archive = null;
}
catch(Exception ex)
Expand Down Expand Up @@ -954,12 +990,12 @@ public void render(RenderInfo info) throws GLException {
if(node.nodeType != 0) continue;
int shape = node.nodeID;

if(visible != null)
if(shapeVisibleAnim != null)
{
var shp = visible.animData.get(shape);
var shp = shapeVisibleAnim.animData.get(shape);
if (shp != null)
{
var vis = shp.get(visibleIndex);
var vis = shp.get(shapeVisibleAnimIndex);
if (vis != null && !vis)
continue;
}
Expand Down Expand Up @@ -1001,9 +1037,9 @@ public void render(RenderInfo info) throws GLException {
// Decide textures based on the BTP if it exists
short TextureSelectIndex = mat.texStages[i];

if (texpattern != null)
if (texPatternAnim != null)
{
Short f = texpattern.get(mat.name, i, texpatternIndex);
Short f = texPatternAnim.get(mat.name, i, texPatternAnimIndex);
if (f != null)
TextureSelectIndex = f;
}
Expand Down
30 changes: 14 additions & 16 deletions src/whitehole/rendering/special/PowerStarRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,38 +68,36 @@ public PowerStarRenderer(RenderInfo info, String modelName, AbstractObj obj) thr
}

// Try SMG1
if (!isGrand && visible == null)
visible = ctor_tryLoadBVA(modelName, "PowerStar", archive);
if (!isGrand && shapeVisibleAnim == null)
shapeVisibleAnim = ctor_tryLoadBVA(modelName, "PowerStar", archive);

if (texpattern == null)
texpattern = ctor_tryLoadBTP(modelName, "PowerStar", archive);
if (texPatternAnim == null)
texPatternAnim = ctor_tryLoadBTP(modelName, "PowerStar", archive);


// Try SMG2. No clue why the name changed...
if (!isGrand && visible == null)
visible = ctor_tryLoadBVA(modelName, "PowerStarColor", archive);
if (!isGrand && shapeVisibleAnim == null)
shapeVisibleAnim = ctor_tryLoadBVA(modelName, "PowerStarColor", archive);

if (texpattern == null)
texpattern = ctor_tryLoadBTP(modelName, "PowerStarColor", archive);
if (texPatternAnim == null)
texPatternAnim = ctor_tryLoadBTP(modelName, "PowerStarColor", archive);

if (texMatrixAnim == null)
texMatrixAnim = ctor_tryLoadBTK(modelName, "PowerStarColor", archive);

// Decide PowerStarColor
texpatternIndex = getPowerStarColor(obj);
texPatternAnimIndex = getPowerStarColor(obj);
texMatrixAnimIndex = texPatternAnimIndex;

// TEMPORARY UNTIL WE GET BTK READING
model.setMaterialHidden("GrandStarBronze", true);
model.setMaterialHidden("GrandStarEmpty", true);
if (texpatternIndex == 1)
if (texPatternAnimIndex == 1)
{
if (grandArchive != null) //Okay well this is just how Grand Stars work...
{
model.setMaterialHidden("FooMat", true);
model.setMaterialHidden("GrandStarBronze", false);
}
else
{
model.materials[2].texMtx[2].transS = -0.25f;
model.materials[2].texMtx[2].doCalc();
}
}

ctor_uploadData(info);
Expand Down
3 changes: 1 addition & 2 deletions src/whitehole/smg/Bmd.java
Original file line number Diff line number Diff line change
Expand Up @@ -1176,8 +1176,7 @@ public class TexMtxInfo
{
public byte proj, type;
public short padding;
public float centerS, centerT;
public float centerU;
public float centerS, centerT, centerU;
public float scaleS, scaleT;
public float rotate;
public short padding2;
Expand Down
115 changes: 115 additions & 0 deletions src/whitehole/smg/animation/Btk.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,125 @@
*/
package whitehole.smg.animation;

import java.io.IOException;
import java.util.*;
import whitehole.io.FileBase;
import whitehole.smg.animation.J3DAnim.*;

/**
*
* @author Hackio
*/
public class Btk {
private final FileBase file;
public List<Animation> animData;

public Btk(FileBase file) throws IOException
{
this.file = file;
this.file.setBigEndian(true);

file.position(0x29);
RotationMultiplier = file.readByte();
float rotationScale = (float)(Math.pow(2, RotationMultiplier) / 0x7FFF);
Duration = file.readShort();

short AnimationCount = (short)(file.readShort() / 3),
ScaleCount = file.readShort(),
RotationCount = file.readShort(),
TranslationCount = file.readShort();

int ChunkStart = 0x20;
int AnimationTableOffset = file.readInt() + ChunkStart,
RemapTableOffset = file.readInt() + ChunkStart,
MaterialSTOffset = file.readInt() + ChunkStart,
TextureMapIDTableOffset = file.readInt() + ChunkStart,
TextureCenterTableOffset = file.readInt() + ChunkStart,
ScaleTableOffset = file.readInt() + ChunkStart,
RotationTableOffset = file.readInt() + ChunkStart,
TranslationTableOffset = file.readInt() + ChunkStart;

animData = new ArrayList(AnimationCount);

file.position(ChunkStart + 0x5C);
UseMaya = file.readInt() == 1;

// Oh boy...
file.position(ScaleTableOffset);
float[] ScaleTable = file.readFloats(ScaleCount);
file.position(RotationTableOffset);
short[] RotationTable = file.readShorts(RotationCount);
file.position(TranslationTableOffset);
float[] TranslationTable = file.readFloats(TranslationCount);

for (int i = 0; i < AnimationCount; i++) {
// get the name of the animation
file.position(MaterialSTOffset + 4 + (i*4));
file.skip(2); // Skip the hash
short off = file.readShort();
file.position(MaterialSTOffset + off);
String matName = file.readString("ASCII", 0);


Animation anim = new Animation();
anim.MaterialName = matName;
file.position(TextureMapIDTableOffset + i);
anim.TextureGeneratorId = file.readByte();
file.position(TextureCenterTableOffset + (i * 0x0C));
anim.Center = file.readFloats(3);

file.position(AnimationTableOffset + (i * 0x36));
anim.ScaleU = J3DAnimationTrack.createTrackFloat(file, ScaleTable, 1);
anim.RotationU = J3DAnimationTrack.createTrackShort(file, RotationTable, rotationScale);
anim.TranslationU = J3DAnimationTrack.createTrackFloat(file, TranslationTable, 1);

anim.ScaleV = J3DAnimationTrack.createTrackFloat(file, ScaleTable, 1);
anim.RotationV = J3DAnimationTrack.createTrackShort(file, RotationTable, rotationScale);
anim.TranslationV = J3DAnimationTrack.createTrackFloat(file, TranslationTable, 1);

anim.ScaleW = J3DAnimationTrack.createTrackFloat(file, ScaleTable, 1);
anim.RotationW = J3DAnimationTrack.createTrackShort(file, RotationTable, rotationScale);
anim.TranslationW = J3DAnimationTrack.createTrackFloat(file, TranslationTable, 1);

animData.add(anim);
}
}

public Animation getAnimByName(String name)
{
for (int i = 0; i < animData.size(); i++) {
var x = animData.get(i);
if (x.MaterialName.equals(name))
return x;
}
return null;
}

/**
* The length of the animation
*/
public final int Duration;
//Loop mode would go here
private final boolean UseMaya;
private final byte RotationMultiplier;

public class Animation
{
public String MaterialName = "";
/**
* index to the Texture Generator inside the model to target
*/
public byte TextureGeneratorId;

public J3DAnimationTrack ScaleU = new J3DAnimationTrack();
public J3DAnimationTrack ScaleV = new J3DAnimationTrack();
public J3DAnimationTrack ScaleW = new J3DAnimationTrack();
public J3DAnimationTrack RotationU = new J3DAnimationTrack();
public J3DAnimationTrack RotationV = new J3DAnimationTrack();
public J3DAnimationTrack RotationW = new J3DAnimationTrack();
public J3DAnimationTrack TranslationU = new J3DAnimationTrack();
public J3DAnimationTrack TranslationV = new J3DAnimationTrack();
public J3DAnimationTrack TranslationW = new J3DAnimationTrack();
public float[] Center = new float[3];
}
}
Loading

0 comments on commit 00bfd77

Please sign in to comment.