OBJ model hotswap

This commit is contained in:
Boblet 2026-01-29 09:49:20 +01:00
parent aa4942ea68
commit 97230f1b74
5 changed files with 80 additions and 9 deletions

View File

@ -21,6 +21,7 @@
* Bullet casings now make sounds when falling to the ground * Bullet casings now make sounds when falling to the ground
* Most ammo types now have QMAW pages, including information on whether or not they are a war crime * Most ammo types now have QMAW pages, including information on whether or not they are a war crime
* Both assembly and chemical factories now have four special ports that only allow items inserted to go into one recipe group * Both assembly and chemical factories now have four special ports that only allow items inserted to go into one recipe group
* All models using the HFR wavefront loader can now be hot-swapped via resource reload (F3 + T)
# Fixed # Fixed
* Potentially fixed yet another issue regarding crates * Potentially fixed yet another issue regarding crates

View File

@ -61,6 +61,7 @@ import com.hbm.render.item.ItemRenderMissileGeneric.RenderMissileType;
import com.hbm.render.item.block.ItemRenderBlock; import com.hbm.render.item.block.ItemRenderBlock;
import com.hbm.render.item.block.ItemRenderDecoBlock; import com.hbm.render.item.block.ItemRenderDecoBlock;
import com.hbm.render.item.weapon.*; import com.hbm.render.item.weapon.*;
import com.hbm.render.loader.HFRModelReloader;
import com.hbm.render.loader.HmfModelLoader; import com.hbm.render.loader.HmfModelLoader;
import com.hbm.render.model.ModelPigeon; import com.hbm.render.model.ModelPigeon;
import com.hbm.render.tileentity.*; import com.hbm.render.tileentity.*;
@ -162,7 +163,9 @@ public class ClientProxy extends ServerProxy {
Jars.initJars(); Jars.initJars();
((IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager()).registerReloadListener(new QMAWLoader()); IReloadableResourceManager resourceMan = (IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager();
resourceMan.registerReloadListener(new QMAWLoader());
resourceMan.registerReloadListener(new HFRModelReloader());
if(GeneralConfig.enableSoundExtension) { if(GeneralConfig.enableSoundExtension) {
SoundSystemConfig.setNumberNormalChannels(GeneralConfig.normalSoundChannels); SoundSystemConfig.setNumberNormalChannels(GeneralConfig.normalSoundChannels);

View File

@ -0,0 +1,34 @@
package com.hbm.render.loader;
import java.io.IOException;
import java.util.Map.Entry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
public class HFRModelReloader implements IResourceManagerReloadListener {
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
for(HFRWavefrontObject obj : HFRWavefrontObject.allModels) {
try {
obj.destroy();
IResource resource = Minecraft.getMinecraft().getResourceManager().getResource(obj.resource);
obj.loadObjModel(resource.getInputStream());
// MainRegistry.logger.info("Reloading OBJ " + obj.resource.getResourcePath());
} catch(IOException e) { }
}
for(Entry<HFRWavefrontObjectVBO, HFRWavefrontObject> entry : HFRWavefrontObject.allVBOs.entrySet()) {
HFRWavefrontObjectVBO vbo = entry.getKey();
HFRWavefrontObject obj = entry.getValue();
vbo.destroy();
vbo.load(obj);
// MainRegistry.logger.info("Reloading VBO " + obj.resource.getResourcePath());
}
}
}

View File

@ -5,6 +5,8 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -22,6 +24,11 @@ import net.minecraftforge.client.model.obj.TextureCoordinate;
import net.minecraftforge.client.model.obj.Vertex; import net.minecraftforge.client.model.obj.Vertex;
public class HFRWavefrontObject implements IModelCustomNamed { public class HFRWavefrontObject implements IModelCustomNamed {
/** For resource reloading */
public static LinkedHashSet<HFRWavefrontObject> allModels = new LinkedHashSet();
public static LinkedHashMap<HFRWavefrontObjectVBO, HFRWavefrontObject> allVBOs = new LinkedHashMap();
private static Pattern vertexPattern = Pattern.compile("(v( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *\\n)|(v( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *$)"); private static Pattern vertexPattern = Pattern.compile("(v( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *\\n)|(v( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *$)");
private static Pattern vertexNormalPattern = Pattern.compile("(vn( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *\\n)|(vn( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *$)"); private static Pattern vertexNormalPattern = Pattern.compile("(vn( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *\\n)|(vn( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *$)");
private static Pattern textureCoordinatePattern = Pattern.compile("(vt( (\\-){0,1}\\d+\\.\\d+){2,3} *\\n)|(vt( (\\-){0,1}\\d+(\\.\\d+)?){2,3} *$)"); private static Pattern textureCoordinatePattern = Pattern.compile("(vt( (\\-){0,1}\\d+\\.\\d+){2,3} *\\n)|(vt( (\\-){0,1}\\d+(\\.\\d+)?){2,3} *$)");
@ -40,10 +47,12 @@ public class HFRWavefrontObject implements IModelCustomNamed {
public ArrayList<TextureCoordinate> textureCoordinates = new ArrayList<TextureCoordinate>(); public ArrayList<TextureCoordinate> textureCoordinates = new ArrayList<TextureCoordinate>();
public ArrayList<S_GroupObject> groupObjects = new ArrayList<S_GroupObject>(); public ArrayList<S_GroupObject> groupObjects = new ArrayList<S_GroupObject>();
private S_GroupObject currentGroupObject; private S_GroupObject currentGroupObject;
public ResourceLocation resource;
private String fileName; private String fileName;
private boolean smoothing = true; private boolean smoothing = true;
public HFRWavefrontObject(ResourceLocation resource) throws ModelFormatException { public HFRWavefrontObject(ResourceLocation resource) throws ModelFormatException {
this.resource = resource;
this.fileName = resource.toString(); this.fileName = resource.toString();
try { try {
@ -52,6 +61,8 @@ public class HFRWavefrontObject implements IModelCustomNamed {
} catch(IOException e) { } catch(IOException e) {
throw new ModelFormatException("IO Exception reading model format", e); throw new ModelFormatException("IO Exception reading model format", e);
} }
this.allModels.add(this);
} }
public HFRWavefrontObject(ResourceLocation resource, boolean smoothing) throws ModelFormatException { public HFRWavefrontObject(ResourceLocation resource, boolean smoothing) throws ModelFormatException {
@ -59,12 +70,15 @@ public class HFRWavefrontObject implements IModelCustomNamed {
this.smoothing = smoothing; this.smoothing = smoothing;
} }
public HFRWavefrontObject(String filename, InputStream inputStream) throws ModelFormatException { public void destroy() {
this.fileName = filename; vertices.clear();
loadObjModel(inputStream); vertexNormals.clear();
textureCoordinates.clear();
groupObjects.clear();
currentGroupObject = null;
} }
private void loadObjModel(InputStream inputStream) throws ModelFormatException { public void loadObjModel(InputStream inputStream) throws ModelFormatException {
BufferedReader reader = null; BufferedReader reader = null;
String currentLine = null; String currentLine = null;
@ -492,7 +506,9 @@ public class HFRWavefrontObject implements IModelCustomNamed {
return names; return names;
} }
public WavefrontObjVBO asVBO() { public HFRWavefrontObjectVBO asVBO() {
return new WavefrontObjVBO(this); HFRWavefrontObjectVBO vbo = new HFRWavefrontObjectVBO(this);
this.allVBOs.put(vbo, this);
return vbo;
} }
} }

View File

@ -10,7 +10,7 @@ import org.lwjgl.opengl.*;
import net.minecraftforge.client.model.obj.TextureCoordinate; import net.minecraftforge.client.model.obj.TextureCoordinate;
import net.minecraftforge.client.model.obj.Vertex; import net.minecraftforge.client.model.obj.Vertex;
public class WavefrontObjVBO implements IModelCustomNamed { public class HFRWavefrontObjectVBO implements IModelCustomNamed {
class VBOBufferData { class VBOBufferData {
@ -27,7 +27,11 @@ public class WavefrontObjVBO implements IModelCustomNamed {
static int VERTEX_SIZE = 3; static int VERTEX_SIZE = 3;
static int UV_SIZE = 3; static int UV_SIZE = 3;
public WavefrontObjVBO(HFRWavefrontObject obj) { public HFRWavefrontObjectVBO(HFRWavefrontObject obj) {
load(obj);
}
public void load(HFRWavefrontObject obj) {
for(S_GroupObject g : obj.groupObjects) { for(S_GroupObject g : obj.groupObjects) {
VBOBufferData data = new VBOBufferData(); VBOBufferData data = new VBOBufferData();
data.name = g.name; data.name = g.name;
@ -74,6 +78,19 @@ public class WavefrontObjVBO implements IModelCustomNamed {
groups.add(data); groups.add(data);
} }
} }
// truth be told, i have no fucking idea what i'm doing
// i know the VBO sends data to the GPU to be saved there directly which is where the optimization comes from in the first place
// so logically, if we want to get rid of this, we need to blow the data up
// documentation on GL15 functions seems nonexistant so fuck it we ball i guess
public void destroy() {
for(VBOBufferData data : groups) {
GL15.glDeleteBuffers(data.vertexHandle);
GL15.glDeleteBuffers(data.uvHandle);
GL15.glDeleteBuffers(data.normalHandle);
}
groups.clear();
}
@Override @Override
public String getType() { public String getType() {