Files
runelite/model-viewer/src/main/java/net/runelite/modelviewer/ModelManager.java
Adam 7e7fb16693 modelviewer: fix zfighting of models
This uses the stencil buffer to hold face priorities and prevents drawing fragments of a lower priority overtop those of higher on the same model
2018-08-04 16:19:25 -04:00

182 lines
5.0 KiB
Java

/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.modelviewer;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import net.runelite.cache.IndexType;
import net.runelite.cache.definitions.ModelDefinition;
import net.runelite.cache.definitions.ObjectDefinition;
import net.runelite.cache.definitions.loaders.ModelLoader;
import net.runelite.cache.fs.Archive;
import net.runelite.cache.fs.Index;
import net.runelite.cache.fs.Storage;
import net.runelite.cache.fs.Store;
import net.runelite.cache.region.Location;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ModelManager
{
private static final Logger logger = LoggerFactory.getLogger(ModelManager.class);
private final Store store;
private final Map<ModelKey, ModelDefinition> models = new HashMap<>();
private final ModelLoader loader = new ModelLoader();
public ModelManager(Store store)
{
this.store = store;
}
public ModelDefinition getModel(int id)
{
return this.getModel(new ModelKey(id, -1, -1, -1), null);
}
public ModelDefinition getModel(int id, ObjectDefinition object, Location location)
{
final int type, rot;
if (location != null)
{
type = location.getType();
rot = location.getOrientation();
}
else
{
type = rot = 0;
}
return this.getModel(new ModelKey(id, object.getId(), type, rot), md ->
{
// this logic is from method3697 in 140
if (object.getObjectTypes() == null)
{
boolean isRotate = object.isRotated();
if (type == 2 && rot > 3)
{
isRotate = !isRotate;
}
if (isRotate)
{
md.method1493();
}
}
else
{
boolean isRotate = object.isRotated() ^ rot > 3;
if (isRotate)
{
md.method1493();
}
}
if (type == 4 && rot > 3)
{
md.rotate(256);
md.move(45, 0, -45);
}
switch (rot & 3)
{
case 1:
md.rotate1();
break;
case 2:
md.rotate2();
break;
case 3:
md.rotate3();
break;
}
short[] recolorToFind = object.getRecolorToFind();
if (recolorToFind != null)
{
short[] recolorToReplace = object.getRecolorToReplace();
for (int i = 0; i < recolorToFind.length; ++i)
{
md.recolor(recolorToFind[i], recolorToReplace[i]);
}
}
short[] retextureToFind = object.getRetextureToFind();
if (retextureToFind != null)
{
short[] textureToReplace = object.getTextureToReplace();
for (int i = 0; i < retextureToFind.length; ++i)
{
md.retexture(retextureToFind[i], textureToReplace[i]);
}
}
if (object.getModelSizeX() != 128 || object.getModelSizeHeight() != 128 || object.getModelSizeY() != 128)
{
md.resize(object.getModelSizeX(), object.getModelSizeHeight(), object.getModelSizeY());
}
if (object.getOffsetX() != 0 || object.getOffsetHeight() != 0 || object.getOffsetY() != 0)
{
md.move((short) object.getOffsetX(), (short) object.getOffsetHeight(), (short) object.getOffsetY());
}
});
}
private ModelDefinition getModel(ModelKey key, Consumer<ModelDefinition> loadConsumer)
{
ModelDefinition md = models.get(key);
if (md != null)
{
return md;
}
Storage storage = store.getStorage();
Index index = store.getIndex(IndexType.MODELS);
Archive modelArchive = index.getArchive(key.getModelId());
byte[] contents;
try
{
contents = modelArchive.decompress(storage.loadArchive(modelArchive));
}
catch (IOException e)
{
throw new RuntimeException(e);
}
md = loader.load(modelArchive.getArchiveId(), contents);
if (loadConsumer != null)
{
loadConsumer.accept(md);
}
md.computeNormals();
md.computeMaxPriority();
models.put(key, md);
return md;
}
}