/* * Copyright (c) 2018, Adam * 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.cache.item; import java.awt.image.BufferedImage; import java.io.IOException; import net.runelite.cache.definitions.ItemDefinition; import net.runelite.cache.definitions.ModelDefinition; import net.runelite.cache.definitions.providers.ItemProvider; import net.runelite.cache.definitions.providers.ModelProvider; import net.runelite.cache.definitions.providers.SpriteProvider; import net.runelite.cache.definitions.providers.TextureProvider; import net.runelite.cache.models.FaceNormal; import net.runelite.cache.models.JagexColor; import net.runelite.cache.models.VertexNormal; public class ItemSpriteFactory { public static BufferedImage createSprite(ItemProvider itemProvider, ModelProvider modelProvider, SpriteProvider spriteProvider, TextureProvider textureProvider, int itemId, int quantity, int border, int shadowColor, boolean noted) throws IOException { SpritePixels spritePixels = createSpritePixels(itemProvider, modelProvider, spriteProvider, textureProvider, itemId, quantity, border, shadowColor, noted); return spritePixels == null ? null : spritePixels.toBufferedImage(); } private static SpritePixels createSpritePixels(ItemProvider itemProvider, ModelProvider modelProvider, SpriteProvider spriteProvider, TextureProvider textureProvider, int itemId, int quantity, int border, int shadowColor, boolean noted) throws IOException { ItemDefinition item = itemProvider.provide(itemId); if (quantity > 1 && item.countObj != null) { int stackItemID = -1; for (int i = 0; i < 10; ++i) { if (quantity >= item.countCo[i] && item.countCo[i] != 0) { stackItemID = item.countObj[i]; } } if (stackItemID != -1) { item = itemProvider.provide(stackItemID); } } Model itemModel = getModel(modelProvider, item); if (itemModel == null) { return null; } SpritePixels auxSpritePixels = null; if (item.notedTemplate != -1) { auxSpritePixels = createSpritePixels(itemProvider, modelProvider, spriteProvider, textureProvider, item.notedID, 10, 1, 0, true); if (auxSpritePixels == null) { return null; } } else if (item.boughtTemplateId != -1) { auxSpritePixels = createSpritePixels(itemProvider, modelProvider, spriteProvider, textureProvider, item.boughtId, quantity, border, 0, false); if (auxSpritePixels == null) { return null; } } else if (item.placeholderTemplateId != -1) { auxSpritePixels = createSpritePixels(itemProvider, modelProvider, spriteProvider, textureProvider, item.placeholderId, quantity, 0, 0, false); if (auxSpritePixels == null) { return null; } } RSTextureProvider rsTextureProvider = new RSTextureProvider(textureProvider, spriteProvider); int width = 36 * 2; int height = 32 * 2; SpritePixels spritePixels = new SpritePixels(width, height); Graphics3D graphics = new Graphics3D(rsTextureProvider); graphics.setBrightness(JagexColor.BRIGHTNESS_MAX); graphics.setRasterBuffer(spritePixels.pixels, width, height); graphics.reset(); graphics.setRasterClipping(); graphics.setOffset(16 * 2, 16 * 2); graphics.rasterGouraudLowRes = false; if (item.placeholderTemplateId != -1) { auxSpritePixels.drawAtOn(graphics, 0, 0); } int zoom2d; // The holy symbol item for some reason needs a different zoom value otherwise it gets cut off if (itemId == 1716 || itemId == 1718) { zoom2d = (int) (((double) item.zoom2d) / 1.5D); } else { zoom2d = (int) (((double) item.zoom2d) / 1.95D); } if (noted) { zoom2d = (int) ((double) zoom2d * 1.5D); } else if (border == 2) { zoom2d = (int) ((double) zoom2d * 1.04D); } int var17 = zoom2d * Graphics3D.SINE[item.xan2d] >> 16; int var18 = zoom2d * Graphics3D.COSINE[item.xan2d] >> 16; itemModel.calculateBoundsCylinder(); itemModel.projectAndDraw(graphics, 0, item.yan2d, item.zan2d, item.xan2d, item.xOffset2d, itemModel.modelHeight / 2 + var17 + item.yOffset2d, var18 + item.yOffset2d); if (item.boughtTemplateId != -1) { auxSpritePixels.drawAtOn(graphics, 0, 0); } if (border >= 1) { spritePixels.drawBorder(1); } if (border >= 2) { spritePixels.drawBorder(0xffffff); } if (shadowColor != 0) { spritePixels.drawShadow(shadowColor); } graphics.setRasterBuffer(spritePixels.pixels, width, height); if (item.notedTemplate != -1) { auxSpritePixels.drawAtOn(graphics, 0, 0); } graphics.setRasterBuffer(graphics.graphicsPixels, graphics.graphicsPixelsWidth, graphics.graphicsPixelsHeight); graphics.setRasterClipping(); graphics.rasterGouraudLowRes = true; return spritePixels; } private static Model getModel(ModelProvider modelProvider, ItemDefinition item) throws IOException { Model itemModel; ModelDefinition inventoryModel = modelProvider.provide(item.inventoryModel); if (inventoryModel == null) { return null; } if (item.resizeX != 128 || item.resizeY != 128 || item.resizeZ != 128) { inventoryModel.resize(item.resizeX, item.resizeY, item.resizeZ); } if (item.colorFind != null) { for (int i = 0; i < item.colorFind.length; ++i) { inventoryModel.recolor(item.colorFind[i], item.colorReplace[i]); } } if (item.textureFind != null) { for (int i = 0; i < item.textureFind.length; ++i) { inventoryModel.retexture(item.textureFind[i], item.textureReplace[i]); } } itemModel = light(inventoryModel, item.ambient + 64, item.contrast + 768, -50, -10, -50); return itemModel; } private static Model light(ModelDefinition def, int ambient, int contrast, int x, int y, int z) { def.computeNormals(); int somethingMagnitude = (int) Math.sqrt((double) (z * z + x * x + y * y)); int var7 = somethingMagnitude * contrast >> 8; Model litModel = new Model(); litModel.faceColors1 = new int[def.faceCount]; litModel.faceColors2 = new int[def.faceCount]; litModel.faceColors3 = new int[def.faceCount]; if (def.numTextureFaces > 0 && def.textureCoords != null) { int[] var9 = new int[def.numTextureFaces]; int var10; for (var10 = 0; var10 < def.faceCount; ++var10) { if (def.textureCoords[var10] != -1) { ++var9[def.textureCoords[var10] & 255]; } } litModel.numTextureFaces = 0; for (var10 = 0; var10 < def.numTextureFaces; ++var10) { if (var9[var10] > 0 && def.textureRenderTypes[var10] == 0) { ++litModel.numTextureFaces; } } litModel.texIndices1 = new int[litModel.numTextureFaces]; litModel.texIndices2 = new int[litModel.numTextureFaces]; litModel.texIndices3 = new int[litModel.numTextureFaces]; var10 = 0; for (int i = 0; i < def.numTextureFaces; ++i) { if (var9[i] > 0 && def.textureRenderTypes[i] == 0) { litModel.texIndices1[var10] = def.texIndices1[i] & '\uffff'; litModel.texIndices2[var10] = def.texIndices2[i] & '\uffff'; litModel.texIndices3[var10] = def.texIndices3[i] & '\uffff'; var9[i] = var10++; } else { var9[i] = -1; } } litModel.textureCoords = new byte[def.faceCount]; for (int i = 0; i < def.faceCount; ++i) { if (def.textureCoords[i] != -1) { litModel.textureCoords[i] = (byte) var9[def.textureCoords[i] & 255]; } else { litModel.textureCoords[i] = -1; } } } for (int faceIdx = 0; faceIdx < def.faceCount; ++faceIdx) { byte faceType; if (def.faceRenderTypes == null) { faceType = 0; } else { faceType = def.faceRenderTypes[faceIdx]; } byte faceAlpha; if (def.faceTransparencies == null) { faceAlpha = 0; } else { faceAlpha = def.faceTransparencies[faceIdx]; } short faceTexture; if (def.faceTextures == null) { faceTexture = -1; } else { faceTexture = def.faceTextures[faceIdx]; } if (faceAlpha == -2) { faceType = 3; } if (faceAlpha == -1) { faceType = 2; } VertexNormal vertexNormal; int tmp; FaceNormal faceNormal; if (faceTexture == -1) { if (faceType != 0) { if (faceType == 1) { faceNormal = def.faceNormals[faceIdx]; tmp = (y * faceNormal.y + z * faceNormal.z + x * faceNormal.x) / (var7 / 2 + var7) + ambient; litModel.faceColors1[faceIdx] = method2608(def.faceColors[faceIdx] & '\uffff', tmp); litModel.faceColors3[faceIdx] = -1; } else if (faceType == 3) { litModel.faceColors1[faceIdx] = 128; litModel.faceColors3[faceIdx] = -1; } else { litModel.faceColors3[faceIdx] = -2; } } else { int var15 = def.faceColors[faceIdx] & '\uffff'; vertexNormal = def.vertexNormals[def.faceIndices1[faceIdx]]; tmp = (y * vertexNormal.y + z * vertexNormal.z + x * vertexNormal.x) / (var7 * vertexNormal.magnitude) + ambient; litModel.faceColors1[faceIdx] = method2608(var15, tmp); vertexNormal = def.vertexNormals[def.faceIndices2[faceIdx]]; tmp = (y * vertexNormal.y + z * vertexNormal.z + x * vertexNormal.x) / (var7 * vertexNormal.magnitude) + ambient; litModel.faceColors2[faceIdx] = method2608(var15, tmp); vertexNormal = def.vertexNormals[def.faceIndices3[faceIdx]]; tmp = (y * vertexNormal.y + z * vertexNormal.z + x * vertexNormal.x) / (var7 * vertexNormal.magnitude) + ambient; litModel.faceColors3[faceIdx] = method2608(var15, tmp); } } else if (faceType != 0) { if (faceType == 1) { faceNormal = def.faceNormals[faceIdx]; tmp = (y * faceNormal.y + z * faceNormal.z + x * faceNormal.x) / (var7 / 2 + var7) + ambient; litModel.faceColors1[faceIdx] = bound2to126(tmp); litModel.faceColors3[faceIdx] = -1; } else { litModel.faceColors3[faceIdx] = -2; } } else { vertexNormal = def.vertexNormals[def.faceIndices1[faceIdx]]; tmp = (y * vertexNormal.y + z * vertexNormal.z + x * vertexNormal.x) / (var7 * vertexNormal.magnitude) + ambient; litModel.faceColors1[faceIdx] = bound2to126(tmp); vertexNormal = def.vertexNormals[def.faceIndices2[faceIdx]]; tmp = (y * vertexNormal.y + z * vertexNormal.z + x * vertexNormal.x) / (var7 * vertexNormal.magnitude) + ambient; litModel.faceColors2[faceIdx] = bound2to126(tmp); vertexNormal = def.vertexNormals[def.faceIndices3[faceIdx]]; tmp = (y * vertexNormal.y + z * vertexNormal.z + x * vertexNormal.x) / (var7 * vertexNormal.magnitude) + ambient; litModel.faceColors3[faceIdx] = bound2to126(tmp); } } litModel.verticesCount = def.vertexCount; litModel.verticesX = def.vertexX; litModel.verticesY = def.vertexY; litModel.verticesZ = def.vertexZ; litModel.indicesCount = def.faceCount; litModel.indices1 = def.faceIndices1; litModel.indices2 = def.faceIndices2; litModel.indices3 = def.faceIndices3; litModel.facePriorities = def.faceRenderPriorities; litModel.faceTransparencies = def.faceTransparencies; litModel.faceTextures = def.faceTextures; return litModel; } static int method2608(int var0, int var1) { var1 = ((var0 & 127) * var1) >> 7; var1 = bound2to126(var1); return (var0 & 65408) + var1; } static int bound2to126(int var0) { if (var0 < 2) { var0 = 2; } else if (var0 > 126) { var0 = 126; } return var0; } }