package NET.worlds.scape; import NET.worlds.console.Console; import NET.worlds.console.Main; import NET.worlds.console.MainCallback; import NET.worlds.core.IniFile; import NET.worlds.network.NetUpdate; import NET.worlds.network.URL; import java.awt.Color; import java.io.IOException; public class Material extends SuperRoot implements BGLoaded, MainCallback { static int serial = 0; public static boolean botMode = false; private boolean keepLoaded = false; private int[] ids; private Texture[] textures; private int vRes = 1; private int hRes = 1; private int sPos = -1; private final boolean loResMode = false; URL textureName; protected URL[] subnames; private boolean doReclump; private static boolean tryBMP = IniFile.gamma().getIniInt("TRYBMP", 0) != 0; private float ambient; private float diffuse; private float specular; private float opacity; private boolean smooth; private boolean filter; private int r; private int g; private int b; private Color color; private static Object classCookie = new Object(); static { nativeInit(); } public static native void nativeInit(); public Material(float ambient, float diffuse, float specular, Color color, Texture texture, float opacity, boolean smooth, boolean filter) { if (botMode) { texture = null; } this.ambient = ambient; this.diffuse = diffuse; this.specular = specular; this.setColor(color); if (texture != null) { this.textures = new Texture[1]; this.textures[0] = texture; } this.opacity = opacity; this.smooth = smooth; this.filter = filter; } public Material(Color color) { this(0.75F, 0.0F, 0.0F, color, null, 1.0F, false, false); } public Material(Texture texture) { this(0.75F, 0.0F, 0.0F, Color.black, texture, 1.0F, false, false); } public Material(Color initialColor, URL textureName) { this(initialColor != null ? initialColor : new Color(128, 128, 128)); if (!botMode) { this.loadTexture(textureName); } } public Material(URL tileTexture, int x, int y) { this(0.75F, 0.0F, 0.0F, Color.black, null, 1.0F, false, false); this.hRes = x; this.vRes = y; serial++; int numSubs = this.getHRes() * this.getVRes(); this.textures = new Texture[numSubs]; this.makeMaterials(); this.subnames = new URL[numSubs]; String lowResBaseName = tileTexture.getBase(); int nextSubname = 0; for (int v = this.vRes; v > 0; v--) { String vExt = "" + v; for (int h = 0; h < this.hRes; nextSubname++) { URL subname = URL.make(tileTexture, lowResBaseName + serial + vExt + (h + 1) + ".cmp"); this.subnames[nextSubname] = subname; this.syncBackgroundLoad(tileTexture.unalias(), subname); h++; } } } public Material(URL textureName) { this(null, textureName); } public Material() { } @Override protected void noteAddingTo(SuperRoot owner) { if (((WObject)owner).hasClump()) { this.addRwChildren(); } } @Override public void detach() { if (this.ids != null) { this.markVoid(); } super.detach(); } public Texture[] getTextures() { return this.textures; } public void addRwChildren() { if (this.ids == null) { if (this.textures == null && this.textureName != null) { this.loadTextures(); } else { this.makeMaterials(); if (this.textures != null) { for (int i = 0; i < this.ids.length; i++) { this.nativeSetTexture(i, this.textures[i]); } } } } } public void markVoid() { if (!this.keepLoaded) { if (this.textureName != null) { this.removeTextures(); } this.closeMaterials(); } } public void setKeepLoaded(boolean f) { boolean klWas = this.keepLoaded; this.keepLoaded = f; if (!f && klWas) { SuperRoot o = this.getOwner(); if (o == null || !((WObject)o).hasClump()) { this.markVoid(); } } } public static Material restore(Restorer r) throws IOException, TooNewException { Material m = (Material)r.restoreMaybeNull(); if (m != null && r.version() < 6 && m.getOwner() != null) { m = (Material)m.clone(); } return m; } private native void nativeSetTexture(int var1, Texture var2); private synchronized void setTexture(int texNum, Texture texture) { if (this.textures[texNum] != null) { Texture t = this.extractTexture(texNum); if (t != null) { t.decRef(); } } this.textures[texNum] = texture; this.nativeSetTexture(texNum, texture); if (!this.doReclump) { this.doReclump = true; Main.register(this); } } @Override public void mainCallback() { Main.unregister(this); if (this.doReclump) { this.propagateTextureChange(); } this.doReclump = false; } private void propagateTextureChange() { if (this.ids != null) { Object o = this.getOwner(); if (o instanceof WObject) { if (o instanceof Surface && ((Surface)o).getMaterial() == this) { ((Surface)o).setMaterial(this, true); } else if (o instanceof Shape && ((Shape)o).getMaterial() == this) { ((Shape)o).setMaterial(this); } else { ((WObject)o).reclump(); } } } this.doReclump = false; } public synchronized void setTexture(Texture texture) { this.textureName = null; if (this.textures != null && this.textures.length != 1) { this.removeTextures(); this.textures = new Texture[1]; this.setTexture(0, texture); } else { if (this.textures == null) { this.textures = new Texture[1]; } else if (texture == this.textures[0]) { return; } this.setTexture(0, texture); } } synchronized native Texture extractTexture(int var1); private void removeTextures() { if (this.textures != null) { for (int i = 0; i < this.textures.length; i++) { Texture t = this.extractTexture(i); if (t != null) { t.decRef(); } } this.textures = null; } this.hRes = this.vRes = 1; this.sPos = -1; this.closeMaterials(); } @Override protected void finalize() { this.removeTextures(); super.finalize(); } private native void closeMaterial(int var1); private void closeMaterials() { if (this.ids != null) { for (int i = 0; i < this.ids.length; i++) { this.closeMaterial(i); } this.ids = null; } } private int calcRes() { this.hRes = 1; this.vRes = 1; this.sPos = -1; if (this.textureName == null) { return -1; } else { String name = this.textureName.getInternal(); int len = name.length(); if (len >= 4 && name.regionMatches(true, len - 4, ".mov", 0, 4)) { this.sPos = 0; } if (len > 7 && name.regionMatches(true, len - 5, "*.", 0, 2)) { int num; int nextStarIndex; for (nextStarIndex = len - 5; nextStarIndex > 2 && name.charAt(nextStarIndex) == '*' && (num = name.charAt(nextStarIndex - 2) - '0') > 0 && num <= 9; nextStarIndex -= 3 ) { char control = Character.toLowerCase(name.charAt(nextStarIndex - 1)); if (control == 'h') { this.hRes = num; } else if (control == 'v') { this.vRes = num; } else if (control == 's' && this.sPos >= 0) { this.sPos = num - 1; } } return len - (nextStarIndex + 1); } else { return -1; } } } private void loadTextures() { int endLen = this.calcRes(); if (endLen >= 0) { String lowResBaseName = this.textureName.getBase(); int baseEnd = lowResBaseName.length() - endLen; lowResBaseName = lowResBaseName.substring(0, baseEnd); int numSubs = this.getHRes() * this.getVRes(); this.textures = new Texture[numSubs]; this.makeMaterials(); if (this.sPos >= 0) { this.subnames = new URL[1]; this.subnames[0] = URL.make(this.textureName, lowResBaseName + ".mov"); BackgroundLoader.get(this, this.subnames[0]); } else { this.subnames = new URL[numSubs]; int nextSubname = 0; for (int v = this.vRes; v > 0; v--) { String vExt = "" + v; for (int h = 0; h < this.hRes; nextSubname++) { URL subname = URL.make(this.textureName, lowResBaseName + vExt + (h + 1) + ".cmp"); this.subnames[nextSubname] = subname; BackgroundLoader.get(this, subname); h++; } } } } else { this.subnames = null; this.textures = new Texture[1]; this.makeMaterials(); BackgroundLoader.get(this, this.textureName); } } public void loadTexture(URL textureName) { boolean vis = this.ids != null; this.removeTextures(); this.textureName = textureName; this.calcRes(); if (vis) { this.addRwChildren(); } Object o = this.getOwner(); if (o instanceof WObject) { ((WObject)o).reclump(); } } private static native int makeMaterial(float var0, float var1, float var2, float var3, int var4, int var5, int var6, boolean var7); private void makeMaterials() { int numSubs = this.getHRes() * this.getVRes(); this.ids = new int[numSubs]; for (int i = 0; i < numSubs; i++) { this.ids[i] = makeMaterial( this.ambient, this.diffuse, this.specular, this.opacity, this.color.getRed(), this.color.getGreen(), this.color.getBlue(), this.smooth ); } } private void loadError(URL name) { SuperRoot owner = this.getOwner(); System.out.println("Unable to load texture " + name + (owner == null ? "" : " for " + owner.getName()) + "."); } public float getAmbient() { return this.ambient; } public float getDiffuse() { return this.diffuse; } public float getSpecular() { return this.specular; } public float getOpacity() { return this.opacity; } public boolean getSmooth() { return this.smooth; } public boolean getFilter() { return this.filter; } public boolean getHiRes() { return this.vRes > 1 || this.hRes > 1; } public int getVRes() { return this.vRes; } public int getHRes() { return this.hRes; } public int getRed() { return this.r; } public int getGreen() { return this.g; } public int getBlue() { return this.b; } public Color getColor() { return this.color; } public native void paramChange(); public void setAmbient(float ambient) { this.ambient = ambient; this.paramChange(); } public void setDiffuse(float diffuse) { this.diffuse = diffuse; this.paramChange(); } public void setSpecular(float specular) { this.specular = specular; this.paramChange(); } public void setOpacity(float opacity) { this.opacity = opacity; this.paramChange(); } public void setSmooth(boolean smooth) { this.smooth = smooth; this.paramChange(); } public void setFilter(boolean filter) { this.filter = filter; this.paramChange(); } public void setColor(Color color) { this.color = color; this.r = color.getRed(); this.g = color.getGreen(); this.b = color.getBlue(); this.paramChange(); } @Override public Object asyncBackgroundLoad(String localName, URL remoteURL) { return localName; } @Override public boolean syncBackgroundLoad(Object obj, URL remoteURL) { int texNum = 0; if (this.textures == null) { return false; } else { String urlString = remoteURL.getAbsolute(); String avatarDir = IniFile.gamma().getIniString("avatarDir", "avatar/"); if (!avatarDir.endsWith("/")) { avatarDir = avatarDir + "/"; } String avStart = URL.make(NetUpdate.getUpgradeServerURL() + avatarDir).getAbsolute(); String remoteBase = remoteURL == null ? null : remoteURL.getBase(); String textureBase = this.textureName == null ? null : this.textureName.getBase(); if (!remoteBase.equals(textureBase)) { if (this.textureName != null && this.textureName.endsWith(".mov")) { String rawBase = this.textureName.getBaseWithoutExt(); String rawRemote = remoteURL.getBaseWithoutExt(); if (!rawBase.startsWith(rawRemote)) { return false; } } else { if (this.subnames == null) { return false; } while (texNum < this.subnames.length) { String subBase = this.subnames[texNum].getBase(); if (remoteBase.equals(subBase)) { break; } texNum++; } if (texNum == this.textures.length) { return false; } } } String localName = (String)obj; if (this.ids == null) { return false; } else { if (localName != null) { if (this.sPos < 0) { Texture t = TextureDecoder.decode(remoteURL, localName); if (t != null && t.textureID != 0) { this.setTexture(texNum, t); } else { localName = null; } } else { Texture[] ts = new ScapePicMovie(localName, remoteURL).getTextures(); if (ts != null && this.hRes * this.vRes * (this.sPos + 1) <= ts.length) { int i = this.hRes * this.vRes * this.sPos; for (int v = (this.vRes - 1) * this.hRes; v >= 0; v -= this.hRes) { for (int h = 0; h < this.hRes; i++) { this.setTexture(v + h, ts[i]); h++; } } } else { localName = null; } } } else { int len = urlString.length(); if (tryBMP && this.sPos == -1 && len > 4 && urlString.regionMatches(true, len - 4, ".cmp", 0, 4) && !remoteURL.isRemote()) { String lName = urlString.substring(0, len - 4) + ".bmp"; Texture t = TextureDecoder.decode(URL.make(lName), lName); if (t != null && t.textureID != 0) { this.setTexture(texNum, t); localName = lName; } } } if (localName == null) { if (urlString.startsWith("avatar:")) { BackgroundLoader.get(this, URL.make(avStart + urlString.substring(7))); return false; } this.loadError(remoteURL); } return false; } } } @Override public Room getBackgroundLoadRoom() { WObject owner = (WObject)this.getOwner(); return owner == null ? null : owner.getRoom(); } @Override public void saveState(Saver s) throws IOException { s.saveVersion(4, classCookie); super.saveState(s); s.saveFloat(this.getAmbient()); s.saveFloat(this.getDiffuse()); s.saveFloat(this.getSpecular()); s.saveFloat(this.getOpacity()); s.saveBoolean(this.getSmooth()); s.saveBoolean(this.getFilter()); s.saveInt(this.getRed()); s.saveInt(this.getGreen()); s.saveInt(this.getBlue()); URL.save(s, this.textureName); s.saveBoolean(this.keepLoaded); if (this.textureName == null) { if (this.textures != null && this.textures.length != 1) { s.saveMaybeNull(null); } else { s.saveMaybeNull(this.textures == null ? null : this.textures[0]); } } } @Override public void restoreState(Restorer r) throws IOException, TooNewException { Texture texture = null; int vers = r.restoreVersion(classCookie); switch (vers) { case 1: super.restoreState(r); case 0: { this.ambient = r.restoreFloat(); this.diffuse = r.restoreFloat(); this.specular = r.restoreFloat(); this.opacity = r.restoreFloat(); int red = r.restoreInt(); int green = r.restoreInt(); int blue = r.restoreInt(); this.setColor(new Color(red, green, blue)); texture = (Texture)r.restoreMaybeNull(); break; } case 2: case 3: case 4: { super.restoreState(r); this.ambient = r.restoreFloat(); this.diffuse = r.restoreFloat(); this.specular = r.restoreFloat(); this.opacity = r.restoreFloat(); if (vers > 3) { this.smooth = r.restoreBoolean(); this.filter = r.restoreBoolean(); } int red = r.restoreInt(); int green = r.restoreInt(); int blue = r.restoreInt(); this.setColor(new Color(red, green, blue)); URL name = URL.restore(r); if (vers > 2) { this.setKeepLoaded(r.restoreBoolean()); } if (name == null) { texture = (Texture)r.restoreMaybeNull(); } else { this.loadTexture(name); } break; } default: throw new TooNewException(); } if (texture != null) { this.textures = new Texture[1]; this.textures[0] = texture; } assert r.version() >= 6 || this.getOwner() == null; } @Override public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { Object ret = null; switch (index - offset) { case 0: if (mode == 0) { ret = new Property(this, index, "Texture").allowSetNull(); } else if (mode == 1) { MaterialTexture mt; if (this.textures != null && this.textures[0] instanceof StringTexture) { mt = new MaterialTexture((StringTexture)this.textures[0]); } else { mt = new MaterialTexture(this.textureName); } this.add(mt); ret = mt; } else if (mode == 2) { if (value == null) { this.loadTexture(null); } else { Console.println(Console.message("Cant-undo-tex")); } } break; case 1: if (mode == 0) { ret = ColorPropertyEditor.make(new Property(this, index, "Color")); } else if (mode == 1) { ret = this.getColor(); } else if (mode == 2) { this.setColor((Color)value); } break; case 2: if (mode == 0) { ret = FloatPropertyEditor.make(new Property(this, index, "Ambient Reflection Coefficient"), 0.0F, 1.0F); } else if (mode == 1) { ret = new Float(this.getAmbient()); } else if (mode == 2) { this.setAmbient((Float)value); } break; case 3: if (mode == 0) { ret = FloatPropertyEditor.make(new Property(this, index, "Diffuse Reflection Coefficient"), 0.0F, 1.0F); } else if (mode == 1) { ret = new Float(this.getDiffuse()); } else if (mode == 2) { this.setDiffuse((Float)value); } break; case 4: if (mode == 0) { ret = FloatPropertyEditor.make(new Property(this, index, "Specular Reflection Coefficient"), 0.0F, 1.0F); } else if (mode == 1) { ret = new Float(this.getSpecular()); } else if (mode == 2) { this.setSpecular((Float)value); } break; case 5: if (mode == 0) { ret = FloatPropertyEditor.make(new Property(this, index, "Opacity"), 0.0F, 1.0F); } else if (mode == 1) { ret = new Float(this.getOpacity()); } else if (mode == 2) { this.setOpacity((Float)value); } break; case 6: if (mode == 0) { ret = BooleanPropertyEditor.make(new Property(this, index, "Smooth"), "No", "Yes"); } else if (mode == 1) { ret = new Boolean(this.getSmooth()); } else if (mode == 2) { this.setSmooth((Boolean)value); } break; case 7: if (mode == 0) { ret = BooleanPropertyEditor.make(new Property(this, index, "Filter"), "No", "Yes"); } else if (mode == 1) { ret = new Boolean(this.getFilter()); } else if (mode == 2) { this.setFilter((Boolean)value); } break; default: ret = super.properties(index, offset + 8, mode, value); } return ret; } @Override public String toString() { return this.getName() + "[" + (this.textureName != null ? this.textureName.toString() : (this.textures == null ? null : this.textures.toString())) + ", " + this.getColor() + ", Ambient " + this.getAmbient() + ", Diffuse " + this.getDiffuse() + ", Specular " + this.getSpecular() + ", Opacity " + this.getOpacity() + ", Smooth " + this.getSmooth() + ", Filter " + this.getFilter() + ", hRes " + this.hRes + ", vRes " + this.vRes + ", loResMode " + false + "]"; } }