diff --git a/java/src/game/gui/Font.java b/java/src/game/gui/Font.java new file mode 100644 index 0000000..225905a --- /dev/null +++ b/java/src/game/gui/Font.java @@ -0,0 +1,106 @@ +package game.gui; + +import java.awt.image.BufferedImage; +import java.io.FileNotFoundException; +import java.io.IOException; + +import game.log.Log; +import game.renderer.GlState; +import game.renderer.texture.TextureUtil; +import game.util.FileUtils; +import game.window.WCF; + +public class Font { + public static final FontChar[] SIZES = new FontChar[256]; + public static final int XGLYPH = 12; + public static final int YGLYPH = 18; + + private static int texture; + + public static void bindTexture() { + GlState.bindTexture(texture); + } + + private static int stride(int width, int height, int x, int y, int c) { + return ((c & 15) * width + x) + (((c >> 4) & 15) * height + y) * (width << 4); // << 2; + } + + private static byte specialChar(int width, int ch) { + return (byte)((ch == Log.CHR_UNK) ? width : ((ch == Log.CHR_SPC) ? (width / 6) : 127)); + } + + private static void calculate(int[] data, FontChar[] glyphs, int width, int height, int page) { + int off; + for(int z = 0; z < 256; z++) { + byte s, t, u, v; + if((u = specialChar(width, (page << 8) + z)) != 127) { + s = t = 0; + v = (byte)(((int)u) * height / width); + if(((page << 8) + z) != Log.CHR_UNK) { + for(int x = 0; x < width; x++) { + for(int y = 0; y < height; y++) { + off = stride(width, height, x, y, z); + data[off/*+3*/] = 0; + } + } + } + glyphs[z] = new FontChar(s, t, u, v); + continue; + } + s = t = 127; + u = v = 0; + for(int x = 0; x < width; x++) { + for(int y = 0; y < height; y++) { + off = stride(width, height, x, y, z); + if((data[off/*+3*/] & 0xff000000) != 0) { + s = x < s ? (byte)x : s; + t = y < t ? (byte)y : t; + u = x > u ? (byte)x : u; + v = y > v ? (byte)y : v; + } + } + } + if(s == 127 && t == 127 && u == 0 && v == 0) { + s = t = 0; + } + else { + u += 1; + v += 1; + } + glyphs[z] = new FontChar(s, t, u, v); + } + } + + public static void load() { + BufferedImage img = null; + try { + img = TextureUtil.readImage(FileUtils.getResource("textures/font.png")); + } + catch(FileNotFoundException e) { + Log.IO.error("Konnte Font-Textur nicht laden: Datei nicht vorhanden"); + } + catch(IOException e) { + Log.IO.error(e, "Konnte Font-Textur nicht laden"); + } + if(img != null && (img.getWidth() != XGLYPH * 16 || img.getHeight() != YGLYPH * 16)) { + Log.IO.error("Konnte Font-Textur nicht laden: Größe ist nicht %dx%d", XGLYPH * 16, YGLYPH * 16); + img = null; + } + if(img == null) + throw new IllegalStateException("Konnte erforderliche Schriftart nicht laden"); + int[] data = new int[XGLYPH * 16 * YGLYPH * 16]; + img.getRGB(0, 0, XGLYPH * 16, YGLYPH * 16, data, 0, XGLYPH * 16); + calculate(data, SIZES, XGLYPH, YGLYPH, 0); + texture = WCF.glGenTextures(); + TextureUtil.uploadImage(texture, img); + Log.RENDER.debug("Font-Textur wurde mit ID #%d geladen", texture); + } + + public static void unload() { + if(texture != 0) { + WCF.glDeleteTextures(texture); + Log.RENDER.debug("Font-Textur mit ID #%d wurde gelöscht", texture); + texture = 0; + } + } +} diff --git a/java/src/game/gui/FontChar.java b/java/src/game/gui/FontChar.java new file mode 100644 index 0000000..74a4d7e --- /dev/null +++ b/java/src/game/gui/FontChar.java @@ -0,0 +1,15 @@ +package game.gui; + +public class FontChar { + public final byte s; + public final byte t; + public final byte u; + public final byte v; + + public FontChar(byte s, byte t, byte u, byte v) { + this.s = s; + this.t = t; + this.u = u; + this.v = v; + } +} diff --git a/java/src/game/gui/Gui.java b/java/src/game/gui/Gui.java new file mode 100644 index 0000000..d1c9403 --- /dev/null +++ b/java/src/game/gui/Gui.java @@ -0,0 +1,362 @@ +package game.gui; + +import java.util.List; + +import game.Game; +import game.collect.Lists; +import game.gui.element.Dropdown; +import game.gui.element.Element; +import game.gui.element.Dropdown.Handle; +import game.renderer.DefaultVertexFormats; +import game.renderer.Drawing; +import game.renderer.GlState; +import game.renderer.RenderBuffer; +import game.renderer.Tessellator; +import game.vars.CVar; +import game.vars.ColorVar; +import game.window.Bind; +import game.window.Button; +import game.window.Keysym; +import game.window.WCF; + +public abstract class Gui { + public static final String DIRT_BACKGROUND = "textures/background.png"; + + protected final Game gm = Game.getGame(); + + public Element selected; + private int min_x; + private int min_y; + private int max_x; + private int max_y; + public final List elems = Lists.newArrayList(); + + public abstract void init(int width, int height); + public abstract String getTitle(); + + public void updateScreen() { + } + + public void onGuiClosed() { + } + + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + } + + public void mouseReleased(int mouseX, int mouseY, int state) { + } + + public void mouseDragged(int mouseX, int mouseY) { + } + + public void drawPost() { + } + + public void drawGuiContainerForegroundLayer() { + } + + public void drawGuiContainerBackgroundLayer() { + } + + public void drawOverlays() { + } + + public void useHotbar(int slot) { + } + + public void dropItem() { + } + + public void drawBackground() { + + } + + public Element clicked(int x, int y) { + if(this.selected != null && this.selected.visible && (this.selected instanceof Handle) && this.selected.inside(x, y)) + return this.selected; // fix (?) + for(Element elem : this.elems) { + if(elem.visible && elem.enabled && elem.inside(x, y)) + return elem; + } + return null; + } + + public void reformat() { + for(Element elem : this.elems) { + elem.reformat(); + } + } + + public void deselect() { + if(this.selected != null && !(this.selected instanceof Handle)) { + this.selected.deselect(); + this.selected = null; + } + } + + public void select(Element elem) { + if(this.selected != elem && !(this.selected instanceof Handle) && !(elem instanceof Handle)) { + if(this.selected != null) + this.selected.deselect(); + if(elem != null) + elem.select(); + this.selected = elem; + } + } + + public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) { + int prev; + Element elem = this.clicked(x, y); + if(this.selected != null && this.selected != elem && this.selected instanceof Handle) { + this.selected.deselect(); + return; + } + else if(this.selected != elem) { + if(this.selected != null) + this.selected.deselect(); + if(elem != null) + elem.select(); + this.selected = elem; + } + if(elem != null) + elem.mouse(btn, x, y, ctrl, shift); + } + + public void mouserel(Button btn, int x, int y) { + if(this.selected != null) + this.selected.mouserel(); + } + + public void drag(int x, int y) { + if(this.selected != null && (Button.MOUSE_LEFT.isDown() || Button.MOUSE_RIGHT.isDown())) + this.selected.drag(x, y); + } + + public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) { + Element elem = this.clicked(x, y); + if(elem != null) + elem.scroll(scr_x, scr_y, x, y, ctrl, shift); + } + + public void key(Keysym key, boolean ctrl, boolean shift) { + if(this.selected != null) + this.selected.key(key, ctrl, shift); + } + + public void character(char code) { + if(this.selected != null) + this.selected.character(code); + } + + protected void shift() { + if(this.gm.fb_x != 0 && this.gm.fb_y != 0) { + int shift_x = (this.gm.fb_x - (this.max_x - this.min_x)) / 2 - this.min_x; + int shift_y = (this.gm.fb_y - (this.max_y - this.min_y)) / 2 - this.min_y; + for(Element elem : this.elems) { + elem.shift(shift_x, shift_y); + } + } + } + + public void init() { + this.selected = null; + this.min_x = this.min_y = Integer.MAX_VALUE; + this.max_x = this.max_y = Integer.MIN_VALUE; + this.elems.clear(); + this.init(this.gm.fb_x, this.gm.fb_y); + } + + public void update() { + if(this.selected != null) + this.selected.update(); + } + + protected T add(T elem) { + this.elems.add(elem); + elem.setGui(this); + this.min_x = Math.min(this.min_x, elem.getX()); + this.min_y = Math.min(this.min_y, elem.getY()); + this.max_x = Math.max(this.max_x, elem.getX() + elem.getWidth()); + this.max_y = Math.max(this.max_y, elem.getY() + elem.getHeight()); + if(elem instanceof Dropdown) + this.add(((Dropdown)elem).getHandle()); + return elem; + } + + protected Element addSelector(String cvar, int x, int y, int w, int h) { + CVar cv = this.gm.getVar(cvar); + if(cv instanceof ColorVar) { + ColorVar color = (ColorVar)cv; + if(!color.getDisplay().isEmpty()) + this.add(color.label(x, y - 20, w, 20)); + return this.add(color.editor(x, y, w, h)); + } + return this.add(cv.selector(x, y, w, h)); + } + + public void draw() { + if(this.selected != null && /* this.selected.r_dirty && */ this.selected instanceof Handle && !this.selected.visible) { + this.selected = null; + } + for(Element elem : this.elems) { + if(/* this.selected != e || */ !(elem instanceof Handle)) // || !e.visible) + elem.draw(); + } + if(this.selected != null && /* elem.r_dirty && */ this.selected instanceof Handle && this.selected.visible) { + this.selected.draw(); + } + } + + public void drawOverlay() { + Element elem = this.selected; + if(Button.isMouseDown() && elem != null && elem.enabled && elem.visible && elem.canClick()) { + elem.drawPress(); + return; + } + if(elem != null && elem.enabled && elem.visible) + elem.drawOverlay(); + elem = this.clicked(this.gm.mouse_x, this.gm.mouse_y); + if(elem != null && elem.enabled && elem.visible && elem.canHover()) + elem.drawHover(); + } + + public static void drawRect(int left, int top, int right, int bottom, int color) + { + if (left < right) + { + int i = left; + left = right; + right = i; + } + + if (top < bottom) + { + int j = top; + top = bottom; + bottom = j; + } + + float f3 = (float)(color >> 24 & 255) / 255.0F; + float f = (float)(color >> 16 & 255) / 255.0F; + float f1 = (float)(color >> 8 & 255) / 255.0F; + float f2 = (float)(color & 255) / 255.0F; + RenderBuffer worldrenderer = Tessellator.getBuffer(); + GlState.enableBlend(); + GlState.disableTexture2D(); + GlState.tryBlendFuncSeparate(770, 771, 1, 0); + GlState.color(f, f1, f2, f3); + worldrenderer.begin(7, DefaultVertexFormats.POSITION); + worldrenderer.pos((double)left, (double)bottom, 0.0D).endVertex(); + worldrenderer.pos((double)right, (double)bottom, 0.0D).endVertex(); + worldrenderer.pos((double)right, (double)top, 0.0D).endVertex(); + worldrenderer.pos((double)left, (double)top, 0.0D).endVertex(); + Tessellator.draw(); + GlState.enableTexture2D(); + GlState.disableBlend(); + } + + public static void drawTexturedModalRect(int x, int y, int textureX, int textureY, int width, int height) + { + float f = 0.00390625F; + float f1 = 0.00390625F; + RenderBuffer worldrenderer = Tessellator.getBuffer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer.pos((double)(x + 0), (double)(y + height), 0.0D).tex((double)((float)(textureX + 0) * f), (double)((float)(textureY + height) * f1)).endVertex(); + worldrenderer.pos((double)(x + width), (double)(y + height), 0.0D).tex((double)((float)(textureX + width) * f), (double)((float)(textureY + height) * f1)).endVertex(); + worldrenderer.pos((double)(x + width), (double)(y + 0), 0.0D).tex((double)((float)(textureX + width) * f), (double)((float)(textureY + 0) * f1)).endVertex(); + worldrenderer.pos((double)(x + 0), (double)(y + 0), 0.0D).tex((double)((float)(textureX + 0) * f), (double)((float)(textureY + 0) * f1)).endVertex(); + Tessellator.draw(); + } + + public static void drawScaledCustomSizeModalRect(int x, int y, float u, float v, int uWidth, int vHeight, int width, int height, float tileWidth, float tileHeight) + { + float f = 1.0F / tileWidth; + float f1 = 1.0F / tileHeight; + RenderBuffer worldrenderer = Tessellator.getBuffer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer.pos((double)x, (double)(y + height), 0.0D).tex((double)(u * f), (double)((v + (float)vHeight) * f1)).endVertex(); + worldrenderer.pos((double)(x + width), (double)(y + height), 0.0D).tex((double)((u + (float)uWidth) * f), (double)((v + (float)vHeight) * f1)).endVertex(); + worldrenderer.pos((double)(x + width), (double)y, 0.0D).tex((double)((u + (float)uWidth) * f), (double)(v * f1)).endVertex(); + worldrenderer.pos((double)x, (double)y, 0.0D).tex((double)(u * f), (double)(v * f1)).endVertex(); + Tessellator.draw(); + } + + public static void drawGradientRect(int left, int top, int right, int bottom, int startColor, int endColor) + { + float f = (float)(startColor >> 24 & 255) / 255.0F; + float f1 = (float)(startColor >> 16 & 255) / 255.0F; + float f2 = (float)(startColor >> 8 & 255) / 255.0F; + float f3 = (float)(startColor & 255) / 255.0F; + float f4 = (float)(endColor >> 24 & 255) / 255.0F; + float f5 = (float)(endColor >> 16 & 255) / 255.0F; + float f6 = (float)(endColor >> 8 & 255) / 255.0F; + float f7 = (float)(endColor & 255) / 255.0F; + GlState.disableTexture2D(); + GlState.enableBlend(); + GlState.disableAlpha(); + GlState.tryBlendFuncSeparate(770, 771, 1, 0); + GlState.shadeModel(7425); + RenderBuffer worldrenderer = Tessellator.getBuffer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_COLOR); + worldrenderer.pos((double)right, (double)top, 0.0).color(f1, f2, f3, f).endVertex(); + worldrenderer.pos((double)left, (double)top, 0.0).color(f1, f2, f3, f).endVertex(); + worldrenderer.pos((double)left, (double)bottom, 0.0).color(f5, f6, f7, f4).endVertex(); + worldrenderer.pos((double)right, (double)bottom, 0.0).color(f5, f6, f7, f4).endVertex(); + Tessellator.draw(); + GlState.shadeModel(7424); + GlState.disableBlend(); + GlState.enableAlpha(); + GlState.enableTexture2D(); + } + + public void drawMainBackground() { + if(this.gm.theWorld != null) { +// Drawing.drawGradient(0, 0, this.fb_x, this.fb_y, this.theWorld == null ? this.style.bg_top : 0x3f202020, +// this.theWorld == null ? this.style.bg_btm : 0x3f000000); + Drawing.drawGradient(0, 0, this.gm.fb_x, this.gm.fb_y, 0xc0101010, 0xd0101010); + } + else { + this.drawDirtBackground(0, 0, this.gm.fb_x, this.gm.fb_y); + } + } + + public void drawDirtBackground(double x, double y, double width, double height) { + GlState.enableTexture2D(); + GlState.disableLighting(); + GlState.disableFog(); + RenderBuffer buf = Tessellator.getBuffer(); + this.gm.getTextureManager().bindTexture(DIRT_BACKGROUND); + GlState.color(1.0F, 1.0F, 1.0F, 1.0F); + double scale = 32.0; + buf.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + buf.pos(x, y + height, 0.0D).tex(0.0D, height / scale) + .color(64, 64, 64, 255).endVertex(); + buf.pos(x + width, y + height, 0.0D) + .tex(width / scale, height / scale) + .color(64, 64, 64, 255).endVertex(); + buf.pos(x + width, y, 0.0D).tex(width / scale, 0.0) + .color(64, 64, 64, 255).endVertex(); + buf.pos(x, y, 0.0D).tex(0.0D, 0.0) + .color(64, 64, 64, 255).endVertex(); + Tessellator.draw(); + GlState.disableTexture2D(); + } + + public void render() { + this.drawMainBackground(); + this.drawBackground(); + if(this.gm.fb_x != 0 && this.gm.fb_y != 0) + this.draw(); + this.drawGuiContainerBackgroundLayer(); + this.drawGuiContainerForegroundLayer(); + GlState.bindTexture(0); + GlState.setActiveTexture(WCF.GL_TEXTURE0); + GlState.enableTexture2D(); + GlState.disableDepth(); + this.drawPost(); + GlState.disableDepth(); + this.drawOverlays(); + if(Bind.isWindowActive()) + this.drawOverlay(); + } +} diff --git a/java/src/game/gui/GuiBinds.java b/java/src/game/gui/GuiBinds.java new file mode 100644 index 0000000..169037c --- /dev/null +++ b/java/src/game/gui/GuiBinds.java @@ -0,0 +1,74 @@ +package game.gui; + +import game.color.TextColor; +import game.gui.element.ActButton; +import game.gui.element.Label; +import game.gui.element.ActButton.Mode; +import game.util.Formatter; +import game.window.Bind; + +public class GuiBinds extends GuiOptions { + protected GuiBinds() { + } + + public void init(int width, int height) { + int y = 0; + int x = 0; + for(Bind bind : Bind.values()) { + this.add(new Label(10 + x * 190, 80 + y * 50, 180, 20, bind.getDisplay())); + this.add(new ActButton(10 + x * 190, 100 + y * 50, 180, 24, new ActButton.Callback() { + public void use(ActButton elem, Mode action) { + if(action == Mode.SECONDARY) { + if(!bind.isDefault()) { + bind.setDefault(); + GuiBinds.this.gm.setDirty(); + GuiBinds.this.reformat(); + } + } + else if(action == Mode.TERTIARY) { + if(bind.getInput() != null) { + bind.setInput(null); + GuiBinds.this.gm.setDirty(); + GuiBinds.this.reformat(); + } + } + else { + Bind.disableInput(bind); + } + } + }, new Formatter() { + public String use(ActButton elem) { + if(bind == Bind.getWaiting()) + return /* TextColor.BLINK + "" + */ TextColor.BLUE + "***"; + else + return (bind.isDupe() ? TextColor.RED : TextColor.YELLOW) + (bind.getInput() == null ? "---" : bind.getInput().getDisplay()); + } + })); + if(++x == 5) { + x = 0; + y++; + } + } + y += x != 0 ? 1 : 0; + this.add(new ActButton(200, 100 + y * 50, 560, 24, new ActButton.Callback() { + public void use(ActButton elem, Mode action) { + boolean flag = false; + for(Bind bind : Bind.values()) { + flag |= !bind.isDefault(); + bind.setDefault(); + } + if(flag) { + GuiBinds.this.gm.setDirty(); + GuiBinds.this.reformat(); + } + } + }, "Zurücksetzen")); + this.addSelector("phy_sensitivity", 30, 160 + y * 50, 440, 24); + this.addSelector("gui_dclick_delay", 490, 160 + y * 50, 440, 24); + super.init(width, height); + } + + public String getTitle() { + return "Tastenbelegung und Maus"; + } +} diff --git a/java/src/game/gui/GuiConnect.java b/java/src/game/gui/GuiConnect.java new file mode 100644 index 0000000..8295c23 --- /dev/null +++ b/java/src/game/gui/GuiConnect.java @@ -0,0 +1,106 @@ +package game.gui; + +import game.color.TextColor; +import game.gui.element.ActButton; +import game.gui.element.Label; +import game.gui.element.Textbox; +import game.gui.element.Textbox.Action; +import game.network.NetHandlerPlayServer; + +public class GuiConnect extends Gui implements Textbox.Callback { + public static final GuiConnect INSTANCE = new GuiConnect(); + + private GuiConnect() { + } + + private Textbox addrBox; + private Textbox portBox; + private Textbox userBox; + private Textbox passBox; + private Textbox accBox; + private Label addrLabel; + private Label portLabel; + private Label userLabel; + private Label passLabel; + private Label accLabel; + + public void init(int width, int height) { + this.addrBox = this.add(new Textbox(0, 20, 410, 24, 128, true, this, "")); + this.portBox = this.add(new Textbox(414, 20, 66, 24, 5, true, this, "")); + this.userBox = this.add(new Textbox(0, 70, 220, 24, NetHandlerPlayServer.MAX_USER_LENGTH, true, this, NetHandlerPlayServer.VALID_USER, "")); + this.passBox = this.add(new Textbox(0, 120, 480, 24, NetHandlerPlayServer.MAX_PASS_LENGTH, true, this, "")); + this.accBox = this.add(new Textbox(0, 170, 480, 24, NetHandlerPlayServer.MAX_PASS_LENGTH, true, this, "")); + this.add(new ActButton(0, 220, 480, 24, new ActButton.Callback() { + public void use(ActButton elem, ActButton.Mode action) { + GuiConnect.this.connect(); + } + }, "Verbinden")); + this.add(new ActButton(0, 250, 480, 24, new ActButton.Callback() { + public void use(ActButton elem, ActButton.Mode action) { + GuiConnect.this.gm.displayGuiScreen(GuiMenu.INSTANCE); + } + }, "Zurück")); + this.addrLabel = this.add(new Label(0, 0, 410, 20, "Adresse", true)); + this.portLabel = this.add(new Label(414, 0, 66, 20, "Port", true)); + this.userLabel = this.add(new Label(0, 50, 220, 20, "Nutzer", true)); + this.passLabel = this.add(new Label(0, 100, 480, 20, "Passwort", true)); + this.accLabel = this.add(new Label(0, 150, 480, 20, "Zugang", true)); + this.shift(); + } + + public String getTitle() { + return "Mit Server verbinden"; + } + + private void connect() { + if(this.gm.theWorld != null) + return; + String addr = this.addrBox.getText(); + if(addr.isEmpty()) { + this.addrLabel.setText(TextColor.RED + "Adresse"); + return; + } + int port = -1; + if(this.portBox.getText().isEmpty()) { + port = 26666; + } + else { + try { + port = Integer.parseInt(this.portBox.getText()); + } + catch(NumberFormatException e) { + } + if(port < 0 || port > 65535) { + this.portLabel.setText(TextColor.RED + "Port"); + return; + } + } + String user = this.userBox.getText(); + if(user.isEmpty()) { + this.userLabel.setText(TextColor.RED + "Nutzer"); + return; + } + String pass = this.passBox.getText(); + String acc = this.accBox.getText(); + this.gm.connect(addr, port, user, pass, acc); + } + + public void use(Textbox elem, Action value) { + if(value == Action.SEND) { + elem.setDeselected(); + this.connect(); + } + else if(value == Action.FOCUS) { + if(elem == this.addrBox) + this.addrLabel.setText("Adresse"); + else if(elem == this.portBox) + this.portLabel.setText("Port"); + else if(elem == this.userBox) + this.userLabel.setText("Nutzer"); + } + } + +// public void updateScreen() { +// +// } +} diff --git a/java/src/game/gui/GuiConsole.java b/java/src/game/gui/GuiConsole.java new file mode 100644 index 0000000..2ab9c10 --- /dev/null +++ b/java/src/game/gui/GuiConsole.java @@ -0,0 +1,311 @@ +package game.gui; + +import java.util.List; + +import game.collect.Lists; +import game.gui.element.ActButton; +import game.gui.element.Fill; +import game.gui.element.Textbox; +import game.gui.element.TransparentBox; +import game.gui.element.Textbox.Action; +import game.log.Log; +import game.network.NetHandlerPlayServer; +import game.packet.CPacketComplete; +import game.util.ExtMath; +import game.window.Keysym; + +public class GuiConsole extends Gui implements Textbox.Callback { + public static final GuiConsole INSTANCE = new GuiConsole(); + + private final List sentMessages = Lists.newArrayList(); + + private String historyBuffer = ""; + private int sentHistoryCursor = -1; + private boolean playerNamesFound; + private boolean waitingOnAutocomplete; + private int autocompleteIndex; + private List foundPlayerNames = Lists.newArrayList(); + private Textbox inputField; + private TransparentBox logBox; + + public void init(int width, int height) { + this.addSelector("con_autoclose", 0, 0, 160, 24); + this.addSelector("con_timestamps", 160, 0, 160, 24); + this.addSelector("con_loglevel", 320, 0, 160, 24); + this.add(new ActButton(480, 0, 160, 24, new ActButton.Callback() { + public void use(ActButton elem, ActButton.Mode action) { + GuiConsole.this.reset(); + GuiConsole.this.setLog(GuiConsole.this.gm.getBuffer()); + } + }, "Löschen")); + this.logBox = this.add(new TransparentBox(0, 24, width, height - 48, this.gm.getBuffer())); + this.add(new Fill(640, 0, width - 640, 24)); + this.inputField = this.add(new Textbox(0, height - 24, width, 24, NetHandlerPlayServer.MAX_CMD_LENGTH, true, this, "")); + this.inputField.setSelected(); + this.sentHistoryCursor = this.sentMessages.size(); + } + + public String getTitle() { + return "Konsole / Chat"; + } + + public void reset() { + this.gm.reset(); + this.sentMessages.clear(); + this.sentHistoryCursor = -1; + } + + public void setLog(String buffer) { + if(this.logBox != null) + this.logBox.setText(buffer); + } + + public void drawMainBackground() { + if(this.gm.theWorld == null) + super.drawMainBackground(); + } + + public void key(Keysym key, boolean ctrl, boolean shift) { + super.key(key, ctrl, shift); +// this.waitingOnAutocomplete = false; + if(key != Keysym.TAB) + this.playerNamesFound = false; + } + + public void use(Textbox elem, Action value) + { + this.waitingOnAutocomplete = false; + + if ((value == Action.FORWARD || value == Action.BACKWARD) && this.gm.thePlayer != null) + { + this.autocompletePlayerNames(); + } + else + { + this.playerNamesFound = false; + } + + if(value == Action.PREVIOUS) + this.getSentHistory(-1); + else if (value == Action.NEXT) + this.getSentHistory(1); + if(value == Action.SEND) + { + String s = this.inputField.getText().trim(); + + if (s.length() > 0) + { + if(this.sentMessages.isEmpty() || !((String)this.sentMessages.get(this.sentMessages.size() - 1)).equals(s)) + this.sentMessages.add(s); + this.gm.exec(s); +// if(this.gm.thePlayer != null) +// this.gm.thePlayer.sendQueue.addToSendQueue(new CPacketMessage(CPacketMessage.Type.CHAT, s)); + } + + this.inputField.setText(""); + if(this.gm.conAutoclose && this.gm.theWorld != null) + this.gm.displayGuiScreen(null); + } + } + + protected void setText(String newChatText, boolean shouldOverwrite) + { + if (shouldOverwrite) + { + this.inputField.setText(newChatText); + } + else + { + this.inputField.insertText(newChatText); + } + } + + public void autocompletePlayerNames() + { + if (this.playerNamesFound) + { + this.inputField.deleteFromCursor(); + + if (this.autocompleteIndex >= this.foundPlayerNames.size()) + { + this.autocompleteIndex = 0; + } + } + else + { + int i = this.inputField.getNthCharFromPos(); + this.foundPlayerNames.clear(); + this.autocompleteIndex = 0; + String s = this.inputField.getText().substring(i).toLowerCase(); + String s1 = this.inputField.getText().substring(0, this.inputField.getCursorPosition()); + this.sendAutocompleteRequest(s1, s); + + if (this.foundPlayerNames.isEmpty()) + { + return; + } + + this.playerNamesFound = true; + this.inputField.deleteFromCursor(); + } + + if (this.foundPlayerNames.size() > 1) + { + StringBuilder stringbuilder = new StringBuilder(); + + for (String s2 : this.foundPlayerNames) + { + if (stringbuilder.length() > 0) + { + stringbuilder.append(", "); + } + + stringbuilder.append(s2); + } + + Log.CONSOLE.user(stringbuilder.toString()); + } + + this.inputField.insertText((String)this.foundPlayerNames.get(this.autocompleteIndex++)); + } + + private void sendAutocompleteRequest(String currentText, String newText) + { + if (currentText.length() >= 1) + { +// BlockPos blockpos = null; +// int eid = -1; +// +// if (this.gm.pointed != null && this.gm.pointed.type == HitPosition.ObjectType.BLOCK) +// { +// blockpos = this.gm.pointed.block; +// } +// else if (this.gm.pointed != null && this.gm.pointed.type == HitPosition.ObjectType.ENTITY) +// { +// eid = this.gm.pointed.entity.getId(); +// } + + this.gm.thePlayer.sendQueue.addToSendQueue(new CPacketComplete(currentText)); + this.waitingOnAutocomplete = true; + } + } + + private void getSentHistory(int msgPos) + { + int i = this.sentHistoryCursor + msgPos; + int j = this.sentMessages.size(); + i = ExtMath.clampi(i, 0, j); + + if (i != this.sentHistoryCursor) + { + if (i == j) + { + this.sentHistoryCursor = j; + this.inputField.setText(this.historyBuffer); + } + else + { + if (this.sentHistoryCursor == j) + { + this.historyBuffer = this.inputField.getText(); + } + + this.inputField.setText(this.sentMessages.get(i)); + this.sentHistoryCursor = i; + } + } + } + + public void onAutocompleteResponse(String[] choices) + { + if (this.waitingOnAutocomplete) + { + this.playerNamesFound = false; + this.foundPlayerNames.clear(); + + for (String s : choices) + { + if (s.length() > 0) + { + this.foundPlayerNames.add(s); + } + } + + String s1 = this.inputField.getText().substring(this.inputField.getNthCharFromPos()); + String s2 = getCommonPrefix(choices); + + if (s2.length() > 0 && !s1.equalsIgnoreCase(s2)) + { + this.inputField.deleteFromCursor(); + this.inputField.insertText(s2); + } + else if (this.foundPlayerNames.size() > 0) + { + this.playerNamesFound = true; + this.autocompletePlayerNames(); + } + } + } + + private static String getCommonPrefix(String[] strs) { + if (strs != null && strs.length != 0) { + int smallestIndexOfDiff = indexOfDifference(strs); + if (smallestIndexOfDiff == -1) { + return strs[0] == null ? "" : strs[0]; + } else { + return smallestIndexOfDiff == 0 ? "" : strs[0].substring(0, smallestIndexOfDiff); + } + } else { + return ""; + } + } + + private static int indexOfDifference(CharSequence[] css) { + if (css != null && css.length > 1) { + boolean anyStringNull = false; + boolean allStringsNull = true; + int arrayLen = css.length; + int shortestStrLen = Integer.MAX_VALUE; + int longestStrLen = 0; + + int firstDiff; + for (firstDiff = 0; firstDiff < arrayLen; ++firstDiff) { + if (css[firstDiff] == null) { + anyStringNull = true; + shortestStrLen = 0; + } else { + allStringsNull = false; + shortestStrLen = Math.min(css[firstDiff].length(), shortestStrLen); + longestStrLen = Math.max(css[firstDiff].length(), longestStrLen); + } + } + + if (allStringsNull || longestStrLen == 0 && !anyStringNull) { + return -1; + } else if (shortestStrLen == 0) { + return 0; + } else { + firstDiff = -1; + + for (int stringPos = 0; stringPos < shortestStrLen; ++stringPos) { + char comparisonChar = css[0].charAt(stringPos); + + for (int arrayPos = 1; arrayPos < arrayLen; ++arrayPos) { + if (css[arrayPos].charAt(stringPos) != comparisonChar) { + firstDiff = stringPos; + break; + } + } + + if (firstDiff != -1) { + break; + } + } + + return firstDiff == -1 && shortestStrLen != longestStrLen ? shortestStrLen : firstDiff; + } + } else { + return -1; + } + } +} diff --git a/java/src/game/gui/GuiDisplay.java b/java/src/game/gui/GuiDisplay.java new file mode 100644 index 0000000..6352dd9 --- /dev/null +++ b/java/src/game/gui/GuiDisplay.java @@ -0,0 +1,70 @@ +package game.gui; + +import game.color.TextColor; +import game.gui.element.Dropdown; +import game.gui.element.Fill; +import game.gui.element.Slider; +import game.util.Formatter; +import game.window.DisplayMode; +import game.window.WCF; + +public class GuiDisplay extends GuiOptions { + protected GuiDisplay() { + } + + public void init(int width, int height) { + DisplayMode[] dmodes = WCF.getDisplayModes(); + if(dmodes != null && dmodes.length > 0) { + int offset = 0; + int pos = 0; + int num = dmodes.length; + if(dmodes.length > DisplayMode.VID_MODES) { + offset = dmodes.length - DisplayMode.VID_MODES; + num = DisplayMode.VID_MODES; + } + DisplayMode[] modes = new DisplayMode[num]; + DisplayMode selected = dmodes[num + offset - 1]; + for(int z = 0; z < num; z++) { + modes[z] = dmodes[z + offset]; + if(modes[z].equals(this.gm.vidMode)) + selected = modes[z]; + } + this.add(new Dropdown(30, 80, 440, 24, false, modes, modes[modes.length - 1], selected, new Dropdown.Callback() { + public void use(Dropdown elem, DisplayMode value) { + GuiDisplay.this.gm.vidMode = value; + } + }, "Auflösung")); + } + else { + this.add(new Fill(30, 80, 440, 24, TextColor.RED + "Auflösung: ")); + } + + this.add(new Slider(30, 120, 440, 24, 0, 0, 360 - 8, 0, (this.gm.sync < 0) ? (360 - 8) : (this.gm.sync != 0 ? ((this.gm.sync < 10) ? 1 : (this.gm.sync - 9)) : 0), new Slider.Callback() { + public void use(Slider elem, int value) { + GuiDisplay.this.gm.getVar("win_sync").parse("" + ((value > 0 && value < 360 - 8) ? (value + 9) : (value != 0 ? -1 : 0))); + GuiDisplay.this.gm.setDirty(); + } + }, new Formatter() { + public String use(Slider elem) { + int value = elem.getValue(); + return "Max. Bildrate: " + (value > 0 && value < (360 - 8) ? (value + 9) + " FPS" : (value != 0 ? "Unbegrenzt" : "VSync")); + } + })); + this.addSelector("gl_vsync_flush", 490, 120, 440, 24); + + this.addSelector("con_overlay", 30, 200, 440, 24); + this.addSelector("con_opacity", 490, 200, 440, 24); + this.addSelector("con_size", 30, 240, 440, 24); + this.addSelector("con_fadeout", 490, 240, 440, 24); + this.addSelector("con_position", 30, 280, 440, 24); + + this.addSelector("gl_fov", 30, 360, 440, 24); + this.addSelector("chunk_view_distance", 30, 400, 440, 24); + this.addSelector("chunk_build_time", 490, 400, 440, 24); + super.init(width, height); + } + + public String getTitle() { + return "Grafik und Anzeige"; + } +} diff --git a/java/src/game/gui/GuiInfo.java b/java/src/game/gui/GuiInfo.java new file mode 100644 index 0000000..f8cf892 --- /dev/null +++ b/java/src/game/gui/GuiInfo.java @@ -0,0 +1,55 @@ +package game.gui; + +import game.color.TextColor; +import game.gui.element.ActButton; +import game.gui.element.TransparentBox; +import game.init.Config; + +public class GuiInfo extends Gui { + private static final String INFO = + TextColor.GREEN + "" + TextColor.BUG + "" + TextColor.BUG + "" + TextColor.BUG + " " + TextColor.VIOLET + "" + Config.VERSION + "" + + TextColor.GREEN + " " + TextColor.BUG + "" + TextColor.BUG + "" + TextColor.BUG + "\n" + + "\n" + + TextColor.LGRAY + "Ein kleine Anwendung zur Simulation, zum Testen, für Spiele, Musik und vieles" + "\n" + + "mehr. Optimiert für Geschwindigkeit, Stabilität und" + TextColor.UNKNOWN + "" + TextColor.UNKNOWN + " [Speicherzugriffsfehler]" + "\n" + + "\n" + + TextColor.CYAN + "Geschrieben von Sen dem \"kleinen\" Dämonen " + TextColor.CRIMSON + TextColor.DEMON + TextColor.BLACK + TextColor.BLKHEART + "\n" + + "\n" + + TextColor.YELLOW + "Verwendete Programmbibliotheken:" + "\n" + + TextColor.LGRAY + " -> " + TextColor.NEON + "axe_ork (Modifiziert: GLFW 3.3.8)" + "\n" + + TextColor.LGRAY + " -> " + TextColor.NEON + "opl3 (Modifiziert: Nuked-OPL3 f2c9873)" + "\n" + + TextColor.LGRAY + " -> " + TextColor.NEON + "nionet (Modifiziert: Netty 4.0.23-Final)" + "\n" + + TextColor.LGRAY + " -> " + TextColor.NEON + "collectutil + futureutil (Modifiziert: Guava 17.0)" + "\n" + + TextColor.LGRAY + " -> " + TextColor.NEON + "tjglu (Modifiziert: LWJGL 2.9.4-nightly-20150209)" + "\n" + +// "\n" + +// TextColor.YELLOW + "Verwendeter Compiler: " + "\n" + +// TextColor.LGRAY + " -> " + TextColor.NEON + BUILD_COMP + "\n" + +// "\n" + +// TextColor.YELLOW + "Kompiliert auf System: " + "\n" + +// TextColor.LGRAY + " -> " + TextColor.NEON + BUILD_SYS + "\n" + + "\n" + + "\n" + + TextColor.BLACK + "#0 " + TextColor.DGRAY + "#1 " + TextColor.GRAY + "#2 " + TextColor.LGRAY + "#3 " + TextColor.WHITE + "#4 " + TextColor.RED + "#5 " + TextColor.GREEN + "#6 " + + TextColor.BLUE + "#7 " + TextColor.YELLOW + "#8 " + TextColor.MAGENTA + "#9 " + TextColor.CYAN + "#A " + TextColor.VIOLET + "#B " + TextColor.ORANGE + "#C " + TextColor.CRIMSON + "#D " + + TextColor.MIDNIGHT + "#E " + TextColor.NEON + "#F " + TextColor.BROWN + "#G " + TextColor.DBROWN + "#H " + TextColor.DGREEN + "#I " + TextColor.DRED + "#J " + TextColor.DMAGENTA + "#K " + + TextColor.DVIOLET + "#L " + TextColor.ORK + "#M " + TextColor.ACID + "#N "; + + public static final GuiInfo INSTANCE = new GuiInfo("Über dieses Programm", INFO); + + private final String header; + private final String info; + + public GuiInfo(String header, String info) { + this.header = header; + this.info = info; + } + + public void init(int width, int height) { + this.add(new TransparentBox(0, 0, width, height - 24, this.info)); + this.add(new ActButton(0, height - 24, width, 24, GuiMenu.INSTANCE, "Zurück")); + } + + public String getTitle() { + return this.header; + } +} diff --git a/java/src/game/gui/GuiMenu.java b/java/src/game/gui/GuiMenu.java new file mode 100644 index 0000000..196b50e --- /dev/null +++ b/java/src/game/gui/GuiMenu.java @@ -0,0 +1,280 @@ +package game.gui; + +import game.color.TextColor; +import game.gui.element.ActButton; +import game.gui.element.Label; +import game.gui.element.Textbox; +import game.gui.element.Textbox.Action; +import game.gui.world.GuiWorlds; +import game.init.Config; +import game.renderer.Drawing; +import game.rng.Random; +import game.util.Splashes; +import game.util.Timing; +import game.window.Keysym; + +public class GuiMenu extends Gui { + public static final GuiMenu INSTANCE = new GuiMenu(); + + private GuiMenu() { + } + + public void drawMainBackground() { + if(this.gm.theWorld != null) + super.drawMainBackground(); + else + this.gm.renderGlobal.renderStarField(this.gm.fb_x, this.gm.fb_y, 0x000000, 0xffffff, (float)this.ticks + (float)Timing.tick_fraction, this.rand); + } + + private final Random rand = new Random(); + + private Label splashLabel; + + private int ticks; + private int hacked; + + private int animWidth = 32; + private int animGrowth = 10; + private int[] animGrow = new int[this.animWidth]; + private String animStr = ""; + private String animBack = ""; + private int animPos; + private int animLen; + private int animDir; + private boolean animStep; + + public void init(int width, int height) { + if(this.gm.theWorld == null) { + this.ticks = 0; + this.hacked = 0; + this.resetAnimation(); + this.add(new ActButton(0, 0, 400, 24, (Gui)GuiWorlds.INSTANCE, "Einzelspieler")); + this.add(new ActButton(0, 28, 400, 24, (Gui)GuiConnect.INSTANCE, "Mehrspieler")); + this.add(new ActButton(0, 56, 400, 24, GuiInfo.INSTANCE, "Info / Über / Mitwirkende")); + this.add(new ActButton(0, 102, 196, 24, GuiOptions.getPage(), "Einstellungen")); + this.add(new ActButton(204, 102, 196, 24, new ActButton.Callback() { + public void use(ActButton elem, ActButton.Mode action) { + GuiMenu.this.gm.interrupted = true; + } + }, "Spiel beenden")); + this.shift(); + this.add(new Label(4, /* this.gm.fb_y - 2 */ 0, 200, 20, TextColor.VIOLET + Config.VERSION, true)); + this.splashLabel = this.add(new Label(0, 160, width, 24, "")); + this.pickSplash(); + } + else { + this.add(new ActButton(0, 0, 400, 24, (Gui)null, "Zurück zum Spiel")); + this.add(new ActButton(0, 28, 400, 24, GuiOptions.getPage(), "Einstellungen")); + if(!this.gm.isRemote() && !this.gm.debugWorld) { + this.add(new Textbox(0, 56, 96, 24, 5, true, new Textbox.Callback() { + public void use(Textbox elem, Action value) { + if(value == Action.SEND || value == Action.UNFOCUS) { + int port = -1; + try { + port = Integer.parseInt(elem.getText()); + } + catch(NumberFormatException e) { + } + if(port < 0 || port > 65535) + elem.setText("" + GuiMenu.this.gm.port); + else + GuiMenu.this.gm.port = port; + } + } + }, "" + this.gm.port)); // "srv_port" + this.add(new ActButton(100, 56, 300, 24, new ActButton.Callback() { + public void use(ActButton elem, ActButton.Mode action) { + GuiMenu.this.gm.bind(GuiMenu.this.gm.bind = (GuiMenu.this.gm.bind != -1 ? -1 : GuiMenu.this.gm.port)); + elem.setText(GuiMenu.this.gm.bind != -1 ? "LAN-Welt schließen" : "LAN-Welt öffnen"); + } + }, this.gm.bind != -1 ? "LAN-Welt schließen" : "LAN-Welt öffnen")); + } + this.add(new ActButton(0, 102, 400, 24, new ActButton.Callback() { + public void use(ActButton elem, ActButton.Mode action) { + GuiMenu.this.gm.unload(); + GuiMenu.this.gm.displayGuiScreen(INSTANCE); + } + }, this.gm.isRemote() ? "Verbindung trennen" : "Welt schließen")); + this.shift(); + } + } + + public String getTitle() { + return this.gm.theWorld == null ? "Hauptmenü" : "Menü"; + } + + private void pickSplash() { + this.splashLabel.setText(TextColor.VIOLET + this.rand.pick(Splashes.SPLASHES)); + } + + private void resetAnimation() { + this.animStr = ""; + this.animBack = ""; + this.animPos = 0; + this.animLen = 0; + this.animDir = 0; + this.animStep = false; + this.animWidth = Math.max(5, (this.gm.fb_x - 5) / 10); + this.animGrowth = this.animWidth / 15; + this.animGrow = new int[this.animWidth]; + } + + private void updateAnimation() { + if(this.animLen == 0) { + this.animDir = this.rand.zrange(3) - 1; + this.animLen = this.animDir == 0 ? (2 + this.rand.zrange(2)) : (8 + this.rand.zrange(96)); + } + else { + this.animPos += this.animDir; + if(this.animPos == -1) { + this.animPos = 0; + this.animDir = 1; + } + else if(this.animPos == this.animWidth - 3) { + this.animPos = this.animWidth - 4; + this.animDir = -1; + } + this.animLen--; + } + this.animStep = !this.animStep; + StringBuilder sb = new StringBuilder(11); + sb.append(TextColor.GRAY); + sb.append("["); + sb.append(TextColor.YELLOW); + switch(this.animDir) { + case -1: + sb.append((this.animStep ? '>' : '-') + "' "); + break; + case 0: + sb.append("`" + (this.animStep ? 'O' : 'o') + "'"); + break; + case 1: + sb.append(" `" + (this.animStep ? '<' : '-')); + break; + } + sb.append(TextColor.GRAY); + sb.append("]"); + this.animStr = sb.toString(); + for(int z = this.animPos; z < this.animPos + 4; z++) { + this.animGrow[z] = 0; + } + for(int z = 0; z < this.animGrowth; z++) { + this.animGrow[this.rand.zrange(this.animWidth)] += 1; + } + sb = new StringBuilder(this.animWidth + 2); + sb.append(TextColor.DGREEN); + for(int z = 0; z < this.animWidth; z++) { + switch(this.animGrow[z] / 5) { + case 0: + sb.append(TextColor.BLACK); + break; + case 1: + sb.append(TextColor.GRAY); + break; + case 2: + case 3: + sb.append(TextColor.LGRAY); + break; + case 4: + case 5: + case 6: + sb.append(TextColor.WHITE); + break; + case 7: + case 8: + case 9: + case 10: + sb.append(TextColor.MAGENTA); + break; + case 11: + case 12: + case 13: + case 14: + case 15: + sb.append(TextColor.DVIOLET); + break; + default: + sb.append(TextColor.VIOLET); + break; + } + sb.append(",."); + } + this.animBack = sb.toString(); + } + + public void updateScreen() { + if(this.gm.theWorld == null) { + this.ticks++; + if(this.gm.shift() && !(this.selected instanceof Textbox)) + this.pickSplash(); + this.updateAnimation(); + } + } + + public void key(Keysym key, boolean ctrl, boolean shift) { + super.key(key, ctrl, shift); + if(this.gm.theWorld == null) { + if((key == Keysym.UP || key == Keysym.W) && (this.hacked == 0 || this.hacked == 1)) + this.hacked++; + else if((key == Keysym.DOWN || key == Keysym.S) && (this.hacked == 2 || this.hacked == 3)) + this.hacked++; + else if((key == Keysym.LEFT || key == Keysym.A) && (this.hacked == 4 || this.hacked == 6)) + this.hacked++; + else if((key == Keysym.RIGHT || key == Keysym.D) && (this.hacked == 5 || this.hacked == 7)) + this.hacked++; + else + this.hacked = 0; + } + } + + /* + protected void actionPerformed(Button button) throws IOException { + if(button.id == 2 && this.hacked == 8) { + this.hacked++; + return; + } + else if(button.id == 1 && this.hacked == 9) { + this.hacked++; + return; + } + if(button.id != 3 || this.hacked != 10) + this.hacked = 0; + switch(button.id) { + case 0: + this.gm.displayGuiScreen(new GuiOptions(this)); + break; + case 1: + this.gm.displayGuiScreen(new GuiWorlds(this)); + break; + case 2: + this.gm.displayGuiScreen(new GuiMultiplayer(this)); + break; + case 3: + if(this.hacked == 10) + Log.info("Hax!"); + this.gm.displayGuiScreen(new GuiCredits(this.hacked == 10)); + this.hacked = 0; + break; +// case 4: +// this.gm.displayGuiScreen(new GuiLanguage()); +// break; + case 4: + this.gm.shutdown(); + break; + } + } + */ + + public void drawOverlays() { + super.drawOverlays(); + if(this.gm.theWorld == null) { + int y = 164; + int h = 16; + int n = Drawing.getWidth(this.splashLabel.getText()); + Drawing.drawRectColor(0, y, this.gm.fb_x / 2 - n / 2 - 10, h, 0x7f7f00ff); + Drawing.drawRectColor(this.gm.fb_x / 2 + n / 2 + 10, y, this.gm.fb_x - (this.gm.fb_x / 2 + n / 2 + 10), h, 0x7f7f00ff); + Drawing.drawText(this.animBack, this.gm.fb_x - Drawing.getWidth(this.animBack) - 2, this.gm.fb_y - 18, 0xffffffff); + Drawing.drawText(this.animStr, this.gm.fb_x - Drawing.getWidth(this.animStr) - ((this.animWidth - this.animPos - 4) * 10), this.gm.fb_y - 20, 0xffffffff); + } + } +} diff --git a/java/src/game/gui/GuiOptions.java b/java/src/game/gui/GuiOptions.java new file mode 100644 index 0000000..3b8890c --- /dev/null +++ b/java/src/game/gui/GuiOptions.java @@ -0,0 +1,30 @@ +package game.gui; + +import game.gui.element.ActButton; +import game.gui.element.SelectedButton; + +public abstract class GuiOptions extends Gui { + private static final GuiOptions[] PAGES = {lastPage = new GuiBinds(), new GuiStyle(), new GuiDisplay(), new GuiSound()}; + + private static GuiOptions lastPage; + + public static GuiOptions getPage() { + return lastPage; + } + + public void init(int width, int height) { + lastPage = this; + this.shift(); + int x = 0; + int y = 0; + for(GuiOptions gui : PAGES) { + this.add(gui == this ? new SelectedButton(240 * x, 24 * y, 240, 24, gui, gui.getTitle()) : + new ActButton(240 * x, 24 * y, 240, 24, gui, gui.getTitle())); + if(++x == 4) { + x = 0; + ++y; + } + } + this.add(new ActButton(width - 240, 0, 240, 24, GuiMenu.INSTANCE, "Zurück")); + } +} diff --git a/java/src/game/gui/GuiSign.java b/java/src/game/gui/GuiSign.java new file mode 100644 index 0000000..43eb536 --- /dev/null +++ b/java/src/game/gui/GuiSign.java @@ -0,0 +1,48 @@ +package game.gui; + +import game.gui.element.ActButton; +import game.gui.element.Textbox; +import game.gui.element.Textbox.Action; +import game.network.NetHandlerPlayClient; +import game.packet.CPacketSign; +import game.world.BlockPos; + +public class GuiSign extends Gui implements Textbox.Callback { + private final BlockPos position; + private final Textbox[] lines = new Textbox[4]; + private final String[] tempLines = new String[this.lines.length]; + + + public void init(int width, int height) { + for(int z = 0; z < this.lines.length; z++) { + this.lines[z] = this.add(new Textbox(0, 40 * z, 300, 24, 50, true, this, this.tempLines[z] == null ? "" : this.tempLines[z])); + } + this.add(new ActButton(0, 40 * (this.lines.length + 1), 300, 24, (Gui)null, "Fertig")); + this.shift(); + } + + public String getTitle() { + return "Schild bearbeiten"; + } + + + public void onGuiClosed() { + NetHandlerPlayClient nethandler = this.gm.getNetHandler(); + if(nethandler != null) { + for(int z = 0; z < this.lines.length; z++) { + this.tempLines[z] = this.lines[z].getText(); + } + nethandler.addToSendQueue(new CPacketSign(this.position, this.tempLines)); + } + } + + public GuiSign(BlockPos sign, String[] lines) { + this.position = sign; + System.arraycopy(lines, 0, this.tempLines, 0, this.lines.length); + } + + public void use(Textbox elem, Action value) { + if(value == Action.SEND) + this.gm.displayGuiScreen(null); + } +} diff --git a/java/src/game/gui/GuiSound.java b/java/src/game/gui/GuiSound.java new file mode 100644 index 0000000..b0bfab5 --- /dev/null +++ b/java/src/game/gui/GuiSound.java @@ -0,0 +1,75 @@ +package game.gui; + +import game.audio.Volume; +import game.gui.element.ActButton; +import game.gui.element.ActButton.Mode; + +public class GuiSound extends GuiOptions { + protected GuiSound() { + } + + public void init(int width, int height) { + // this.addSelector("mid_visualizer", 30, 80, 440, 24); // "Visualisation" +// this.addSelector("mid_opl_bank", 490, 80, 440, 24); +// this.addSelector("mid_play_unknown", 30, 120, 440, 24); +// this.addSelector("mid_keep_notes", 490, 120, 440, 24); +// this.addSelector("mid_dont_fade", 30, 160, 440, 24); +// this.addSelector("mid_debug_events", 490, 160, 440, 24); +// this.addSelector("mid_velocity_func", 30, 200, 440, 24); +// this.addSelector("mid_opl_voices", 490, 200, 440, 24); + +// gui_add_custom(win, 30, 240, 128, 128, gui_render_velocity); + + this.addSelector("snd_device_type", 490, 260, 440, 24); + +// this.addSelector("snd_sample_rate", 30, 380, 440, 24); +// this.addSelector("snd_sample_format", 490, 380, 440, 24); + + this.addSelector("snd_buffer_size", 30, 420, 440, 24); + this.addSelector("snd_frame_size", 490, 420, 440, 24); + + this.add(new ActButton(30, 480, 900, 24, new ActButton.Callback() { + public void use(ActButton elem, Mode action) { + GuiSound.this.gm.restartSound(false); + } + }, "Übernehmen und Audio-Thread neu starten")); + + int x = 30; + int y = 540; + for(Volume volume : Volume.values()) { + this.addSelector(volume.getCVarName(), x, y, 440, 24); + x = (x == 30) ? 490 : 30; + if(x == 30) + y += 40; + } + super.init(width, height); + } + + public String getTitle() { + return "Audio und Ton"; + } + +// void gui_fmt_velofunc(gui_t *elem, int value) { +// snprintf(elem->text, elem->capacity, "%s %d: %s", elem->format_text, value, (value ? (value == -128 ? "Vollklang [1]" : (value < 0 ? "Log. Gedämpft [nlog(x)]" : "Log.+Minimum [m+nlog(x)]")) : "Linear [x]")); +// } + +// int gui_rect(gui_t *elem, int x, int y, int w, int h, uint color) { +// gfx_draw_rect(elem->pos_x + x, elem->pos_y + y, w, h, 0, 0, 0xff000000 | color, 0xff000000 | color, 0, 0); +// return h; +// } +// +// // uint bank_getlevel(char function, byte velocity, byte volume, char pan); +// +// void gui_render_velocity(gui_t *elem, int value) { +// elem->r_dirty = 1; +// if(!value) +// gui_rect(elem, 0, 0, elem->size_x, elem->size_y, 0x202020); +// else +// return; +// int y; +// for(int x = 0; x < 128; x++) { +// y = x; // bank_getlevel(snd.mid_velo, x, 127, 0) / 512; +// gui_rect(elem, x, 128 - 1 - y, 1, y, 0x2fbf2f); +// } +// } +} diff --git a/java/src/game/gui/GuiStyle.java b/java/src/game/gui/GuiStyle.java new file mode 100644 index 0000000..414b3cb --- /dev/null +++ b/java/src/game/gui/GuiStyle.java @@ -0,0 +1,106 @@ +package game.gui; + +import game.gui.element.ActButton; +import game.gui.element.Dropdown; +import game.gui.element.SelectedButton; +import game.gui.element.Slider; +import game.gui.element.Switch; +import game.gui.element.Textbox; +import game.gui.element.Toggle; +import game.gui.element.ActButton.Mode; +import game.gui.element.Textbox.Action; + +public class GuiStyle extends GuiOptions implements Dropdown.Callback, ActButton.Callback, Toggle.Callback, Switch.Callback, Slider.Callback, Textbox.Callback { + private static final String[] STYLE_CVARS = { + "color_hover", + "color_background_t", + "color_button_top", + "color_textbox_top", + "color_border_top", + + "color_press", + "color_background_b", + "color_button_btm", + "color_textbox_btm", + "color_border_btm", + + "color_select", + "color_label_text", + "color_button_text", + "color_textbox_text", + "color_cursor" + }; + + protected GuiStyle() { + } + + public void init(int width, int height) { + int z; + for(z = 0; z < STYLE_CVARS.length; z++) { + this.addSelector(STYLE_CVARS[z], 10 + (z % 5) * 190, 100 + z / 5 * 50, 180, 24); + } + z = 0; + for(Style theme : Style.values()) { + ActButton.Callback callback = new ActButton.Callback() { + public void use(ActButton elem, Mode action) { + if(GuiStyle.this.gm.style != theme) { + GuiStyle.this.gm.style = theme; + GuiStyle.this.gm.setDirty(); + GuiStyle.this.gm.displayGuiScreen(GuiStyle.this); + } + } + }; + this.add(theme == this.gm.style ? new SelectedButton(10 + (z % 3) * 320, 360 + (z / 3) * 40, 300, 24, callback, theme.name) : + new ActButton(10 + (z % 3) * 320, 360 + (z / 3) * 40, 300, 24, callback, theme.name)); + z++; + } + + String[] values = new String[] {"VALUE 1", "VALUE 2"}; + this.add(new Dropdown(10, height - 74, 300, 24, false, values, values[1], values[0], this, "DROPDOWN")); + this.add(new ActButton(330, height - 74, 300, 24, (ActButton.Callback)this, "BUTTON")); + this.add(new Toggle(650, height - 74, 140, 24, false, true, this, "TOGGLE")); + this.add(new Toggle(810, height - 74, 140, 24, true, false, this, "TOGGLE")); + values = new String[] {"VALUE 1", "VALUE 2", "VALUE 3", "VALUE 4"}; + this.add(new Switch(10, height - 34, 300, 24, values, values[2], values[0], this, "ENUM")); + this.add(new Slider(330, height - 34, 300, 24, 0, -20, 827, 60, 120, this, "SLIDER")); + this.add(new Textbox(650, height - 34, 300, 24, 128, true, this, "FIELD")); + + this.add(new ActButton(200, 100 + 3 * 50, 560, 24, new ActButton.Callback() { + public void use(ActButton elem, Mode action) { + if(GuiStyle.this.gm.style != Style.CUSTOM) { + GuiStyle.this.gm.style = Style.CUSTOM; + GuiStyle.this.gm.setDirty(); + } + GuiStyle.this.gm.displayGuiScreen(GuiStyle.this); + } + }, "Übernehmen")); + this.add(new ActButton(200, 140 + 3 * 50, 560, 24, new ActButton.Callback() { + public void use(ActButton elem, Mode action) { + GuiStyle.this.gm.style = Style.CUSTOM; + for(String cvar : STYLE_CVARS) { + GuiStyle.this.gm.getVar(cvar).setDefault(); + } + GuiStyle.this.gm.setDirty(); + GuiStyle.this.gm.displayGuiScreen(GuiStyle.this); + } + }, "Zurücksetzen")); + super.init(width, height); + } + + public String getTitle() { + return "Benutzeroberfläche"; + } + + public void use(Textbox elem, Action value) { + } + public void use(Slider elem, int value) { + } + public void use(Switch elem, String value) { + } + public void use(Toggle elem, boolean value) { + } + public void use(ActButton elem, Mode action) { + } + public void use(Dropdown elem, String value) { + } +} diff --git a/java/src/game/gui/Style.java b/java/src/game/gui/Style.java new file mode 100644 index 0000000..4c2ada5 --- /dev/null +++ b/java/src/game/gui/Style.java @@ -0,0 +1,127 @@ +package game.gui; + +import game.properties.IStringSerializable; +import game.util.Displayable; +import game.vars.CVarCategory; +import game.vars.Variable; +import game.vars.Variable.IntType; + +public enum Style implements IStringSerializable, Displayable { + DEFAULT("default", "Glänzend (Standard)"), GRAY("gray", "Grau"), BLUE("blue", "Blau"), CUSTOM("custom", "Angepasst"); + + public final String id; + public final String name; + + private Style(String id, String name) { + this.id = id; + this.name = name; + } + + @Variable(type = IntType.COLOR, name = "color_border_top", category = CVarCategory.STYLE, display = "Umrahmung") + public int brdr_top; + @Variable(type = IntType.COLOR, name = "color_border_btm", category = CVarCategory.STYLE) + public int brdr_btm; + + @Variable(type = IntType.COLOR, name = "color_button_top", category = CVarCategory.STYLE, display = "Knopf") + public int fill_top; + @Variable(type = IntType.COLOR, name = "color_button_btm", category = CVarCategory.STYLE) + public int fill_btm; + @Variable(type = IntType.COLOR, name = "color_textbox_top", category = CVarCategory.STYLE, display = "Textfeld") + public int field_top; + @Variable(type = IntType.COLOR, name = "color_textbox_btm", category = CVarCategory.STYLE) + public int field_btm; + + @Variable(type = IntType.COLOR, name = "color_label_text", category = CVarCategory.STYLE, display = "Beschriftung") + public int text_label; + @Variable(type = IntType.COLOR, name = "color_button_text", category = CVarCategory.STYLE, display = "Text Knopf") + public int text_base; + @Variable(type = IntType.COLOR, name = "color_textbox_text", category = CVarCategory.STYLE, display = "Textfeld Text") + public int text_field; + + @Variable(type = IntType.COLOR, name = "color_background_t", category = CVarCategory.STYLE, display = "Hintergrund") + public int bg_top; + @Variable(type = IntType.COLOR, name = "color_background_b", category = CVarCategory.STYLE) + public int bg_btm; + + @Variable(type = IntType.ALPHA, name = "color_press", category = CVarCategory.STYLE, display = "Gedrückt") + public int press; + @Variable(type = IntType.ALPHA, name = "color_hover", category = CVarCategory.STYLE, display = "Gewählt") + public int hover; + @Variable(type = IntType.ALPHA, name = "color_select", category = CVarCategory.STYLE, display = "Textauswahl") + public int select; + @Variable(type = IntType.ALPHA, name = "color_cursor", category = CVarCategory.STYLE, display = "Textmarke") + public int cursor; + + static { + DEFAULT + .border(0xffffff, 0x3f3f3f) + .background(0x000000, 0x000000) + .base(0x404040, 0x000000, 0xffffff, 0xefefef) + .field(0x000000, 0x202020, 0xdfdfdf) + .select(0x30ffffff, 0x28ffffff, 0x60dfdfdf, 0xffffffff); + + GRAY + .border(0x000000, 0x202020) + .background(0x404040, 0x0a0a0a) + .base(0x808080, 0x000000, 0xffffff, 0xffffff) + .field(0x404040, 0x808080, 0xffffff) + .select(0x18ffffff, 0x288080ff, 0x808080ff, 0xff000000); + + BLUE + .border(0x0000df, 0x300020) + .background(0x20208f, 0x0a0a2d) + .base(0x2020a0, 0x000020, 0x8fffaf, 0x00cfaf) + .field(0x505090, 0x406060, 0xcfdfff) + .select(0x288f00ff, 0x28c080ff, 0x604020ff, 0xff2fff6f); + + CUSTOM + .border(0x000000, 0x000000) + .background(0x404040, 0x404040) + .base(0x808080, 0x808080, 0xffffff, 0xffffff) + .field(0x808080, 0x808080, 0xffffff) + .select(0x18ffffff, 0x288080ff, 0x808080ff, 0xff000000); + } + + private Style border(int top, int btm) { + this.brdr_top = top | 0xff000000; + this.brdr_btm = btm | 0xff000000; + return this; + } + + private Style background(int top, int btm) { + this.bg_top = top | 0xff000000; + this.bg_btm = btm | 0xff000000; + return this; + } + + private Style base(int top, int btm, int text, int label) { + this.fill_top = top | 0xff000000; + this.fill_btm = btm | 0xff000000; + this.text_base = text | 0xff000000; + this.text_label = label | 0xff000000; + return this; + } + + private Style field(int top, int btm, int text) { + this.field_top = top | 0xff000000; + this.field_btm = btm | 0xff000000; + this.text_field = text | 0xff000000; + return this; + } + + private Style select(int prs, int hov, int sel, int cur) { + this.press = prs; + this.hover = hov; + this.select = sel; + this.cursor = cur; + return this; + } + + public String getName() { + return this.id; + } + + public String getDisplay() { + return this.name; + } +} diff --git a/java/src/game/gui/element/ActButton.java b/java/src/game/gui/element/ActButton.java new file mode 100644 index 0000000..1b49e34 --- /dev/null +++ b/java/src/game/gui/element/ActButton.java @@ -0,0 +1,44 @@ +package game.gui.element; + +import game.Game; +import game.gui.Gui; +import game.util.Formatter; +import game.window.Button; + +public class ActButton extends Element { + public static enum Mode { + PRIMARY, SECONDARY, TERTIARY; + } + + public static interface Callback { + void use(ActButton elem, Mode action); + } + + private final Callback func; + + public ActButton(int x, int y, int w, int h, Callback callback, Formatter formatter) { + super(x, y, w, h, formatter); + this.func = callback; + this.formatText(); + } + + public ActButton(int x, int y, int w, int h, Callback callback, String text) { + super(x, y, w, h, null); + this.func = callback; + this.setText(text); + } + + public ActButton(int x, int y, int w, int h, Gui gui, String text) { + this(x, y, w, h, new Callback() { + public void use(ActButton elem, Mode action) { + Game.getGame().displayGuiScreen(gui); + } + }, text); + } + + + public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) { + this.func.use(this, (ctrl || (btn == Button.MOUSE_MIDDLE)) ? Mode.TERTIARY : ((shift || (btn == Button.MOUSE_RIGHT)) ? Mode.SECONDARY : Mode.PRIMARY)); + this.formatText(); + } +} diff --git a/java/src/game/gui/element/Dropdown.java b/java/src/game/gui/element/Dropdown.java new file mode 100644 index 0000000..a5c4ebf --- /dev/null +++ b/java/src/game/gui/element/Dropdown.java @@ -0,0 +1,126 @@ +package game.gui.element; + +import game.gui.Font; +import game.renderer.Drawing; +import game.util.Displayable; +import game.util.ExtMath; +import game.util.Formatter; +import game.util.Util; +import game.window.Button; + +public class Dropdown extends Element { + public class Handle extends Element { + private Handle(boolean up) { + super(Dropdown.this.pos_x, Dropdown.this.pos_y + (up ? -(Font.YGLYPH * Dropdown.this.values.length + 2) : Dropdown.this.size_y), Dropdown.this.size_x, Font.YGLYPH * Dropdown.this.values.length + 2, null); + StringBuilder sb = new StringBuilder(); + for(T value : Dropdown.this.values) { + if(sb.length() > 0) + sb.append('\n'); + sb.append(value instanceof Displayable ? ((Displayable)value).getDisplay() : value.toString()); + } + this.setText(sb.toString()); + this.visible = this.r_dirty = false; + } + + public void updateText() { + this.r_dirty = true; + } + + protected boolean isTextCenteredX() { + return false; + } + + protected boolean isTextCenteredY() { + return false; + } + + public boolean canClick() { + return false; + } + + public void deselect() { + this.visible = false; + this.r_dirty = true; + } + + public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) { + Dropdown drop = Dropdown.this; + int prev = drop.value; + drop.value = (y - (this.pos_y + this.margin_y1)) * drop.values.length / (this.size_y - (this.margin_y1 + this.margin_y2)); + drop.value = ExtMath.clampi(drop.value, 0, drop.values.length - 1); + if(drop.value != prev) { + drop.func.use(drop, drop.getValue()); + drop.formatText(); + } + this.visible = false; + this.r_dirty = true; + } + + public void drawHover() { + int m = ((this.gm.mouse_y - (this.pos_y + this.margin_y1)) * Dropdown.this.values.length / (this.size_y - (this.margin_y1 + this.margin_y2))); + // if((sys.mouse_y - this.pos_y) < (this.size_y - this.margin_y2)) + Drawing.drawRectColor(this.pos_x + this.margin_x1, + this.pos_y + this.margin_y1 + ExtMath.clampi(m, 0, Dropdown.this.values.length - 1) * ((this.size_y - (this.margin_y1 + this.margin_y2)) / Dropdown.this.values.length), + this.size_x - (this.margin_x1 + this.margin_x2), + (this.size_y - (this.margin_y1 + this.margin_y2)) / Dropdown.this.values.length, this.gm.style.hover); + } + } + + public static interface Callback { + void use(Dropdown elem, T value); + } + + private final Callback func; + private final T[] values; + private final Handle handle; + private final int def; + + private int value; + + public Dropdown(int x, int y, int w, int h, boolean up, T[] values, T def, T init, Callback callback, Formatter> formatter) { + super(x, y, w, h, formatter); + this.func = callback; + this.values = values; + this.def = Util.indexOfChecked(this.values, def); + this.value = Util.indexOfChecked(this.values, init); + this.handle = new Handle(up); + this.formatText(); + } + + public Dropdown(int x, int y, int w, int h, boolean up, T[] values, T def, T init, Callback callback, final String text) { + this(x, y, w, h, up, values, def, init, callback, new Formatter>() { + public String use(Dropdown elem) { + T value = elem.getValue(); + return String.format("%s: %s", text, value instanceof Displayable ? ((Displayable)value).getDisplay() : value.toString()); + } + }); + } + + public T getValue() { + return this.values[this.value]; + } + + public void setValue(T value) { + this.value = Util.indexOfChecked(this.values, value); + } + + public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) { + int prev = this.value; + if(ctrl || (btn == Button.MOUSE_MIDDLE)) { + if((this.value = this.def) != prev) { + this.func.use(this, this.getValue()); + this.formatText(); + } + } + else if(this.gui != null) { + Handle drop = this.handle; + drop.visible = true; + drop.r_dirty = true; + this.gui.selected = drop; + } + } + + public Handle getHandle() { + return this.handle; + } +} diff --git a/java/src/game/gui/element/Element.java b/java/src/game/gui/element/Element.java new file mode 100644 index 0000000..63c7304 --- /dev/null +++ b/java/src/game/gui/element/Element.java @@ -0,0 +1,278 @@ +package game.gui.element; + +import game.Game; +import game.gui.Font; +import game.gui.Gui; +import game.gui.element.Dropdown.Handle; +import game.renderer.Drawing; +import game.renderer.Drawing.Vec2i; +import game.util.Formatter; +import game.window.Button; +import game.window.Keysym; +import game.window.WCF; + +public abstract class Element { + protected final Game gm = Game.getGame(); + + protected Gui gui; + protected Formatter format; + protected String text = ""; + +// String format_text; +// Object aux_data; +// String[] format_data; +// CVar cv_data; + + protected int pos_x; + protected int pos_y; + protected int size_x; + protected int size_y; + protected int text_x = 0; + protected int text_y = 0; + protected int tsize_x = 0; + protected int tsize_y = 0; + + protected final int margin_x1 = this.getMargin(); + protected final int margin_y1 = this.getMargin(); + protected final int margin_x2 = this.getMargin(); + protected final int margin_y2 = this.getMargin(); + + public boolean visible = true; + public boolean enabled = true; + public boolean r_dirty = true; + + + public Element(int x, int y, int w, int h, Formatter formatter) { + this.pos_x = x; + this.pos_y = y; + this.size_x = w; + this.size_y = h; + this.format = formatter; +// gui_update_style(this, 1); +// if(type != ElemType.SLIDER) { +// this.margin_x1 = this.margin_x2 = (type == ElemType.FIELD || type == ElemType.DROPDOWN_HANDLE) ? this.border : 0; +// this.margin_y1 = this.margin_y2 = (type == ElemType.FIELD || type == ElemType.DROPDOWN_HANDLE) ? this.border : 0; +// } + } + + public void setGui(Gui gui) { + if(gui == null) + throw new NullPointerException("gui"); + if(this.gui != null) + throw new IllegalStateException("GUI bereits gesetzt"); + this.gui = gui; + } + + protected int getMargin() { + return 1; + } + + public final int getX() { + return this.pos_x; + } + + public final int getY() { + return this.pos_y; + } + + public final int getWidth() { + return this.size_x; + } + + public final int getHeight() { + return this.size_y; + } + + protected boolean isTextCenteredX() { + return true; + } + + protected boolean isTextCenteredY() { + return true; + } + + protected boolean hasLinebreak() { + return false; + } + + public boolean canHover() { + return true; + } + + public boolean canClick() { + return this.canHover(); + } + + public boolean inside(int x, int y) { + return (x >= this.pos_x) && (x < (this.pos_x + this.size_x)) && (y >= this.pos_y) && (y < (this.pos_y + this.size_y)); + } + + public boolean intersects(Element elem) { + return (elem.pos_y + elem.size_y) > this.pos_y && elem.pos_y < (this.pos_y + this.size_y) && (elem.pos_x + elem.size_x) > this.pos_x && elem.pos_x < (this.pos_x + this.size_x); + } + + public void updateText() { + Vec2i size = Drawing.txt_size(this.pos_x + this.margin_x1, this.pos_y + this.margin_y1, + this.pos_x + this.margin_x1, this.pos_y + this.margin_y1, + this.hasLinebreak() ? (this.pos_x + (this.size_x - (this.margin_x1 + this.margin_x2))) : Integer.MAX_VALUE, Integer.MAX_VALUE, this.text); + this.tsize_x = size.xpos; + this.tsize_y = size.ypos; +// if(this.type != ElemType.FIELD) { + if(this.isTextCenteredX()) + this.text_x = (this.size_x - this.tsize_x) / 2; + if(this.isTextCenteredY()) + this.text_y = (this.size_y - this.tsize_y - Font.YGLYPH) / 2; +// } + // logd("DBG", "s = %d %d; o = %d %d", this.tsize_x, this.tsize_y, this.text_x, this.text_y); +// gui_update_dropdown(); + if(this.gui != null && this.gui.selected instanceof Handle && this.gui.selected.visible) + this.gui.selected.r_dirty = true; + this.r_dirty = true; + } + + public void setText(String str) { + this.text = str; + this.updateText(); + } + + public String getText() { + return this.text; + } + + protected void formatText() { + if(this.format != null) { + this.text = this.format.use(this); + this.updateText(); + } + } + + public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) { + + } + + public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) { + + } + + public void mouserel() { + + } + + public void drag(int x, int y) { + + } + + public void character(char code) { + + } + + public void key(Keysym key, boolean ctrl, boolean shift) { + + } + + public void select() { + + } + + public void deselect() { + + } + + public void update() { + + } + + public void setSelected() { + if(this.gui != null) + this.gui.select(this); + } + + public void setDeselected() { + if(this.gui != null && this.gui.selected == this) + this.gui.deselect(); + } + + public void shift(int shift_x, int shift_y) { + this.pos_x += shift_x; + this.pos_y += shift_y; + } + + public void reformat() { + if(this.format != null) { +// boolean flag = this.r_dirty; + this.formatText(); +// if(!flag && !this.visible) +// this.r_dirty = false; + } + } + + protected void drawBackground() { + Drawing.drawGradient2Border(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_top, this.gm.style.fill_btm, this.gm.style.brdr_top, this.gm.style.brdr_btm); +// Drawing.drawGradient2GradBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_top, this.gm.style.fill_btm, 0xff000000, +// this.gm.style.brdr_top, Drawing.mixColor(this.gm.style.brdr_top, this.gm.style.brdr_btm), Drawing.mixColor(this.gm.style.brdr_top, this.gm.style.brdr_btm), this.gm.style.brdr_btm); + } + + protected void drawForeground(int x1, int y1, int x2, int y2) { + Drawing.drawText(this.text, x1 + this.text_x, y1 + this.text_y, this.gm.style.text_base); + } + + public void draw() { +// if(this.r_dirty) { + if(this.visible) { +// WCF.glScissor(this.pos_x, (this.gm.fb_y - (this.pos_y + this.size_y)) < 0 ? 0 : (this.gm.fb_y - (this.pos_y + this.size_y)), this.size_x, this.size_y); +// WCF.glEnable(WCF.GL_SCISSOR_TEST); +// WCF.glClear(WCF.GL_COLOR_BUFFER_BIT); +// WCF.glDisable(WCF.GL_SCISSOR_TEST); + this.drawBackground(); +// if(this.selected == this && this.type == ElemType.DROPDOWN_HANDLE) +// continue; + int x1 = this.pos_x + this.margin_x1; + int y1 = this.pos_y + this.margin_y1; + int x2 = this.size_x - (this.margin_x1 + this.margin_x2); + int y2 = this.size_y - (this.margin_y1 + this.margin_y2); + // if(elem.type == ElemType.FIELD) { + WCF.glScissor(x1 < 0 ? 0 : x1, (this.gm.fb_y - (y1 + y2)) < 0 ? 0 : (this.gm.fb_y - (y1 + y2)), x2 < 0 ? 0 : x2, y2 < 0 ? 0 : y2); + WCF.glEnable(WCF.GL_SCISSOR_TEST); + // } + // if(this.type == ElemType.CUSTOM) + // this.func(this, 1); + // else + this.drawForeground(x1, y1, x2, y2); + // logd("DBG", "%d @ %d %d -> %d %d", elem.id, x1, y1, elem.pos_x + x2, elem.pos_y + y2); + // if(elem.type == ElemType.FIELD) { + WCF.glDisable(WCF.GL_SCISSOR_TEST); + // glScissor(0, 0, sys.fb_x, sys.fb_y); + // } + } +// else { +// WCF.glScissor(this.pos_x, (this.gm.fb_y - (this.pos_y + this.size_y)) < 0 ? 0 : (this.gm.fb_y - (this.pos_y + this.size_y)), this.size_x, this.size_y); +// // logd("DBG", "%d @ %d %d -> %d %d", elem.id, elem.pos_x, elem.pos_y, elem.pos_x + elem.size_x, elem.pos_y + elem.size_y); +// WCF.glEnable(WCF.GL_SCISSOR_TEST); +//// if(this.type == ElemType.CUSTOM) +//// this.func(this, 0); +//// else +// WCF.glClear(WCF.GL_COLOR_BUFFER_BIT); +// WCF.glDisable(WCF.GL_SCISSOR_TEST); +// this.r_dirty = false; +// } + // this.r_dirty = this.visible; + // logd("DBG", "@ r"); +// if(this.visible) { +// } +// else { +// } +// } + } + + public void drawOverlay() { + + } + + public void drawHover() { + Drawing.drawRectColor(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.hover); + } + + public void drawPress() { + Drawing.drawRectColor(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.press); + } +} diff --git a/java/src/game/gui/element/Fill.java b/java/src/game/gui/element/Fill.java new file mode 100644 index 0000000..1fbe1c9 --- /dev/null +++ b/java/src/game/gui/element/Fill.java @@ -0,0 +1,46 @@ +package game.gui.element; + +public class Fill extends Element { + private final boolean left; + private final boolean top; + + public Fill(int x, int y, int w, int h, String text, boolean top, boolean left) { + super(x, y, w, h, null); + this.top = top; + this.left = left; + this.setText(text); + } + + public Fill(int x, int y, int w, int h, String text, boolean left) { + this(x, y, w, h, text, false, left); + } + + public Fill(int x, int y, int w, int h, String text) { + this(x, y, w, h, text, false, false); + } + + public Fill(int x, int y, int w, int h, boolean top, boolean left) { + this(x, y, w, h, "", top, left); + } + + public Fill(int x, int y, int w, int h, boolean left) { + this(x, y, w, h, "", false, left); + } + + public Fill(int x, int y, int w, int h) { + this(x, y, w, h, "", false, false); + } + + + public boolean canHover() { + return false; + } + + protected boolean isTextCenteredX() { + return !this.left; + } + + protected boolean isTextCenteredY() { + return !this.top; + } +} diff --git a/java/src/game/gui/element/GuiList.java b/java/src/game/gui/element/GuiList.java new file mode 100755 index 0000000..78646c5 --- /dev/null +++ b/java/src/game/gui/element/GuiList.java @@ -0,0 +1,407 @@ +package game.gui.element; + +import java.util.List; + +import game.collect.Lists; +import game.gui.Gui; +import game.renderer.DefaultVertexFormats; +import game.renderer.Drawing; +import game.renderer.GlState; +import game.renderer.Tessellator; +import game.util.ExtMath; +import game.window.Button; +import game.renderer.RenderBuffer; + +public abstract class GuiList extends Gui +{ + protected final List elements = Lists.newArrayList(); + + protected int width; + protected int height; + + protected int top; + protected int bottom; + protected int right; + protected int left; + protected int mouseX; + protected int mouseY; + protected int initialClickY = -2; + protected float scrollMultiplier; + protected float amountScrolled; + protected int selectedElement = -1; + protected long lastClicked; + + public abstract int getListWidth(); // 220 + + public abstract int getSlotHeight(); + + protected int getScrollBarX() + { + return 0; + } + + public void setDimensions(int widthIn, int heightIn, int topIn, int bottomIn) + { + this.width = widthIn; + this.height = heightIn; + this.top = topIn; + this.bottom = bottomIn; + this.left = 0; + this.right = widthIn; + } + + public void init(int width, int height) { + + this.selectedElement = -1; + } + + public void setSlotXBoundsFromLeft(int leftIn) + { + this.left = leftIn; + this.right = leftIn + this.width; + } + + public final T getListEntry(int index) { + return this.elements.get(index); + } + + public final T getSelected() { + return this.selectedElement < 0 ? null : this.elements.get(this.selectedElement); + } + + public final int getSize() { + return this.elements.size(); + } + + protected int getContentHeight() + { + return this.getSize() * this.getSlotHeight(); + } + + public int getSlotIndexFromScreenCoords(int x, int y) + { + int i = this.left + this.width / 2 - this.getListWidth() / 2; + int j = this.left + this.width / 2 + this.getListWidth() / 2; + int k = y - this.top + (int)this.amountScrolled - 4; + int l = k / this.getSlotHeight(); + return this.isInList(x, y) && x >= i && x <= j && l >= 0 && k >= 0 && l < this.getSize() ? l : -1; + } + + protected boolean isInList(int x, int y) + { + return x >= this.getScrollBarX() + 6; // x < this.getScrollBarX(); + } + + protected final boolean isSelected(int slotIndex) + { + return slotIndex == this.selectedElement; + } + + protected void bindAmountScrolled() + { + this.amountScrolled = ExtMath.clampf(this.amountScrolled, 0.0F, (float)this.getMaxScroll()); + } + + public int getMaxScroll() + { + return Math.max(0, this.getContentHeight() - (this.bottom - this.top - 4)); + } + + public int getAmountScrolled() + { + return (int)this.amountScrolled; + } + + public boolean isMouseYWithinSlotBounds(int p_148141_1_) + { + return p_148141_1_ >= this.top && p_148141_1_ <= this.bottom && this.mouseX >= this.left && this.mouseX <= this.right; + } + + public void scrollBy(int amount) + { + this.amountScrolled += (float)amount; + this.bindAmountScrolled(); + this.initialClickY = -2; + } + +// public void actionPerformed(Button button) +// { +// if (button.enabled) +// { +// if (button.id == this.scrollUpButtonID) +// { +// this.amountScrolled -= (float)(this.slotHeight * 2 / 3); +// this.initialClickY = -2; +// this.bindAmountScrolled(); +// } +// else if (button.id == this.scrollDownButtonID) +// { +// this.amountScrolled += (float)(this.slotHeight * 2 / 3); +// this.initialClickY = -2; +// this.bindAmountScrolled(); +// } +// } +// } + + public void draw() + { + int mouseXIn = this.gm.mouse_x; + int mouseYIn = this.gm.mouse_y; + this.mouseX = mouseXIn; + this.mouseY = mouseYIn; + this.drawBackground(); + int i = this.getScrollBarX(); + int j = i + 6; + this.bindAmountScrolled(); + GlState.disableLighting(); + GlState.disableFog(); + GlState.enableTexture2D(); + RenderBuffer worldrenderer = Tessellator.getBuffer(); + this.gm.getTextureManager().bindTexture(Gui.DIRT_BACKGROUND); + GlState.color(1.0F, 1.0F, 1.0F, 1.0F); + + float f = 32.0F; + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + worldrenderer.pos((double)this.left, (double)this.bottom, 0.0D).tex((double)((float)this.left / f), (double)((float)(this.bottom + (int)this.amountScrolled) / f)).color(32, 32, 32, 255).endVertex(); + worldrenderer.pos((double)this.right, (double)this.bottom, 0.0D).tex((double)((float)this.right / f), (double)((float)(this.bottom + (int)this.amountScrolled) / f)).color(32, 32, 32, 255).endVertex(); + worldrenderer.pos((double)this.right, (double)this.top, 0.0D).tex((double)((float)this.right / f), (double)((float)(this.top + (int)this.amountScrolled) / f)).color(32, 32, 32, 255).endVertex(); + worldrenderer.pos((double)this.left, (double)this.top, 0.0D).tex((double)((float)this.left / f), (double)((float)(this.top + (int)this.amountScrolled) / f)).color(32, 32, 32, 255).endVertex(); + Tessellator.draw(); + + int x = this.left + this.width / 2 - this.getListWidth() / 2 + 2; + int y = this.top + 4 - (int)this.amountScrolled; + + this.drawSelectionBox(x, y, mouseXIn, mouseYIn); + GlState.disableDepth(); + + this.overlayBackground(0, this.top, 255, 255); + this.overlayBackground(this.bottom, this.height, 255, 255); + + GlState.enableBlend(); + GlState.tryBlendFuncSeparate(770, 771, 0, 1); + GlState.disableAlpha(); + GlState.shadeModel(7425); + GlState.disableTexture2D(); + + int i1 = 4; + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + worldrenderer.pos((double)this.left, (double)(this.top + i1), 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 0).endVertex(); + worldrenderer.pos((double)this.right, (double)(this.top + i1), 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 0).endVertex(); + worldrenderer.pos((double)this.right, (double)this.top, 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 255).endVertex(); + worldrenderer.pos((double)this.left, (double)this.top, 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 255).endVertex(); + Tessellator.draw(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + worldrenderer.pos((double)this.left, (double)this.bottom, 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 255).endVertex(); + worldrenderer.pos((double)this.right, (double)this.bottom, 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 255).endVertex(); + worldrenderer.pos((double)this.right, (double)(this.bottom - i1), 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 0).endVertex(); + worldrenderer.pos((double)this.left, (double)(this.bottom - i1), 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 0).endVertex(); + Tessellator.draw(); + + int j1 = this.getMaxScroll(); + + if (j1 > 0) + { + int k1 = (this.bottom - this.top) * (this.bottom - this.top) / this.getContentHeight(); + k1 = ExtMath.clampi(k1, 32, this.bottom - this.top - 8); + int l1 = (int)this.amountScrolled * (this.bottom - this.top - k1) / j1 + this.top; + + if (l1 < this.top) + { + l1 = this.top; + } + + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + worldrenderer.pos((double)i, (double)this.bottom, 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 255).endVertex(); + worldrenderer.pos((double)j, (double)this.bottom, 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 255).endVertex(); + worldrenderer.pos((double)j, (double)this.top, 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 255).endVertex(); + worldrenderer.pos((double)i, (double)this.top, 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 255).endVertex(); + Tessellator.draw(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + worldrenderer.pos((double)i, (double)(l1 + k1), 0.0D).tex(0.0D, 1.0D).color(128, 128, 128, 255).endVertex(); + worldrenderer.pos((double)j, (double)(l1 + k1), 0.0D).tex(1.0D, 1.0D).color(128, 128, 128, 255).endVertex(); + worldrenderer.pos((double)j, (double)l1, 0.0D).tex(1.0D, 0.0D).color(128, 128, 128, 255).endVertex(); + worldrenderer.pos((double)i, (double)l1, 0.0D).tex(0.0D, 0.0D).color(128, 128, 128, 255).endVertex(); + Tessellator.draw(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + worldrenderer.pos((double)i, (double)(l1 + k1 - 1), 0.0D).tex(0.0D, 1.0D).color(192, 192, 192, 255).endVertex(); + worldrenderer.pos((double)(j - 1), (double)(l1 + k1 - 1), 0.0D).tex(1.0D, 1.0D).color(192, 192, 192, 255).endVertex(); + worldrenderer.pos((double)(j - 1), (double)l1, 0.0D).tex(1.0D, 0.0D).color(192, 192, 192, 255).endVertex(); + worldrenderer.pos((double)i, (double)l1, 0.0D).tex(0.0D, 0.0D).color(192, 192, 192, 255).endVertex(); + Tessellator.draw(); + } + + GlState.enableTexture2D(); + GlState.shadeModel(7424); + GlState.enableAlpha(); + GlState.disableBlend(); + + super.draw(); + } + + public void handleMouseInput() + { + if (this.isMouseYWithinSlotBounds(this.mouseY)) + { +// if (Button.MOUSE_LEFT.isDown() && this.getEnabled()) +// { + if (this.initialClickY == -1) + { + boolean flag1 = true; + + if (this.mouseY >= this.top && this.mouseY <= this.bottom) + { + int j2 = (this.width - this.getListWidth()) / 2; + int k2 = (this.width + this.getListWidth()) / 2; + int l2 = this.mouseY - this.top + (int)this.amountScrolled - 4; + int i1 = l2 / this.getSlotHeight(); + + if (i1 < this.getSize() && this.mouseX >= j2 && this.mouseX <= k2 && i1 >= 0 && l2 >= 0) + { + } + else if (this.mouseX >= j2 && this.mouseX <= k2 && l2 < 0) + { + flag1 = false; + } + + int i3 = this.getScrollBarX(); + int j1 = i3 + 6; + + if (this.mouseX >= i3 && this.mouseX <= j1) + { + this.scrollMultiplier = -1.0F; + int k1 = this.getMaxScroll(); + + if (k1 < 1) + { + k1 = 1; + } + + int l1 = (int)((float)((this.bottom - this.top) * (this.bottom - this.top)) / (float)this.getContentHeight()); + l1 = ExtMath.clampi(l1, 32, this.bottom - this.top - 8); + this.scrollMultiplier /= (float)(this.bottom - this.top - l1) / (float)k1; + } + else + { + this.scrollMultiplier = 1.0F; + } + + if (flag1) + { + this.initialClickY = this.mouseY; + } + else + { + this.initialClickY = -2; + } + } + else + { + this.initialClickY = -2; + } + } + else if (this.initialClickY >= 0) + { + this.amountScrolled -= (float)(this.mouseY - this.initialClickY) * this.scrollMultiplier; + this.initialClickY = this.mouseY; + } +// } +// else +// { +// this.initialClickY = -1; +// } + } + } + + protected void drawSelectionBox(int x, int y, int mouseXIn, int mouseYIn) + { + int size = this.getSize(); + RenderBuffer rb = Tessellator.getBuffer(); + + for (int z = 0; z < size; z++) + { + int y1 = y + z * this.getSlotHeight(); + int h = this.getSlotHeight() - 4; + + if (this.isSelected(z)) + { + int x1 = this.left + (this.width / 2 - this.getListWidth() / 2); + int x2 = this.left + this.width / 2 + this.getListWidth() / 2; + GlState.color(1.0F, 1.0F, 1.0F, 1.0F); + GlState.disableTexture2D(); + rb.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + rb.pos((double)x1, (double)(y1 + h + 2), 0.0D).tex(0.0D, 1.0D).color(128, 128, 128, 255).endVertex(); + rb.pos((double)x2, (double)(y1 + h + 2), 0.0D).tex(1.0D, 1.0D).color(128, 128, 128, 255).endVertex(); + rb.pos((double)x2, (double)(y1 - 2), 0.0D).tex(1.0D, 0.0D).color(128, 128, 128, 255).endVertex(); + rb.pos((double)x1, (double)(y1 - 2), 0.0D).tex(0.0D, 0.0D).color(128, 128, 128, 255).endVertex(); + rb.pos((double)(x1 + 1), (double)(y1 + h + 1), 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 255).endVertex(); + rb.pos((double)(x2 - 1), (double)(y1 + h + 1), 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 255).endVertex(); + rb.pos((double)(x2 - 1), (double)(y1 - 1), 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 255).endVertex(); + rb.pos((double)(x1 + 1), (double)(y1 - 1), 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 255).endVertex(); + Tessellator.draw(); + GlState.enableTexture2D(); + } + + boolean hover = this.getSlotIndexFromScreenCoords(mouseXIn, mouseYIn) == z; + this.getListEntry(z).draw(x, y1, mouseXIn - x, mouseYIn - y1, hover); + if(hover) + Drawing.drawRectColor(x - 2, y1 - 2, this.getListWidth(), this.getSlotHeight(), this.gm.style.hover); + } + } + + protected void overlayBackground(int startY, int endY, int startAlpha, int endAlpha) + { + RenderBuffer rb = Tessellator.getBuffer(); + this.gm.getTextureManager().bindTexture(Gui.DIRT_BACKGROUND); + GlState.color(1.0F, 1.0F, 1.0F, 1.0F); + float f = 32.0F; + rb.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + rb.pos((double)this.left, (double)endY, 0.0D).tex(0.0D, (double)((float)endY / 32.0F)).color(64, 64, 64, endAlpha).endVertex(); + rb.pos((double)(this.left + this.width), (double)endY, 0.0D).tex((double)((float)this.width / 32.0F), (double)((float)endY / 32.0F)).color(64, 64, 64, endAlpha).endVertex(); + rb.pos((double)(this.left + this.width), (double)startY, 0.0D).tex((double)((float)this.width / 32.0F), (double)((float)startY / 32.0F)).color(64, 64, 64, startAlpha).endVertex(); + rb.pos((double)this.left, (double)startY, 0.0D).tex(0.0D, (double)((float)startY / 32.0F)).color(64, 64, 64, startAlpha).endVertex(); + Tessellator.draw(); + } + + public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) + { + super.mouse(btn, x, y, ctrl, shift); + if (this.isMouseYWithinSlotBounds(y)) + { + int i = this.getSlotIndexFromScreenCoords(x, y); + + if (i >= 0) + { + int j = this.left + this.width / 2 - this.getListWidth() / 2 + 2; + int k = this.top + 4 - this.getAmountScrolled() + i * this.getSlotHeight(); + int l = x - j; + int i1 = y - k; + + boolean flag = i == this.selectedElement && System.currentTimeMillis() - this.lastClicked < (long)this.gm.dclickDelay; + this.selectedElement = i; + this.lastClicked = System.currentTimeMillis(); + + this.getListEntry(i).select(flag, l, i1); + } + } + if(btn == Button.MOUSE_LEFT && this.clicked(x, y) == null) + this.handleMouseInput(); + } + + public void mouserel(Button btn, int x, int y) { + super.mouserel(btn, x, y); + if(btn == Button.MOUSE_LEFT) + this.initialClickY = -1; + } + + public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) { + super.scroll(scr_x, scr_y, x, y, ctrl, shift); + if(scr_y != 0 && this.clicked(x, y) == null) + this.amountScrolled -= (float)(ExtMath.clampi(scr_y, -1, 1) * this.getSlotHeight() / 2); + } + + public void drag(int x, int y) { + super.drag(x, y); + if(this.selected == null && Button.MOUSE_LEFT.isDown()) + this.handleMouseInput(); + } +} diff --git a/java/src/game/gui/element/InventoryButton.java b/java/src/game/gui/element/InventoryButton.java new file mode 100644 index 0000000..0e4a219 --- /dev/null +++ b/java/src/game/gui/element/InventoryButton.java @@ -0,0 +1,17 @@ +package game.gui.element; + +import game.renderer.Drawing; + +public class InventoryButton extends Element { + public InventoryButton(int x, int y, int w, int h) { + super(x, y, w, h, null); + } + + protected void drawBackground() { +// Drawing.drawRect2Border(this.pos_x, this.pos_y, this.size_x, this.size_y, 0xff6f6f6f, 0xffafafaf); + Drawing.drawRect2GradBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, 0xff6f6f6f, 0xff000000, 0xffafafaf, 0xff7f7f7f, 0xff7f7f7f, 0xff4f4f4f); + } + + protected void drawForeground(int x1, int y1, int x2, int y2) { + } +} diff --git a/java/src/game/gui/element/Label.java b/java/src/game/gui/element/Label.java new file mode 100644 index 0000000..6f356ad --- /dev/null +++ b/java/src/game/gui/element/Label.java @@ -0,0 +1,28 @@ +package game.gui.element; + +import game.renderer.Drawing; + +public class Label extends Fill { + public Label(int x, int y, int w, int h, String text, boolean top, boolean left) { + super(x, y, w, h, text, top, left); + } + + public Label(int x, int y, int w, int h, String text, boolean left) { + super(x, y, w, h, text, left); + } + + public Label(int x, int y, int w, int h, String text) { + super(x, y, w, h, text); + } + + protected void drawBackground() { + } + + protected void drawForeground(int x1, int y1, int x2, int y2) { + Drawing.drawText(this.text, x1 + this.text_x, y1 + this.text_y, this.gm.style.text_label); + } + + protected int getMargin() { + return 0; + } +} diff --git a/java/src/game/gui/element/ListEntry.java b/java/src/game/gui/element/ListEntry.java new file mode 100644 index 0000000..2d5d173 --- /dev/null +++ b/java/src/game/gui/element/ListEntry.java @@ -0,0 +1,7 @@ +package game.gui.element; + +public interface ListEntry +{ + void draw(int x, int y, int mouseX, int mouseY, boolean hovered); + void select(boolean dclick, int mx, int my); +} \ No newline at end of file diff --git a/java/src/game/gui/element/SelectedButton.java b/java/src/game/gui/element/SelectedButton.java new file mode 100644 index 0000000..930a348 --- /dev/null +++ b/java/src/game/gui/element/SelectedButton.java @@ -0,0 +1,18 @@ +package game.gui.element; + +import game.gui.Gui; +import game.renderer.Drawing; + +public class SelectedButton extends ActButton { + public SelectedButton(int x, int y, int w, int h, Callback callback, String text) { + super(x, y, w, h, callback, text); + } + + public SelectedButton(int x, int y, int w, int h, Gui gui, String text) { + super(x, y, w, h, gui, text); + } + + protected void drawBackground() { + Drawing.drawGradient2Border(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_btm, this.gm.style.fill_top, this.gm.style.brdr_top, this.gm.style.brdr_btm); + } +} diff --git a/java/src/game/gui/element/Slider.java b/java/src/game/gui/element/Slider.java new file mode 100644 index 0000000..e0a84f8 --- /dev/null +++ b/java/src/game/gui/element/Slider.java @@ -0,0 +1,165 @@ +package game.gui.element; + +import game.renderer.Drawing; +import game.util.ExtMath; +import game.util.Formatter; +import game.window.Button; + +public class Slider extends Element { + public static interface Callback { + void use(Slider elem, int value); + } + + public static interface FloatCallback { + void use(Slider elem, float value); + } + + private static final int SLIDER_WIDTH = 10; + + private final Callback func; + private final int def; + private final int min; + private final int max; + private final int precision; + private final int handle; + + private int value; + private int position; + + public Slider(int x, int y, int w, int h, int prec, int min, int max, int def, int init, Callback callback, Formatter formatter) { + super(x, y, w, h, formatter); + this.handle = ((this.size_y * SLIDER_WIDTH) / 24) & ~1; + this.func = callback; + this.precision = prec; + this.min = min; + this.max = max; + this.def = def; + this.value = init; + this.position = gui_slider_pixel(); + this.formatText(); + } + + public Slider(int x, int y, int w, int h, int prec, int min, int max, int def, int init, Callback callback, final String text) { + this(x, y, w, h, prec, min, max, def, init, callback, new Formatter() { + public String use(Slider elem) { + return String.format("%s: %d", text, elem.value); + } + }); + } + + public Slider(int x, int y, int w, int h, int prec, int min, int max, int def, int init, Callback callback, final String text, final String unit) { + this(x, y, w, h, prec, min, max, def, init, callback, new Formatter() { + private final String format = unit.isEmpty() ? "%s: %d" : "%s: %d %s"; + + public String use(Slider elem) { + return String.format(this.format, text, elem.value, unit); + } + }); + } + + public Slider(int x, int y, int w, int h, int prec, float min, float max, float def, float init, final FloatCallback callback, Formatter formatter) { + this(x, y, w, h, prec, (int)(min * 1000.0f), (int)(max * 1000.0f), (int)(def * 1000.0f), (int)(init * 1000.0f), new Callback() { + public void use(Slider elem, int value) { + callback.use(elem, (float)value / 1000.0f); + } + }, formatter); + } + + public Slider(int x, int y, int w, int h, final int prec, float min, float max, float def, float init, FloatCallback callback, final String text, final String unit) { + this(x, y, w, h, prec < 0 ? 0 : prec, min, max, def, init, callback, new Formatter() { + private final String format = "%s: " + (prec <= 0 ? "%d" : ("%." + prec + "f")) + (unit.isEmpty() ? "" : " %s"); + + public String use(Slider elem) { + return prec <= 0 ? String.format(this.format, text, prec < 0 ? (int)((float)elem.value / 10.0f) : (elem.value / 1000), unit) + : String.format(this.format, text, (float)elem.value / 1000.0f, unit); + } + }); + } + + public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) { + if(scr_y != 0) { + int prev = this.value; + this.value += (scr_y < 0 ? -1 : 1) * (ctrl ? (this.precision != 0 ? 1 : 10) : ((this.precision >= 2) ? 10 : (this.precision != 0 ? 100 : 1))) * (shift ? (this.precision != 0 ? 50 : 5) : 1); + this.value = ExtMath.clampi(this.value, this.min, this.max); + this.position = gui_slider_pixel(); + if(this.value != prev) { + this.func.use(this, this.value); + this.formatText(); + } + } + } + + public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) { + int prev = this.value; + if(ctrl || (btn == Button.MOUSE_MIDDLE)) { + this.value = this.def; + this.position = gui_slider_pixel(); + if(this.value != prev) { + this.func.use(this, this.value); + this.formatText(); + } + } + else { + this.position = x - this.pos_x; + this.value = gui_slider_value(); + this.position = gui_slider_pixel(); + if(this.value != prev) { + this.func.use(this, this.value); + this.formatText(); + } + } + } + + public void drag(int x, int y) { + x = (x < this.pos_x) ? this.pos_x : ((x >= (this.pos_x + this.size_x)) ? (this.pos_x - 1 + this.size_x) : x); + int prev = this.value; + this.position = x - this.pos_x; + this.value = gui_slider_value(); + this.value = ExtMath.clampi(this.value, this.min, this.max); + this.position = gui_slider_pixel(); + if(this.value != prev) { + this.func.use(this, this.value); + this.formatText(); + } + } + + public void reformat() { + this.position = gui_slider_pixel(); + if(this.visible) + this.r_dirty = true; + super.reformat(); + } + + private int gui_slider_value() { + int r = this.min + (int)(((float)(int)(this.position - (this.handle / 2))) * ((float)(int)(this.max - this.min)) / ((float)(int)(this.size_x + 1 - this.handle))); + return ExtMath.clampi(r, this.min, this.max); + } + + private int gui_slider_pixel() { + int r = ((int)(float)(((float)(int)(this.value - this.min)) * ((float)(int)(this.size_x + 1 - this.handle)) / ((float)(int)(this.max - this.min)))) + (this.handle / 2); + return ExtMath.clampi(r, this.handle / 2, this.size_x - (this.handle / 2)); + } + + public void setValue(int value) { + this.value = ExtMath.clampi(value, this.min, this.max); + this.position = gui_slider_pixel(); + this.formatText(); + } + + public void setFloatValue(float value) { + this.setValue((int)(value * 1000.0f)); + } + + public int getValue() { + return this.value; + } + + public float getFloatValue() { + return (float)this.value / 1000.0f; + } + + protected void drawBackground() { + Drawing.drawGradient2Border(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_btm, this.gm.style.fill_top, this.gm.style.brdr_top, this.gm.style.brdr_btm); + Drawing.drawGradient2Border(this.pos_x + this.position - (this.handle / 2), this.pos_y, this.handle, this.size_y, this.gm.style.fill_top, this.gm.style.fill_btm, this.gm.style.brdr_btm, this.gm.style.brdr_top); + } +} diff --git a/java/src/game/gui/element/Switch.java b/java/src/game/gui/element/Switch.java new file mode 100644 index 0000000..9115632 --- /dev/null +++ b/java/src/game/gui/element/Switch.java @@ -0,0 +1,54 @@ +package game.gui.element; + +import game.util.Displayable; +import game.util.Formatter; +import game.util.Util; +import game.window.Button; + +public class Switch extends Element { + public static interface Callback { + void use(Switch elem, T value); + } + + private final Callback func; + private final T[] values; + private final int def; + + private int value; + + public Switch(int x, int y, int w, int h, T[] values, T def, T init, Callback callback, Formatter> formatter) { + super(x, y, w, h, formatter); + this.func = callback; + this.values = values; + this.def = Util.indexOfChecked(this.values, def); + this.value = Util.indexOfChecked(this.values, init); + this.formatText(); + } + + public Switch(int x, int y, int w, int h, T[] values, T def, T init, Callback callback, final String text) { + this(x, y, w, h, values, def, init, callback, new Formatter>() { + public String use(Switch elem) { + T value = elem.getValue(); + return String.format("%s: %s", text, value instanceof Displayable ? ((Displayable)value).getDisplay() : value.toString()); + } + }); + } + + public T getValue() { + return this.values[this.value]; + } + + public void setValue(T value) { + this.value = Util.indexOfChecked(this.values, value); + } + + public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) { + int prev = this.value; + this.value = (ctrl || (btn == Button.MOUSE_MIDDLE)) ? this.def : (this.value + ((shift || (btn == Button.MOUSE_RIGHT)) ? -1 : 1)); + this.value = (this.value == this.values.length) ? 0 : ((this.value == -1) ? (this.values.length - 1) : this.value); + if(this.value != prev) { + this.func.use(this, this.getValue()); + this.formatText(); + } + } +} diff --git a/java/src/game/gui/element/Textbox.java b/java/src/game/gui/element/Textbox.java new file mode 100644 index 0000000..66ae1d0 --- /dev/null +++ b/java/src/game/gui/element/Textbox.java @@ -0,0 +1,488 @@ +package game.gui.element; + +import game.gui.Font; +import game.renderer.Drawing; +import game.renderer.Drawing.Offset; +import game.renderer.Drawing.Vec2i; +import game.util.CharValidator; +import game.util.ExtMath; +import game.util.Timing; +import game.util.Util; +import game.window.Button; +import game.window.Keysym; +import game.window.WCF; + +public class Textbox extends Element { + public static enum Action { + FOCUS, UNFOCUS, PREVIOUS, NEXT, FUNCTION, SEND, LINE, FORWARD, BACKWARD; + } + + public static interface Callback { + void use(Textbox elem, Action value); + } + + private final Callback func; + private final CharValidator validator; + private final int capacity; + private final boolean xbreak; + private final boolean editable; + + private long tmr_scroll; + private long tmr_leftmb; + private int scrollx; + private int scrolly; + private int sel_start = -1; + private int sel_end = -1; + private int sel_drag = -1; + private int cursorX = 0; + private int cursorY = 0; + + private Textbox(int x, int y, int w, int h, int cap, boolean line, boolean editable, Callback callback, CharValidator validator, String text) { + super(x, y, w, h, null); + this.func = callback; + this.validator = validator; + this.capacity = cap; + this.xbreak = !line; + this.editable = editable; + if(line) + this.text_y = (this.size_y - (this.margin_y1 + this.margin_y2 + Font.YGLYPH)) / 2; + this.setText(text); + } + + public Textbox(int x, int y, int w, int h, int cap, boolean line, Callback callback, String text) { + this(x, y, w, h, cap, line, true, callback, null, text); + } + + public Textbox(int x, int y, int w, int h, int cap, boolean line, Callback callback, CharValidator validator, String text) { + this(x, y, w, h, cap, line, true, callback, validator, text); + } + + public Textbox(int x, int y, int w, int h, int cap, Callback callback, String text) { + this(x, y, w, h, cap, false, true, callback, null, text); + } + + public Textbox(int x, int y, int w, int h, String text) { + this(x, y, w, h, Integer.MAX_VALUE, false, false, null, null, text); + } + +// public void setEditable(boolean editable) { +// this.editable = editable; +// } + + protected boolean isTextCenteredX() { + return false; + } + + protected boolean isTextCenteredY() { + return false; + } + + protected boolean hasLinebreak() { + return this.xbreak; + } + + public boolean canHover() { + return false; + } + + public void setText(String str) { + if(this.validator != null) + str = this.validator.filter(str); + this.text = str.length() > this.capacity ? str.substring(0, this.capacity) : str; + this.updateText(); + this.sel_start = this.sel_end = this.sel_drag = this.text.length(); + gui_text_update_cur(this.sel_start, true); + } + + public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) { + if(scr_y != 0 && this.xbreak) { + int limit = Font.YGLYPH + this.tsize_y - (this.size_y - (this.margin_y1 + this.margin_y2)); + limit = ExtMath.clampi(limit, 0, 0x7fffffff); + int prev = this.text_y; + this.text_y += (scr_y < 0 ? -1 : 1) * (ctrl ? 1 : Font.YGLYPH) * this.gm.scrollLines * (shift ? 10 : 1); + this.text_y = ExtMath.clampi(this.text_y, -limit, 0); + if(this.sel_start >= 0) + this.cursorY += (this.text_y - prev); + this.r_dirty = true; + } + else if(scr_y != 0 || scr_x != 0) { + int limit = Font.XGLYPH + this.tsize_x - (this.size_x - (this.margin_x1 + this.margin_x2)); + limit = ExtMath.clampi(limit, 0, 0x7fffffff); + int prev = this.text_x; + this.text_x += ((scr_y != 0 ? scr_y : (-scr_x)) < 0 ? -1 : 1) * (ctrl ? 1 : Font.XGLYPH) * this.gm.scrollLines * (shift ? 10 : 1); + this.text_x = ExtMath.clampi(this.text_x, -limit, 0); + if(this.sel_start >= 0) + this.cursorX += (this.text_x - prev); + this.r_dirty = true; + } + } + + public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) { + if(btn == Button.MOUSE_LEFT) { + if(!shift && ((Timing.tmr_current - this.tmr_leftmb) <= (((long)this.gm.dclickDelay) * 1000L))) { + this.sel_start = this.sel_drag = 0; + this.sel_end = this.text.length(); + this.r_dirty = true; + } + else { + gui_text_select(x, y, shift); + } + this.tmr_leftmb = Timing.tmr_current; + } + else if((btn == Button.MOUSE_MIDDLE) && this.func != null) { + this.func.use(this, Action.FUNCTION); + } + } + + public void mouserel() { + this.scrollx = this.scrolly = 0; + } + + public void drag(int x, int y) { + gui_text_select(x, y, true); + } + + public void character(char code) { + if(this.editable) { +// int pos = 0; +// char chr[8]; +// utf_rwriten(chr, &pos, 8, code); +// chr[pos] = 0; + insertText(Character.toString(code)); + } + } + + public void key(Keysym key, boolean ctrl, boolean shift) { + if(ctrl && key == Keysym.A) { + this.sel_start = this.sel_drag = 0; + this.sel_end = this.text.length(); + this.r_dirty = true; + } + else if(ctrl && (key == Keysym.C) || (this.editable && (key == Keysym.X))) { + if(this.sel_start >= 0 && this.sel_start != this.sel_end) { // fix empty + // char end = this.text[this.sel_end]; + // this.text[this.sel_end] = 0; + String str = Util.strip(this.text, this.sel_start, this.sel_end - this.sel_start, '\n', (char)0, '?'); + WCF.setClipboard(str); + // this.text[this.sel_end] = end; + if(key == Keysym.X) + insertText(""); + } + } + else if(this.editable && ctrl && key == Keysym.V) { + insertText(WCF.getClipboard()); + } + else if(this.editable && !ctrl && key == Keysym.RETURN) { + if(this.xbreak) { + insertText("\n"); + } + else if(this.func != null) { + this.func.use(this, shift ? Action.LINE : Action.SEND); + } + } + else if(this.editable && (!ctrl) && (key == Keysym.BACKSPACE || key == Keysym.DELETE)) { + if(this.sel_start != this.sel_end) { + insertText(""); + } + else if(key == Keysym.DELETE && this.sel_start >= 0) { + if(this.sel_end < this.text.length()) { + this.sel_end += 1; + insertText(""); + } + else { + this.sel_end = this.sel_start; + } + } + else if(key == Keysym.BACKSPACE && this.sel_start > 0) { + this.sel_start -= 1; + insertText(""); + } + } + else if(!ctrl && (key == Keysym.RIGHT || key == Keysym.LEFT)) { + if(key == Keysym.RIGHT && this.sel_start != this.sel_end) { + this.sel_start = this.sel_drag = this.sel_end; + } + else if(key == Keysym.LEFT && this.sel_start != this.sel_end) { + this.sel_end = this.sel_drag = this.sel_start; + } + if(key == Keysym.RIGHT && this.sel_start >= 0) { + if(this.sel_end < this.text.length()) { + this.sel_start = this.sel_drag = this.sel_end += 1; + } + else { + this.sel_end = this.sel_drag = this.sel_start; + } + gui_text_update_cur(this.sel_end, true); + } + else if(key == Keysym.LEFT && this.sel_start >= 0) { + if(this.sel_start > 0) + this.sel_start -= 1; + this.sel_end = this.sel_drag = this.sel_start; + gui_text_update_cur(this.sel_end, true); + } + } + else if(!ctrl && (key == Keysym.DOWN || key == Keysym.UP)) { + if(this.xbreak) { + if(key == Keysym.DOWN && this.sel_start != this.sel_end) { + this.sel_start = this.sel_drag = this.sel_end; + } + else if(key == Keysym.UP && this.sel_start != this.sel_end) { + this.sel_end = this.sel_drag = this.sel_start; + } + if(key == Keysym.DOWN && this.sel_start >= 0) { + if(this.sel_end < this.text.length()) { + // char ch = this.text.charAt(this.sel_end); + // this.sel_end += 1; + int nl = this.text.indexOf('\n', this.sel_end); + // while(ch && ch != '\n') { + // ch = utf_readn(this.text, &this.sel_end); + // } + this.sel_end = nl >= 0 ? nl + 1 : this.text.length(); + // else + // this.sel_end -= 1; + this.sel_start = this.sel_drag = this.sel_end; + } + else { + this.sel_end = this.sel_drag = this.sel_start; + } + gui_text_update_cur(this.sel_end, true); + } + else if(key == Keysym.UP && this.sel_start >= 0) { + // uint ch; + if(this.sel_start > 0) { + int nl = this.text.lastIndexOf('\n', this.sel_start); + this.sel_start = nl >= 0 ? nl : 0; + // do { + // ch = utf_rreadn(this.text, &this.sel_start); + // } + // while(ch && ch != '\n'); + } + this.sel_end = this.sel_drag = this.sel_start; + gui_text_update_cur(this.sel_end, true); + } + } + else if(this.func != null) { + this.func.use(this, (key == Keysym.DOWN) ? Action.NEXT : Action.PREVIOUS); + } + } + else if((!ctrl) && key == Keysym.TAB) { + if(this.func != null) { + this.func.use(this, shift ? Action.BACKWARD : Action.FORWARD); + } + } + } + + public void select() { + if(this.func != null) { + this.func.use(this, Action.FOCUS); + } + } + + public void deselect() { + this.sel_start = this.sel_end = this.sel_drag = -1; + this.tmr_leftmb = 0L; + this.r_dirty = true; + if(this.func != null) { + this.func.use(this, Action.UNFOCUS); + } + } + + public void update() { + if((this.scrollx != 0 && !(this.xbreak)) || (this.scrolly != 0 && this.xbreak)) { + int n; + if(!this.xbreak) + this.text_x += (n = (int)((float)((float)this.tmr_scroll) / 1000000.0f * 4.0f * ((float)this.scrollx))); + else + this.text_y += (n = (int)((float)((float)this.tmr_scroll) / 1000000.0f * 4.0f * ((float)this.scrolly))); + if(n != 0) { + gui_text_clamp_scroll(); + this.r_dirty = true; + } + if((((long)n) * 1000000L) <= this.tmr_scroll) + this.tmr_scroll -= ((long)n) * 1000000L; + else + this.tmr_scroll = 0L; + this.tmr_scroll += Timing.tmr_delta; + } + } + + public void shift(int shift_x, int shift_y) { + super.shift(shift_x, shift_y); + this.cursorX += shift_x; + this.cursorY += shift_y; + } + + private void gui_text_clamp_scroll() { + int limit; + if(this.xbreak) { + limit = Font.YGLYPH + this.tsize_y - (this.size_y - (this.margin_y1 + this.margin_y2)); + limit = ExtMath.clampi(limit, 0, 0x7fffffff); + this.text_y = ExtMath.clampi(this.text_y, -limit, 0); + } + else { + limit = Font.XGLYPH + this.tsize_x - (this.size_x - (this.margin_x1 + this.margin_x2)); + limit = ExtMath.clampi(limit, 0, 0x7fffffff); + this.text_x = ExtMath.clampi(this.text_x, -limit, 0); + } + } + + private void gui_text_update_cur(int offset, boolean shift) { + int x1 = this.pos_x + this.margin_x1; + int y1 = this.pos_y + this.margin_y1; + int x2 = this.size_x - (this.margin_x1 + this.margin_x2); + int y2 = this.size_y - (this.margin_y1 + this.margin_y2); + gui_text_clamp_scroll(); + Vec2i coord = Drawing.txt_coord(offset, x1 + (this.xbreak ? 0 : this.text_x), y1 + this.text_y, + x1 + this.text_x, y1 + this.text_y, this.xbreak ? (this.pos_x + x2) : 0x7fffffff, 0x7fffffff, this.text); + this.cursorX = coord.xpos; + this.cursorY = coord.ypos; + if(shift) { + if(this.xbreak && this.cursorY < y1) + this.text_y += y1 - this.cursorY; + else if(this.xbreak && (this.cursorY + Font.YGLYPH) >= (y1 + y2)) + this.text_y -= (this.cursorY + Font.YGLYPH) - (y1 + y2); + if(!(this.xbreak) && this.cursorX < x1) + this.text_x += x1 - this.cursorX; + else if(!(this.xbreak) && (this.cursorX + Font.XGLYPH) >= (x1 + x2)) + this.text_x -= (this.cursorX + Font.XGLYPH) - (x1 + x2); + gui_text_update_cur(offset, false); + } + else { + this.r_dirty = true; + } + } + + public void insertText(String str) { + if(str == null || (this.sel_start == -1)) + return; + str = Util.strip(str, 0, str.length(), this.xbreak ? '\n' : ' ', ' ', (char)0); + if(this.validator != null) + str = this.validator.filter(str); + // plen = strlen(&sys.work_buf[1 + olen - this.sel_end]); + // logd("t", "%d %d %d", olen, slen, plen); + if((str.length() + this.text.length() - (this.sel_end - this.sel_start)) > this.capacity) + return; + this.text = this.text.substring(0, this.sel_start) + str + this.text.substring(this.sel_end); + // memcpy(sys.work_buf, &this.text[this.sel_end], 1 + this.text.length() - this.sel_end); + // memcpy(&this.text[this.sel_start], &sys.work_buf[1 + this.text.length() - this.sel_end], str.length()); + // memcpy(&this.text[this.sel_start + str.length()], sys.work_buf, 1 + this.text.length() - this.sel_end); + this.sel_start += str.length(); + this.sel_end = this.sel_drag = this.sel_start; + this.updateText(); + gui_text_update_cur(this.sel_end, true); + } + + private void gui_text_select(int x, int y, boolean drag) { + int x1 = this.pos_x + this.margin_x1; + int y1 = this.pos_y + this.margin_y1; + int x2 = this.size_x - (this.margin_x1 + this.margin_x2); + int y2 = this.size_y - (this.margin_y1 + this.margin_y2); + Offset off = Drawing.txt_offset(x, y, x1 + (this.xbreak ? 0 : this.text_x), y1 + this.text_y, + x1 + this.text_x, y1 + this.text_y, this.xbreak ? (this.pos_x + x2) : 0x7fffffff, 0x7fffffff, this.text); + if(off != null) { + this.cursorX = off.xpos; + this.cursorY = off.ypos; + } + int offset = off == null ? 0 : off.offset; + // logd("tst", "@A %d %d -. %d %d", x1, y1, x2, y2); + // logd("tst", "@C %d %d -. %d, %d %d", x, y, offset, this.min, this.max); + if(!drag) { + this.sel_drag = this.sel_start = this.sel_end = offset; + } + else if(drag && this.sel_drag >= 0 && offset >= this.sel_drag) { + this.sel_start = this.sel_drag; + this.sel_end = offset; + } + else if(drag && this.sel_drag >= 0 && offset < this.sel_drag) { + this.sel_start = offset; + this.sel_end = this.sel_drag; + } + // logd("tst", "@S %d . %d . %d", this.sel_start, this.sel_drag, this.sel_end); + this.r_dirty = true; + if(x < x1) + this.scrollx = x1 - x; + else if(x >= (x1 + x2)) + this.scrollx = -(x - (x1 + x2)); + if(y < y1) + this.scrolly = y1 - y; + else if(y >= (y1 + y2)) + this.scrolly = -(y - (y1 + y2)); + } + + protected void drawBackground() { + Drawing.drawGradient2Border(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.field_top, this.gm.style.field_btm, this.gm.style.brdr_top, this.gm.style.brdr_btm); + } + + protected void drawForeground(int x1, int y1, int x2, int y2) { + Drawing.txt_draw(x1 + (this.xbreak ? 0 : this.text_x), y1 + this.text_y, + x1 + this.text_x, y1 + this.text_y, + this.xbreak ? (this.pos_x + x2) : Integer.MAX_VALUE, Integer.MAX_VALUE, this.gm.style.text_field, this.text); + if(this.sel_start >= 0 && this.sel_end != this.sel_start) + Drawing.txt_draw_range(this.sel_start, this.sel_end, x1 + (this.xbreak ? 0 : this.text_x), y1 + this.text_y, + x1 + this.text_x, y1 + this.text_y, + this.xbreak ? (this.pos_x + x2) : Integer.MAX_VALUE, Integer.MAX_VALUE, this.gm.style.select, this.text); + } + + public void drawOverlay() { + if(this.editable && this.sel_start >= 0 && this.sel_end == this.sel_start && this.gm.ftime() % 1.0f < 0.5f) { + int x1 = this.pos_x + this.margin_x1; + int y1 = this.pos_y + this.margin_y1; + int x2 = this.size_x - (this.margin_x1 + this.margin_x2); + int y2 = this.size_y - (this.margin_y1 + this.margin_y2); + WCF.glScissor(x1 < 0 ? 0 : x1, (this.gm.fb_y - (y1 + y2)) < 0 ? 0 : (this.gm.fb_y - (y1 + y2)), x2 < 0 ? 0 : x2, y2 < 0 ? 0 : y2); + WCF.glEnable(WCF.GL_SCISSOR_TEST); + Drawing.drawRectColor(this.cursorX, this.cursorY, 1, Font.YGLYPH, this.gm.style.cursor); + WCF.glDisable(WCF.GL_SCISSOR_TEST); + } + } + + + + + + + + + + public void deleteFromCursor() { + int num = this.getNthCharFromPos() - this.sel_start; + if(this.text.length() != 0) { + if(this.sel_start != this.sel_end) { + this.insertText(""); + } + else { +// boolean flag = num < 0; + int i = this.sel_start + num; // flag ? this.sel_start + num : this.sel_start; + int j = this.sel_start; // flag ? this.sel_start : this.sel_start + num; + String s = ""; + + if(i >= 0) { + s = this.text.substring(0, i); + } + + if(j < this.text.length()) { + s = s + this.text.substring(j); + } + + this.setText(s); +// this.text = s; +// +// if(flag) { +// this.moveCursorBy(num); +// } + } + } + } + + public int getNthCharFromPos() { + int i = this.sel_start; + while(i > 0 && this.text.charAt(i - 1) != ' ') { + --i; + } + return i; + } + + public int getCursorPosition() { + return this.sel_start == this.sel_end ? this.sel_start : -1; + } +} diff --git a/java/src/game/gui/element/Toggle.java b/java/src/game/gui/element/Toggle.java new file mode 100644 index 0000000..c2df8f8 --- /dev/null +++ b/java/src/game/gui/element/Toggle.java @@ -0,0 +1,51 @@ +package game.gui.element; + +import game.renderer.Drawing; +import game.util.Formatter; +import game.window.Button; + +public class Toggle extends Element { + public static interface Callback { + void use(Toggle elem, boolean value); + } + + private final Callback func; + private final boolean def; + + private boolean value; + + public Toggle(int x, int y, int w, int h, boolean def, boolean init, Callback callback, Formatter formatter) { + super(x, y, w, h, formatter); + this.func = callback; + this.def = def; + this.value = init; + this.formatText(); + } + + public Toggle(int x, int y, int w, int h, boolean def, boolean init, Callback callback, final String text) { + this(x, y, w, h, def, init, callback, new Formatter() { + public String use(Toggle elem) { + return String.format("%s: %s", text, elem.value ? "An" : "Aus"); + } + }); + } + + + public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) { + boolean prev = this.value; + if((this.value = (ctrl || (btn == Button.MOUSE_MIDDLE)) ? this.def : !this.value) != prev) { +// this.type = this.value != 0 ? ElemType.TOGGLE_ON : ElemType.TOGGLE_OFF; +// gui_update_style(this, 1); + this.r_dirty = true; + this.func.use(this, this.value); + this.formatText(); + } + } + + protected void drawBackground() { + if(this.value) + Drawing.drawGradient2Border(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_btm, this.gm.style.fill_top, this.gm.style.brdr_top, this.gm.style.brdr_btm); + else + super.drawBackground(); + } +} diff --git a/java/src/game/gui/element/TransparentBox.java b/java/src/game/gui/element/TransparentBox.java new file mode 100644 index 0000000..3f7ac25 --- /dev/null +++ b/java/src/game/gui/element/TransparentBox.java @@ -0,0 +1,12 @@ +package game.gui.element; + +public class TransparentBox extends Textbox { + public TransparentBox(int x, int y, int w, int h, String text) { + super(x, y, w, h, text); + } + + protected void drawBackground() { +// Drawing.drawGradient2Border(this.pos_x, this.pos_y, this.size_x, this.size_y, +// this.gm.style.field_top & 0x80ffffff, this.gm.style.field_btm & 0x80ffffff, this.gm.style.brdr_top & 0x80ffffff, this.gm.style.brdr_btm & 0x80ffffff); + } +} diff --git a/java/src/game/log/ConsolePos.java b/java/src/game/log/ConsolePos.java new file mode 100644 index 0000000..a7836fc --- /dev/null +++ b/java/src/game/log/ConsolePos.java @@ -0,0 +1,25 @@ +package game.log; + +import game.properties.IStringSerializable; +import game.util.Displayable; + +public enum ConsolePos implements Displayable, IStringSerializable { + TOP("top", "Am oberen Bildschirmrand"), + BOTTOM("bottom", "Am unteren Bildschirmrand"); + + public final String id; + public final String name; + + private ConsolePos(String id, String name) { + this.id = id; + this.name = name; + } + + public String getName() { + return this.id; + } + + public String getDisplay() { + return this.name; + } +} diff --git a/java/src/game/log/Log.java b/java/src/game/log/Log.java new file mode 100644 index 0000000..216db62 --- /dev/null +++ b/java/src/game/log/Log.java @@ -0,0 +1,206 @@ +package game.log; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.List; + +import game.Game; +import game.collect.Lists; +import game.color.TextColor; + +public enum Log { + SYSTEM("System"), + RENDER("Render"), + IO("I/O"), + CONSOLE("Console"), + TICK("Tick"), + SOUND("Sound"), + JNI("JNI"); + + private static class LogMessage { + private final LogLevel level; + private final String prefix; + private final String[] lines; + + private LogMessage(LogLevel level, String prefix, String[] lines) { + this.level = level; + this.prefix = prefix; + this.lines = lines; + } + } + + public static final char CHR_CRESET = 0x01; + public static final char CHR_COLORS2 = 0x02; + public static final char CHR_COLORE2 = 0x09; + public static final char CHR_NLN = 0x0a; + public static final char CHR_COLORS1 = 0x0b; + public static final char CHR_COLORE1 = 0x1f; + public static final char CHR_SPC = 0x20; + public static final char CHR_UNK = 0x7f; + + private static final List LOG = Lists.newArrayList(); + + private final String prefix; + + private Log(String prefix) { + this.prefix = prefix; + } + + private static void logOut(String str) { + char c; + int pos = 0; + int last = 0; + int color; + while(pos < str.length()) { + c = str.charAt(pos); + if(((c >= CHR_COLORS1) && (c <= CHR_COLORE1)) || ((c >= CHR_COLORS2) && (c <= CHR_COLORE2))) { + if(pos - last != 0) + System.err.print(str.substring(last, pos)); + color = TextColor.getColor(c); // (c >= CHR_COLORS2) && (c <= CHR_COLORE2) ? aux_colors[c - CHR_COLORS2] : text_colors[c - CHR_COLORS1]; + System.err.printf("\u001b[38;2;%d;%d;%dm", (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff); + last = ++pos; + continue; + } + else if(c == CHR_CRESET) { + if(pos - last != 0) + System.err.print(str.substring(last, pos)); + System.err.print("\u001b[0m"); + last = ++pos; + continue; + } + else if(c == CHR_UNK) { + if(pos - last != 0) + System.err.print(str.substring(last, pos)); + System.err.print("?"); + last = ++pos; + continue; + } + else if(c >= 0 && c < CHR_SPC && c != CHR_NLN) { + if(pos - last != 0) + System.err.print(str.substring(last, pos)); + last = ++pos; + continue; + } + pos++; + if(pos >= str.length() && pos - last != 0) + System.err.print(str.substring(last, pos)); + } + System.err.print("\u001b[0m\n"); + } + + public static String str_time(long time) { + long secs = (time /= 1000000L) % 60L; + long mins = (time /= 60L) % 60L; + long hrs = (time /= 60L) % 24L; + time /= 24L; + return time > 0 ? String.format("%dD+%02d:%02d:%02d", time, hrs, mins, secs) : String.format("%02d:%02d:%02d", hrs, mins, secs); + } + + public static void flushLog() { + synchronized(LOG) { + while(!LOG.isEmpty()) { + LogMessage msg = LOG.remove(0); + for(String line : msg.lines) { + line = msg.level.color + line; + Game.getGame().log(msg.prefix + line, line); + logOut(msg.prefix + line); + } + } + } + } + + private void log(LogLevel level, String msg) { + if(level.ordinal() > Game.getGame().level.ordinal()) + return; + String prefix = String.format(TextColor.DGRAY + "[" + TextColor.GREEN + "%s" + TextColor.DGRAY + "][" + TextColor.LGRAY + "%s" + TextColor.DGRAY + "|" + TextColor.LGRAY + "%s" + + TextColor.DGRAY + "][%s%s" + TextColor.DGRAY + "] ", + str_time(Game.getGame().rtime()), this.prefix, Thread.currentThread().getName(), level.color, level.log); + String[] lines = msg.split("\n"); + if(/* Game.getGame() == null || */ Game.getGame().isMainThread()) { + for(String line : lines) { + line = level.color + line; + Game.getGame().log(prefix + line, line); + logOut(prefix + line); + } + } + else { + synchronized(LOG) { + LOG.add(new LogMessage(level, prefix, lines)); + } + } + } + + public void user(String fmt, Object ... args) { + this.log(LogLevel.USER, String.format(fmt, args)); + } + + public void error(String fmt, Object ... args) { + this.log(LogLevel.ERROR, String.format(fmt, args)); + } + + public void warn(String fmt, Object ... args) { + this.log(LogLevel.WARN, String.format(fmt, args)); + } + + public void info(String fmt, Object ... args) { + this.log(LogLevel.INFO, String.format(fmt, args)); + } + + public void perf(String fmt, Object ... args) { + this.log(LogLevel.PERF, String.format(fmt, args)); + } + + public void debug(String fmt, Object ... args) { + this.log(LogLevel.DEBUG, String.format(fmt, args)); + } + + public void trace(String fmt, Object ... args) { + this.log(LogLevel.TRACE, String.format(fmt, args)); + } + + public void error(Throwable ex, String fmt, Object ... args) { + this.log(LogLevel.ERROR, String.format(fmt, args)); + StringWriter sw = new StringWriter(); + PrintWriter st = new PrintWriter(sw); + ex.printStackTrace(st); + sw.flush(); + this.log(LogLevel.ERROR, sw.toString().trim().replace('\t', ' ')); + } + + public void user(String msg) { + this.log(LogLevel.USER, msg); + } + + public void error(String msg) { + this.log(LogLevel.ERROR, msg); + } + + public void warn(String msg) { + this.log(LogLevel.WARN, msg); + } + + public void info(String msg) { + this.log(LogLevel.INFO, msg); + } + + public void perf(String msg) { + this.log(LogLevel.PERF, msg); + } + + public void debug(String msg) { + this.log(LogLevel.DEBUG, msg); + } + + public void trace(String msg) { + this.log(LogLevel.TRACE, msg); + } + + public void error(Throwable ex, String msg) { + this.log(LogLevel.ERROR, msg); + StringWriter sw = new StringWriter(); + PrintWriter st = new PrintWriter(sw); + ex.printStackTrace(st); + sw.flush(); + this.log(LogLevel.ERROR, sw.toString().trim().replace('\t', ' ')); + } +} diff --git a/java/src/game/log/LogLevel.java b/java/src/game/log/LogLevel.java new file mode 100644 index 0000000..2af9bb6 --- /dev/null +++ b/java/src/game/log/LogLevel.java @@ -0,0 +1,36 @@ +package game.log; + +import game.color.TextColor; +import game.properties.IStringSerializable; +import game.util.Displayable; + +public enum LogLevel implements Displayable, IStringSerializable { + SILENT("silent", "Nichts", "UNK?", TextColor.BLACK), + USER("user", "Benutzer", "USER", TextColor.WHITE), + ERROR("error", "Fehler", "ERR!", TextColor.RED), + WARN("warn", "Warnung", "WARN", TextColor.YELLOW), + INFO("info", "Info", "INFO", TextColor.BLUE), + PERF("perf", "Leistung", "PERF", TextColor.CYAN), + DEBUG("debug", "*Debug*", "DBG#", TextColor.MAGENTA), + TRACE("trace", "*Trace*", "TRC#", TextColor.VIOLET); + + public final String id; + public final String name; + public final String log; + public final TextColor color; + + private LogLevel(String id, String name, String log, TextColor color) { + this.id = id; + this.name = name; + this.log = log; + this.color = color; + } + + public String getName() { + return this.id; + } + + public String getDisplay() { + return this.name; + } +} \ No newline at end of file diff --git a/java/src/game/log/Message.java b/java/src/game/log/Message.java new file mode 100644 index 0000000..47146fe --- /dev/null +++ b/java/src/game/log/Message.java @@ -0,0 +1,11 @@ +package game.log; + +public class Message { + public final String message; + public final long time; + + public Message(String message, long time) { + this.message = message; + this.time = time; + } +} diff --git a/java/src/game/renderer/Drawing.java b/java/src/game/renderer/Drawing.java new file mode 100644 index 0000000..8c87bc0 --- /dev/null +++ b/java/src/game/renderer/Drawing.java @@ -0,0 +1,548 @@ +package game.renderer; + +import game.color.TextColor; +import game.gui.Font; +import game.gui.FontChar; +import game.log.Log; + +public abstract class Drawing { + public static class Vec2i { + public final int xpos; + public final int ypos; + + private Vec2i(int x, int y) { + this.xpos = x; + this.ypos = y; + } + } + + public static class Offset extends Vec2i { + public final int offset; + + private Offset(int off, int x, int y) { + super(x, y); + this.offset = off; + } + } + +// private static final int FLAG_ULINE = 0x01; +// private static final int FLAG_CLINE = 0x02; +// private static final int FLAG_BLINK = 0x04; +// private static final int FLAG_FADE = 0x08; + +// public static void drawTexturedModalRect(int tw, int th, int x, int y, int textureX, int textureY, int width, int height) +// { +// float xs = 1.0f / (float)tw; // 0.00390625F; +// float ys = 1.0f / (float)th; // 0.00390625F; +// RenderBuffer rb = Tessellator.getBuffer(); +// rb.begin(7, DefaultVertexFormats.POSITION_TEX); +// rb.pos((double)(x + 0), (double)(y + height), 0.0).tex((double)((float)(textureX + 0) * xs), (double)((float)(textureY + height) * ys)).endVertex(); +// rb.pos((double)(x + width), (double)(y + height), 0.0).tex((double)((float)(textureX + width) * xs), (double)((float)(textureY + height) * ys)).endVertex(); +// rb.pos((double)(x + width), (double)(y + 0), 0.0).tex((double)((float)(textureX + width) * xs), (double)((float)(textureY + 0) * ys)).endVertex(); +// rb.pos((double)(x + 0), (double)(y + 0), 0.0).tex((double)((float)(textureX + 0) * xs), (double)((float)(textureY + 0) * ys)).endVertex(); +// Tessellator.draw(); +// } + + public static void drawTexturedModalRect(RenderBuffer rb, int tw, int th, int x, int y, int textureX, int textureY, int width, int height, int color) + { + float xs = 1.0f / (float)tw; // 0.00390625F; + float ys = 1.0f / (float)th; // 0.00390625F; + rb.pos((double)(x + 0), (double)(y + height), 0.0).tex((double)((float)(textureX + 0) * xs), (double)((float)(textureY + height) * ys)).color(color).endVertex(); + rb.pos((double)(x + width), (double)(y + height), 0.0).tex((double)((float)(textureX + width) * xs), (double)((float)(textureY + height) * ys)).color(color).endVertex(); + rb.pos((double)(x + width), (double)(y + 0), 0.0).tex((double)((float)(textureX + width) * xs), (double)((float)(textureY + 0) * ys)).color(color).endVertex(); + rb.pos((double)(x + 0), (double)(y + 0), 0.0).tex((double)((float)(textureX + 0) * xs), (double)((float)(textureY + 0) * ys)).color(color).endVertex(); + } + + private static void color(int c) { + float a = (float)(c >> 24 & 255) / 255.0F; + float r = (float)(c >> 16 & 255) / 255.0F; + float g = (float)(c >> 8 & 255) / 255.0F; + float b = (float)(c & 255) / 255.0F; + GlState.color(r, g, b, a); + } + +// private static void trect(int left, int top, int right, int bottom) +// { +// RenderBuffer worldrenderer = Tessellator.getBuffer(); +// worldrenderer.begin(7, DefaultVertexFormats.POSITION); +// worldrenderer.pos((double)left, (double)bottom, 0.0D).endVertex(); +// worldrenderer.pos((double)right, (double)bottom, 0.0D).endVertex(); +// worldrenderer.pos((double)right, (double)top, 0.0D).endVertex(); +// worldrenderer.pos((double)left, (double)top, 0.0D).endVertex(); +// Tessellator.draw(); +// } + + public static void txt_draw(int x, int y, int x1, int y1, int x2, int y2, int color, String str) { + GlState.enableTexture2D(); + GlState.enableBlend(); + GlState.disableAlpha(); + GlState.tryBlendFuncSeparate(770, 771, 1, 0); + GlState.shadeModel(7425); + GlState.color(1.0f, 1.0f, 1.0f, 1.0f); + Font.bindTexture(); + RenderBuffer rb = Tessellator.getBuffer(); + rb.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + int h = Font.YGLYPH; + int tx, ty, u, v; + FontChar glyph; + char ch; + int ncolor = color; +// color(color); + for(int z = 0; z < str.length(); z++) { + ch = str.charAt(z); + if(ch == Log.CHR_NLN) { + x = x1; + y += h; + continue; + } +// else if(ch >= Log.CHR_ULINE && ch <= Log.CHR_FADE) { +// continue; +// } + else if((ch >= Log.CHR_COLORS1 && ch <= Log.CHR_COLORE1) || (ch >= Log.CHR_COLORS2 && ch <= Log.CHR_COLORE2)) { +// color(TextColor.getColor(ch) | (color & 0xff000000)); + ncolor = TextColor.getColor(ch) | (color & 0xff000000); + continue; + } +// else if(ch == Log.CHR_FRESET) { +// continue; +// } + else if(ch == Log.CHR_CRESET) { +// color(color); + ncolor = color; + continue; + } + if(ch >= 256) + ch = Log.CHR_UNK; + glyph = Font.SIZES[ch]; + if(glyph.u == 0 && glyph.v != 0) + continue; + else if(glyph.u == 0) + glyph = Font.SIZES[Log.CHR_UNK]; + u = glyph.u + 3 - glyph.s; + v = h; + tx = ((x + u) > x2) ? x1 : x; + ty = ((x + u) > x2) ? y + h : y; + x = tx; + y = ty; + if(x < x1 || y < y1 || x > x2 || y > y2) { + break; + } + drawTexturedModalRect(rb, Font.XGLYPH * 16, Font.YGLYPH * 16, x, y, (ch & 0x0f) * Font.XGLYPH + glyph.s, ((ch & 0xf0) >> 4) * Font.YGLYPH, glyph.u, h, ncolor); + x += u; + } + Tessellator.draw(); + GlState.shadeModel(7424); + GlState.disableBlend(); + GlState.enableAlpha(); + GlState.enableTexture2D(); + } + + public static void txt_draw_range(int start, int end, int x, int y, int x1, int y1, int x2, int y2, int back, String str) { + int h = Font.YGLYPH; + int tx, ty, u, v; + FontChar glyph; + char ch; + int pos = 0; + int lpos = 0; +// ShaderContext shd = Shader.TEXT.use(); +// shd.setVec2("font_size", (float)font.xglyph, (float)font.yglyph); +// shd.setInt("flags", 0); +// shd.setColor("color", 0x00000000); +// shd.setColor("back", back); +// shd.setInt("ch_index", Log.CHR_SPC & 0xff); +// GlState.bindTexture(font.textures[Log.CHR_SPC >> 8]); + while(true) { + pos = lpos; + if(lpos >= str.length()) + break; + ch = str.charAt(lpos++); + if(ch == Log.CHR_NLN) { + x = x1; + y += h; + continue; + } + else if(ch < Log.CHR_SPC) { + continue; + } + if(ch >= 256) + ch = Log.CHR_UNK; + glyph = Font.SIZES[ch]; + if(glyph.u == 0 && glyph.v != 0) + continue; + else if(glyph.u == 0) + glyph = Font.SIZES[Log.CHR_UNK]; + u = glyph.u + 3 - glyph.s; + v = h; + tx = ((x + u) > x2) ? x1 : x; + ty = ((x + u) > x2) ? y + h : y; + x = tx; + y = ty; + if(x < x1 || y < y1 || x > x2 || y > y2) { + break; + } + if(pos >= start && pos < end) { +// shd.setVec2("offset", (float)x, (float)y); +// shd.setVec2("size", (float)u, (float)v); +// shd.setVec4("glyph", (float)glyph.s, 0.0f, (float)glyph.u, (float)h); +// shd.draw(); + drawRect(x, y, x + u, y + v, back); + } + x += u; + } +// shd.discard(); + } + + public static Vec2i txt_size(int x, int y, int x1, int y1, int x2, int y2, String str) { + int h = Font.YGLYPH; + int ix = x; + int iy = y; + int tx, ty, u, v; + FontChar glyph; + char ch; + for(int z = 0; z < str.length(); z++) { + ch = str.charAt(z); + if(ch == Log.CHR_NLN) { + x = x1; + y += h; + continue; + } + else if(ch < Log.CHR_SPC) { + continue; + } + if(ch >= 256) + ch = Log.CHR_UNK; + glyph = Font.SIZES[ch]; + if(glyph.u == 0 && glyph.v != 0) + continue; + else if(glyph.u == 0) + glyph = Font.SIZES[Log.CHR_UNK]; + u = glyph.u + 3 - glyph.s; + v = h; + tx = ((x + u) > x2) ? x1 : x; + ty = ((x + u) > x2) ? y + h : y; + x = tx; + y = ty; + if(x < x1 || y < y1 || x > x2 || y > y2) { + break; + } + x += u; + } + return new Vec2i(x - ix, y - iy); + } + + public static Vec2i txt_box(int x, int y, int x1, int y1, int x2, int y2, String str) { + int h = Font.YGLYPH; + int ix = x; +// int iy = y; + int tx, ty, u, v; + FontChar glyph; + char ch; + for(int z = 0; z < str.length(); z++) { + ch = str.charAt(z); + if(ch == Log.CHR_NLN) { + x = x1; + y += h; + continue; + } + else if(ch < Log.CHR_SPC) { + continue; + } + if(ch >= 256) + ch = Log.CHR_UNK; + glyph = Font.SIZES[ch]; + if(glyph.u == 0 && glyph.v != 0) + continue; + else if(glyph.u == 0) + glyph = Font.SIZES[Log.CHR_UNK]; + u = glyph.u + 3 - glyph.s; + v = h; + tx = ((x + u) > x2) ? x1 : x; + ty = ((x + u) > x2) ? y + h : y; + x = tx; + y = ty; + if(x < x1 || y < y1 || x > x2 || y > y2) { + break; + } + x += u; + ix = x > ix ? x : ix; + } + return new Vec2i(ix - 2, y + h); + } + + public static Vec2i txt_coord(int offset, int x, int y, int x1, int y1, int x2, int y2, String str) { + int h = Font.YGLYPH; + int tx, ty, u, v; + FontChar glyph; + char ch; + int pos = 0; + int lpos = 0; + while(true) { + pos = lpos; + if(lpos >= str.length()) + break; + ch = str.charAt(lpos++); + if(pos == offset) { + return new Vec2i(x, y); + } + if(ch == Log.CHR_NLN) { + x = x1; + y += h; + continue; + } + else if(ch < Log.CHR_SPC) { + continue; + } + if(ch >= 256) + ch = Log.CHR_UNK; + glyph = Font.SIZES[ch]; + if(glyph.u == 0 && glyph.v != 0) + continue; + else if(glyph.u == 0) + glyph = Font.SIZES[Log.CHR_UNK]; + u = glyph.u + 3 - glyph.s; + v = h; + tx = ((x + u) > x2) ? x1 : x; + ty = ((x + u) > x2) ? y + h : y; + x = tx; + y = ty; + if(x < x1 || y < y1 || x > x2 || y > y2) { + break; + } + x += u; + } + return new Vec2i(x, y); + } + + public static Offset txt_offset(int ox, int oy, int x, int y, int x1, int y1, int x2, int y2, String str) { + int h = Font.YGLYPH; + int tx, ty, u, v; + FontChar glyph; + char ch; + int pos = 0; + int lpos = 0; + if(oy < y) { + return null; + } + ox = ox < x1 ? x1 : ox; + while(true) { + pos = lpos; + if(lpos >= str.length()) + break; + ch = str.charAt(lpos++); + if(ch == Log.CHR_NLN) { + if(ox >= x && oy >= y && oy < (y + h)) { + return new Offset(pos, x, y); + } + x = x1; + y += h; + continue; + } + else if(ch < Log.CHR_SPC) { + continue; + } + if(ch >= 256) + ch = Log.CHR_UNK; + glyph = Font.SIZES[ch]; + if(glyph.u == 0 && glyph.v != 0) + continue; + else if(glyph.u == 0) + glyph = Font.SIZES[Log.CHR_UNK]; + u = glyph.u + 3 - glyph.s; + v = h; + tx = ((x + u) > x2) ? x1 : x; + ty = ((x + u) > x2) ? y + h : y; + if(ty > y && ox >= x && oy >= y && oy < (y + h)) { + return new Offset(pos, tx, ty); + } + x = tx; + y = ty; + if(x < x1 || y < y1 || x > x2 || y > y2) { + pos = lpos; + break; + } + if(ox >= x && oy >= y && ox < (x + u) && oy < (y + h)) { + return new Offset(pos, x, y); + } + x += u; + } + return new Offset(pos, x, y); + } + +// public static void gfx_blit(int tex) { +// ShaderContext shd = Shader.BLIT.use(); +// GlState.bindTexture(tex); +// shd.draw(); +// shd.discard(); +// } + + public static void drawGradientRect(int left, int top, int right, int bottom, int ctop, int cbottom) + { + float at = (float)(ctop >> 24 & 255) / 255.0F; + float rt = (float)(ctop >> 16 & 255) / 255.0F; + float gt = (float)(ctop >> 8 & 255) / 255.0F; + float bt = (float)(ctop & 255) / 255.0F; + float ab = (float)(cbottom >> 24 & 255) / 255.0F; + float rb = (float)(cbottom >> 16 & 255) / 255.0F; + float gb = (float)(cbottom >> 8 & 255) / 255.0F; + float bb = (float)(cbottom & 255) / 255.0F; + GlState.disableTexture2D(); + GlState.enableBlend(); + GlState.disableAlpha(); + GlState.tryBlendFuncSeparate(770, 771, 1, 0); + GlState.shadeModel(7425); + RenderBuffer buf = Tessellator.getBuffer(); + buf.begin(7, DefaultVertexFormats.POSITION_COLOR); + buf.pos((double)right, (double)top, 0.0).color(rt, gt, bt, at).endVertex(); + buf.pos((double)left, (double)top, 0.0).color(rt, gt, bt, at).endVertex(); + buf.pos((double)left, (double)bottom, 0.0).color(rb, gb, bb, ab).endVertex(); + buf.pos((double)right, (double)bottom, 0.0).color(rb, gb, bb, ab).endVertex(); + Tessellator.draw(); + GlState.shadeModel(7424); + GlState.disableBlend(); + GlState.enableAlpha(); + GlState.enableTexture2D(); + } + + public static void draw4GradientRect(int left, int top, int right, int bottom, int lopleft, int topright, int btmleft, int btmright) + { + GlState.disableTexture2D(); + GlState.enableBlend(); + GlState.disableAlpha(); + GlState.tryBlendFuncSeparate(770, 771, 1, 0); + GlState.shadeModel(7425); + RenderBuffer buf = Tessellator.getBuffer(); + buf.begin(7, DefaultVertexFormats.POSITION_COLOR); + buf.pos((double)right, (double)top, 0.0).color(topright).endVertex(); + buf.pos((double)left, (double)top, 0.0).color(lopleft).endVertex(); + buf.pos((double)left, (double)bottom, 0.0).color(btmleft).endVertex(); + buf.pos((double)right, (double)bottom, 0.0).color(btmright).endVertex(); + Tessellator.draw(); + GlState.shadeModel(7424); + GlState.disableBlend(); + GlState.enableAlpha(); + GlState.enableTexture2D(); + } + + public static void drawRect(int left, int top, int right, int bottom, int color) + { + if (left < right) + { + int i = left; + left = right; + right = i; + } + + if (top < bottom) + { + int j = top; + top = bottom; + bottom = j; + } + + float f3 = (float)(color >> 24 & 255) / 255.0F; + float f = (float)(color >> 16 & 255) / 255.0F; + float f1 = (float)(color >> 8 & 255) / 255.0F; + float f2 = (float)(color & 255) / 255.0F; + RenderBuffer worldrenderer = Tessellator.getBuffer(); + GlState.enableBlend(); + GlState.disableAlpha(); + GlState.disableTexture2D(); + GlState.tryBlendFuncSeparate(770, 771, 1, 0); + GlState.shadeModel(7425); + GlState.color(f, f1, f2, f3); + worldrenderer.begin(7, DefaultVertexFormats.POSITION); + worldrenderer.pos((double)left, (double)bottom, 0.0D).endVertex(); + worldrenderer.pos((double)right, (double)bottom, 0.0D).endVertex(); + worldrenderer.pos((double)right, (double)top, 0.0D).endVertex(); + worldrenderer.pos((double)left, (double)top, 0.0D).endVertex(); + Tessellator.draw(); + GlState.shadeModel(7424); + GlState.enableTexture2D(); + GlState.disableBlend(); + GlState.enableAlpha(); + GlState.color(1.0f, 1.0f, 1.0f, 1.0f); + } + +// public static void gfx_draw_rect(int x, int y, int w, int h, int border, int top, int bottom, int b_top, int b_bottom) { +// drawGradientRect(x, y, x + w, y + h, b_top, b_bottom); +// drawGradientRect(x + border, y + border, x + w - border, y + h - border, top, bottom); +// } + + public static void drawRectColor(int x, int y, int w, int h, int color) { + drawRect(x, y, x + w, y + h, color); + } + + public static void drawGradient(int x, int y, int w, int h, int top, int bottom) { + drawGradientRect(x, y, x + w, y + h, top, bottom); + } + + public static void drawRectBorder(int x, int y, int w, int h, int color, int border) { + drawRect(x, y, x + w, y + h, border); + drawRect(x + 1, y + 1, x + w - 1, y + h - 1, color); + } + +// public static void drawRect2Border(int x, int y, int w, int h, int color, int border) { +// drawRect(x, y, x + w, y + h, border); +// drawRect(x + 2, y + 2, x + w - 2, y + h - 2, color); +// } + + public static void drawRect2GradBorder(int x, int y, int w, int h, int color, int border, int lopleft, int topright, int btmleft, int btmright) { + drawRect(x, y, x + w, y + h, border); + draw4GradientRect(x + 1, y + 1, x + w - 1, y + h - 1, lopleft, topright, btmleft, btmright); + drawRect(x + 2, y + 2, x + w - 2, y + h - 2, color); + } + + public static void drawGradient2GradBorder(int x, int y, int w, int h, int top, int bottom, int border, int lopleft, int topright, int btmleft, int btmright) { + drawRect(x, y, x + w, y + h, border); + draw4GradientRect(x + 1, y + 1, x + w - 1, y + h - 1, lopleft, topright, btmleft, btmright); + drawGradientRect(x + 2, y + 2, x + w - 2, y + h - 2, top, bottom); + } + + public static void drawGradient2Border(int x, int y, int w, int h, int top, int bottom, int b_top, int b_bottom) { + drawGradientRect(x, y, x + w, y + h, b_top, b_bottom); + drawGradientRect(x + 1, y + 1, x + w - 1, y + h - 1, top, bottom); + } + + public static Vec2i getSize(String str) { + return txt_size(0, 0, 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, str); + } + + public static int getWidth(String str) { + return txt_size(0, 0, 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, str).xpos; + } + + public static void drawTextbox(String str, int x, int y, int back) { + Vec2i size = txt_box(x + 2, y, x + 2, y, Integer.MAX_VALUE, Integer.MAX_VALUE, str); + drawRect(x, y, size.xpos + 2, size.ypos, back); + txt_draw(x + 2, y, x + 2, y, Integer.MAX_VALUE, Integer.MAX_VALUE, 0xffffffff, str); + } + + public static void drawTextboxRight(String str, int x, int y, int back) { + Vec2i size = getSize(str); + drawTextbox(str, x - (size.xpos + 2), y, back); + } + + public static void drawTextboxCentered(String str, int x, int y, int back) { + Vec2i size = getSize(str); + drawTextbox(str, x - (size.xpos + 2) / 2, y, back); + } + + public static void drawText(String str, int x, int y, int color) { + txt_draw(x, y, x, y, Integer.MAX_VALUE, Integer.MAX_VALUE, color, str); + } + + public static void drawTextRight(String str, int x, int y, int color) { + Vec2i size = getSize(str); + drawText(str, x - size.xpos, y, color); + } + + public static void drawTextUpward(String str, int x, int y, int color) { + Vec2i size = getSize(str); + drawText(str, x - size.xpos / 2, y - size.ypos, color); + } + + public static int mixColor(int c1, int c2) { + return ((((c1 >> 24 & 255) + (c2 >> 24 & 255)) / 2) << 24) | ((((c1 >> 16 & 255) + (c2 >> 16 & 255)) / 2) << 16) | ((((c1 >> 8 & 255) + (c2 >> 8 & 255)) / 2) << 8) | + (((c1 & 255) + (c2 & 255)) / 2); + } +} diff --git a/java/src/game/util/CharValidator.java b/java/src/game/util/CharValidator.java new file mode 100644 index 0000000..2a22181 --- /dev/null +++ b/java/src/game/util/CharValidator.java @@ -0,0 +1,24 @@ +package game.util; + +public interface CharValidator { + boolean valid(char ch); + + default String filter(String str) { + StringBuilder sb = new StringBuilder(); + for(int z = 0; z < str.length(); z++) { + char ch = str.charAt(z); + if(this.valid(ch)) + sb.append(ch); + } + return sb.toString(); + } + + default boolean valid(String str) { + for(int z = 0; z < str.length(); z++) { + char ch = str.charAt(z); + if(!this.valid(ch)) + return false; + } + return true; + } +} \ No newline at end of file diff --git a/java/src/game/util/DC32.java b/java/src/game/util/DC32.java new file mode 100644 index 0000000..2a22138 --- /dev/null +++ b/java/src/game/util/DC32.java @@ -0,0 +1,44 @@ +package game.util; + +public class DC32 { + public static final byte[] ASCII = { // 0x1f -> AUX1 + 0, ' ', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'G', // $00, $80 + 'H', 'I', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'V', 'W', 'X', 'Z', 0 // $10, $90 + }; + + public static final byte[] AUX1 = { // 0x01 -> lc / UC, 0x1f -> AUX2 + 0, 0, '!', '"', '#', '$', '%', '&', '\'', '*', '+', ',', '-', '.', '/', 'F', // $20, $A0 + ':', '1', 'J', ';', '=', '?', '0', '\\', 'Q', '^', '_', 'U', '|', '~', 'Y', 0 // $30, $B0 + }; + + public static final byte[] AUX2 = { // 0x0f -> [0x10 ~ 0x1f ... 0x0f -> UTF] | [0x01 ~ 0x0e -> AUX3], 0x0c -> STR_WSPC + 0, 0x01, '(', ')', '<', '>', '@', '[', ']', '`', '{', '}', 0, 0x7f, 0x0a, 0, // $40 + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f // $50 + }; + + public static final byte[] AUX3 = { // 0x01 -> SYM_DEMON + 0, 0, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0 // $60 + }; + + public static final char[] ASCII_TO_DC32 = { + 0x00, 0x41, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x4e, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x01, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x42, 0x43, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x36, 0x31, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x30, 0x33, 0x44, 0x34, 0x45, 0x35, + 0x46, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x2f, 0x0f, 0x10, 0x11, 0x32, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x38, 0x18, 0x19, 0x1a, 0x3b, 0x1b, 0x1c, 0x1d, 0x3e, 0x1e, 0x47, 0x37, 0x48, 0x39, 0x3a, + 0x49, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0xaf, 0x8f, 0x90, 0x91, 0xb2, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0xb8, 0x98, 0x99, 0x9a, 0xbb, 0x9b, 0x9c, 0x9d, 0xbe, 0x9e, 0x4a, 0x3c, 0x4b, 0x3d, 0x4d + }; + + public static final byte[] ASCII_TO_DC32S = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x16, 0x11, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0, 0, 0, 0, 0, 0, + 0, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x1b, 0x0f, 0x10, 0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x16, 0x18, 0x19, 0x1a, 0x1b, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0, 0, 0, 0, 0, + 0, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x1b, 0x0f, 0x10, 0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x16, 0x18, 0x19, 0x1a, 0x1b, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0, 0, 0, 0, 0 + }; +} diff --git a/java/src/game/util/Displayable.java b/java/src/game/util/Displayable.java new file mode 100644 index 0000000..376ddff --- /dev/null +++ b/java/src/game/util/Displayable.java @@ -0,0 +1,5 @@ +package game.util; + +public interface Displayable { + public String getDisplay(); +} diff --git a/java/src/game/util/ExtMath.java b/java/src/game/util/ExtMath.java new file mode 100755 index 0000000..be7b98b --- /dev/null +++ b/java/src/game/util/ExtMath.java @@ -0,0 +1,163 @@ +package game.util; + +public abstract class ExtMath { + private static final float[] SIN_TABLE = new float[65536]; + private static final double ATAN_ADD = Double.longBitsToDouble(4805340802404319232L); + private static final double[] ATAN_SIN = new double[257]; + private static final double[] ATAN_COS = new double[257]; + + static { + for(int z = 0; z < 65536; z++) { + SIN_TABLE[z] = (float)Math.sin((double)z * Math.PI * 2.0D / 65536.0D); + } + for(int z = 0; z < 257; z++) { + double a = Math.asin((double)z / 256.0D); + ATAN_COS[z] = Math.cos(a); + ATAN_SIN[z] = a; + } + } + + public static float sin(float value) { + return SIN_TABLE[(int)(value * 10430.378F) & 65535]; + } + + public static float cos(float value) { + return SIN_TABLE[(int)(value * 10430.378F + 16384.0F) & 65535]; + } + + public static float sqrtf(float value) { + return (float)Math.sqrt((double)value); + } + + public static float sqrtd(double value) { + return (float)Math.sqrt(value); + } + + public static int floorf(float value) { + int i = (int)value; + return value < (float)i ? i - 1 : i; + } + + public static int floord(double value) { + int i = (int)value; + return value < (double)i ? i - 1 : i; + } + + public static float absf(float value) { + return value >= 0.0F ? value : -value; + } + + public static int absi(int value) { + return value >= 0 ? value : -value; + } + + public static int ceilf(float value) { + int i = (int)value; + return value > (float)i ? i + 1 : i; + } + + public static int ceild(double value) { + int i = (int)value; + return value > (double)i ? i + 1 : i; + } + + public static int clampi(int num, int min, int max) { + return num < min ? min : (num > max ? max : num); + } + + public static float clampf(float num, float min, float max) { + return num < min ? min : (num > max ? max : num); + } + + public static double clampd(double num, double min, double max) { + return num < min ? min : (num > max ? max : num); + } + + public static float wrapf(float value) { + value = value % 360.0F; + + if(value >= 180.0F) { + value -= 360.0F; + } + + if(value < -180.0F) { + value += 360.0F; + } + + return value; + } + + public static double wrapd(double value) { + value = value % 360.0D; + + if(value >= 180.0D) { + value -= 360.0D; + } + + if(value < -180.0D) { + value += 360.0D; + } + + return value; + } + + public static double atan2(double v1, double v2) { + double d0 = v2 * v2 + v1 * v1; + + if(Double.isNaN(d0)) { + return Double.NaN; + } + else { + boolean flag = v1 < 0.0D; + + if(flag) { + v1 = -v1; + } + + boolean flag1 = v2 < 0.0D; + + if(flag1) { + v2 = -v2; + } + + boolean flag2 = v1 > v2; + + if(flag2) { + double d1 = v2; + v2 = v1; + v1 = d1; + } + + double p1 = 0.5D * d0; + long li = Double.doubleToRawLongBits(d0); + li = 6910469410427058090L - (li >> 1); + d0 = Double.longBitsToDouble(li); + d0 = d0 * (1.5D - p1 * d0 * d0); + + v2 = v2 * d0; + v1 = v1 * d0; + double d2 = ATAN_ADD + v1; + int i = (int)Double.doubleToRawLongBits(d2); + double d3 = ATAN_SIN[i]; + double d4 = ATAN_COS[i]; + double d5 = d2 - ATAN_ADD; + double d6 = v1 * d4 - v2 * d5; + double d7 = (6.0D + d6 * d6) * d6 * 0.16666666666666666D; + double d8 = d3 + d7; + + if(flag2) { + d8 = (Math.PI / 2D) - d8; + } + + if(flag1) { + d8 = Math.PI - d8; + } + + if(flag) { + d8 = -d8; + } + + return d8; + } + } +} diff --git a/java/src/game/util/FileCallback.java b/java/src/game/util/FileCallback.java new file mode 100644 index 0000000..0c840c7 --- /dev/null +++ b/java/src/game/util/FileCallback.java @@ -0,0 +1,7 @@ +package game.util; + +import java.io.File; + +public interface FileCallback { + void selected(File file); +} \ No newline at end of file diff --git a/java/src/game/util/FileUtils.java b/java/src/game/util/FileUtils.java new file mode 100644 index 0000000..547a9b3 --- /dev/null +++ b/java/src/game/util/FileUtils.java @@ -0,0 +1,97 @@ +package game.util; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import game.log.Log; +import game.net.util.CharsetUtil; + +public class FileUtils { + public static String read(InputStream input) throws IOException { + return new String(readBytes(input), CharsetUtil.UTF_8); + } + + public static byte[] readBytes(InputStream input) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + long count = 0L; + int n; + for(boolean u = false; -1 != (n = input.read(buffer)); count += (long)n) { + output.write(buffer, 0, n); + } + return output.toByteArray(); + } + + public static String read(File file) throws IOException { + FileInputStream in = null; + String s; + try { + in = new FileInputStream(file); + s = FileUtils.read(in); + } + finally { + try { + if(in != null) + in.close(); + } + catch(IOException e) { + } + } + return s; + } + + public static void write(File file, String data) throws IOException { + FileOutputStream out = null; + try { + out = new FileOutputStream(file); + if(out != null) { + out.write(data.getBytes(CharsetUtil.UTF_8)); + out.close(); + } + } + finally { + try { + if(out != null) + out.close(); + } + catch(IOException e) { + } + } + } + + public static InputStream getResource(String path) throws FileNotFoundException { + InputStream in = FileUtils.class.getResourceAsStream("/" + path); + if(in == null) + throw new FileNotFoundException(path); + return in; + } + + public static boolean deleteFiles(File[] files) { + if(files == null) { + Log.JNI.warn("Konnte Ordner nicht löschen"); + return false; + } + + for(int i = 0; i < files.length; ++i) { + File file = files[i]; + Log.JNI.info("Lösche " + file); + + if(file.isDirectory() && !deleteFiles(file.listFiles())) { + Log.JNI.warn("Konnte Ordner " + file + " nicht löschen"); + return false; + } + + if(!file.delete()) { + Log.JNI.warn("Konnte Datei " + file + " nicht löschen"); + return false; + } + } + + return true; + } +} diff --git a/java/src/game/util/Formatter.java b/java/src/game/util/Formatter.java new file mode 100644 index 0000000..d14563e --- /dev/null +++ b/java/src/game/util/Formatter.java @@ -0,0 +1,7 @@ +package game.util; + +import game.gui.element.Element; + +public interface Formatter { + String use(T elem); +} diff --git a/java/src/game/util/PerfSection.java b/java/src/game/util/PerfSection.java new file mode 100644 index 0000000..cfcf813 --- /dev/null +++ b/java/src/game/util/PerfSection.java @@ -0,0 +1,56 @@ +package game.util; + +import game.window.WCF; + +public enum PerfSection { + TIMING("Timing"), + INPUT("Input"), + TICK("Tick"), + UPDATE("Update"), + RENDER("Render"), + GUI("Gui"), + REST("Rest"), + SWAP("Swap"), + EVENTS("Events"), + WAIT("Wait"); + + private static PerfSection section; + private static int swap; + private static long start; + private static long total; + + private final String name; + + private long time; + private long[] last = new long[2]; + + private PerfSection(String name) { + this.name = name; + } + + public void enter() { + this.time = WCF.getTime(); + if(section != null) + section.last[swap] = section.time = this.time - section.time; + section = this; + } + + public String getName() { + return this.name; + } + + public long getLast() { + return this.last[swap ^ 1]; + } + + public static void swap() { + long current = WCF.getTime(); + total = current - start; + start = current; + swap ^= 1; + } + + public static long getTotal(boolean wait) { + return total - (wait ? 0L : WAIT.getLast()); + } +} diff --git a/java/src/game/util/Predicates.java b/java/src/game/util/Predicates.java new file mode 100644 index 0000000..27ad39e --- /dev/null +++ b/java/src/game/util/Predicates.java @@ -0,0 +1,645 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package game.util; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Static utility methods pertaining to {@code Predicate} instances. + * + *

All methods returns serializable predicates as long as they're given + * serializable parameters. + * + *

See the Guava User Guide article on the + * use of {@code Predicate}. + * + * @author Kevin Bourrillion + * @since 2.0 (imported from Google Collections Library) + */ + +public final class Predicates { + private Predicates() {} + + // TODO(kevinb): considering having these implement a VisitablePredicate + // interface which specifies an accept(PredicateVisitor) method. + + /** + * Returns a predicate that always evaluates to {@code true}. + */ + + public static Predicate alwaysTrue() { + return ObjectPredicate.ALWAYS_TRUE.withNarrowedType(); + } + + /** + * Returns a predicate that always evaluates to {@code false}. + */ +// +// public static Predicate alwaysFalse() { +// return ObjectPredicate.ALWAYS_FALSE.withNarrowedType(); +// } + + /** + * Returns a predicate that evaluates to {@code true} if the object reference + * being tested is null. + */ + + public static Predicate isNull() { + return ObjectPredicate.IS_NULL.withNarrowedType(); + } + + /** + * Returns a predicate that evaluates to {@code true} if the object reference + * being tested is not null. + */ + + public static Predicate notNull() { + return ObjectPredicate.NOT_NULL.withNarrowedType(); + } + + /** + * Returns a predicate that evaluates to {@code true} if the given predicate + * evaluates to {@code false}. + */ + public static Predicate not(Predicate predicate) { + return new NotPredicate(predicate); + } + + /** + * Returns a predicate that evaluates to {@code true} if each of its + * components evaluates to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a false + * predicate is found. It defensively copies the iterable passed in, so future + * changes to it won't alter the behavior of this predicate. If {@code + * components} is empty, the returned predicate will always evaluate to {@code + * true}. + */ +// public static Predicate and( +// Iterable> components) { +// return new AndPredicate(defensiveCopy(components)); +// } + + /** + * Returns a predicate that evaluates to {@code true} if each of its + * components evaluates to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a false + * predicate is found. It defensively copies the array passed in, so future + * changes to it won't alter the behavior of this predicate. If {@code + * components} is empty, the returned predicate will always evaluate to {@code + * true}. + */ + public static Predicate and(Predicate... components) { + return new AndPredicate(defensiveCopy(components)); + } + + /** + * Returns a predicate that evaluates to {@code true} if both of its + * components evaluate to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a false + * predicate is found. + */ + public static Predicate and(Predicate first, + Predicate second) { + return new AndPredicate(Predicates.asList( + first, second)); + } + + /** + * Returns a predicate that evaluates to {@code true} if any one of its + * components evaluates to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a + * true predicate is found. It defensively copies the iterable passed in, so + * future changes to it won't alter the behavior of this predicate. If {@code + * components} is empty, the returned predicate will always evaluate to {@code + * false}. + */ +// public static Predicate or( +// Iterable> components) { +// return new OrPredicate(defensiveCopy(components)); +// } + + /** + * Returns a predicate that evaluates to {@code true} if any one of its + * components evaluates to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a + * true predicate is found. It defensively copies the array passed in, so + * future changes to it won't alter the behavior of this predicate. If {@code + * components} is empty, the returned predicate will always evaluate to {@code + * false}. + */ +// public static Predicate or(Predicate... components) { +// return new OrPredicate(defensiveCopy(components)); +// } + + /** + * Returns a predicate that evaluates to {@code true} if either of its + * components evaluates to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a + * true predicate is found. + */ +// public static Predicate or( +// Predicate first, Predicate second) { +// return new OrPredicate(Predicates.asList( +// checkNotNull(first), checkNotNull(second))); +// } + + /** + * Returns a predicate that evaluates to {@code true} if the object being + * tested {@code equals()} the given target or both are null. + */ + public static Predicate equalTo(T target) { + return (target == null) + ? Predicates.isNull() + : new IsEqualToPredicate(target); + } + + /** + * Returns a predicate that evaluates to {@code true} if the object being + * tested is an instance of the given class. If the object being tested + * is {@code null} this predicate evaluates to {@code false}. + * + *

If you want to filter an {@code Iterable} to narrow its type, consider + * using {@link com.google.common.collect.Iterables#filter(Iterable, Class)} + * in preference. + * + *

Warning: contrary to the typical assumptions about predicates (as + * documented at {@link Predicate#apply}), the returned predicate may not be + * consistent with equals. For example, {@code + * instanceOf(ArrayList.class)} will yield different results for the two equal + * instances {@code Lists.newArrayList(1)} and {@code Arrays.asList(1)}. + */ + + public static Predicate instanceOf(Class clazz) { + return new InstanceOfPredicate(clazz); + } + + /** + * Returns a predicate that evaluates to {@code true} if the class being + * tested is assignable from the given class. The returned predicate + * does not allow null inputs. + * + * @since 10.0 + */ +// +// @Beta +// public static Predicate> assignableFrom(Class clazz) { +// return new AssignableFromPredicate(clazz); +// } + + /** + * Returns a predicate that evaluates to {@code true} if the object reference + * being tested is a member of the given collection. It does not defensively + * copy the collection passed in, so future changes to it will alter the + * behavior of the predicate. + * + *

This method can technically accept any {@code Collection}, but using + * a typed collection helps prevent bugs. This approach doesn't block any + * potential users since it is always possible to use {@code + * Predicates.in()}. + * + * @param target the collection that may contain the function input + */ + public static Predicate in(Collection target) { + return new InPredicate(target); + } + + /** + * Returns the composition of a function and a predicate. For every {@code x}, + * the generated predicate returns {@code predicate(function(x))}. + * + * @return the composition of the provided function and predicate + */ + public static Predicate compose( + Predicate predicate, Function function) { + return new CompositionPredicate(predicate, function); + } + + /** + * Returns a predicate that evaluates to {@code true} if the + * {@code CharSequence} being tested contains any match for the given + * regular expression pattern. The test used is equivalent to + * {@code Pattern.compile(pattern).matcher(arg).find()} + * + * @throws java.util.regex.PatternSyntaxException if the pattern is invalid + * @since 3.0 + */ +// +// public static Predicate containsPattern(String pattern) { +// return new ContainsPatternFromStringPredicate(pattern); +// } + + /** + * Returns a predicate that evaluates to {@code true} if the + * {@code CharSequence} being tested contains any match for the given + * regular expression pattern. The test used is equivalent to + * {@code pattern.matcher(arg).find()} + * + * @since 3.0 + */ + +// public static Predicate contains(Pattern pattern) { +// return new ContainsPatternPredicate(pattern); +// } + + // End public API, begin private implementation classes. + + // Package private for GWT serialization. + enum ObjectPredicate implements Predicate { + /** @see Predicates#alwaysTrue() */ + ALWAYS_TRUE { + @Override public boolean test(Object o) { + return true; + } +// @Override public String toString() { +// return "Predicates.alwaysTrue()"; +// } + }, + /** @see Predicates#alwaysFalse() */ +// ALWAYS_FALSE { +// @Override public boolean test(Object o) { +// return false; +// } +// @Override public String toString() { +// return "Predicates.alwaysFalse()"; +// } +// }, + /** @see Predicates#isNull() */ + IS_NULL { + @Override public boolean test(Object o) { + return o == null; + } +// @Override public String toString() { +// return "Predicates.isNull()"; +// } + }, + /** @see Predicates#notNull() */ + NOT_NULL { + @Override public boolean test(Object o) { + return o != null; + } +// @Override public String toString() { +// return "Predicates.notNull()"; +// } + }; + + // safe contravariant cast + Predicate withNarrowedType() { + return (Predicate) this; + } + } + + /** @see Predicates#not(Predicate) */ + private static class NotPredicate implements Predicate, Serializable { + final Predicate predicate; + + NotPredicate(Predicate predicate) { + this.predicate = predicate; + } + @Override + public boolean test(T t) { + return !predicate.test(t); + } +// @Override public int hashCode() { +// return ~predicate.hashCode(); +// } +// @Override public boolean equals(Object obj) { +// if (obj instanceof NotPredicate) { +// NotPredicate that = (NotPredicate) obj; +// return predicate.equals(that.predicate); +// } +// return false; +// } +// @Override public String toString() { +// return "Predicates.not(" + predicate.toString() + ")"; +// } +// private static final long serialVersionUID = 0; + } + +// private static final Joiner COMMA_JOINER = Joiner.on(','); + + /** @see Predicates#and(Iterable) */ + private static class AndPredicate implements Predicate, Serializable { + private final List> components; + + private AndPredicate(List> components) { + this.components = components; + } + @Override + public boolean test(T t) { + // Avoid using the Iterator to avoid generating garbage (issue 820). + for (int i = 0; i < components.size(); i++) { + if (!components.get(i).test(t)) { + return false; + } + } + return true; + } +// @Override public int hashCode() { +// // add a random number to avoid collisions with OrPredicate +// return components.hashCode() + 0x12472c2c; +// } +// @Override public boolean equals(Object obj) { +// if (obj instanceof AndPredicate) { +// AndPredicate that = (AndPredicate) obj; +// return components.equals(that.components); +// } +// return false; +// } +// @Override public String toString() { +// return "Predicates.and(" + COMMA_JOINER.join(components) + ")"; +// } +// private static final long serialVersionUID = 0; + } + + /** @see Predicates#or(Iterable) */ +// private static class OrPredicate implements Predicate, Serializable { +// private final List> components; +// +// private OrPredicate(List> components) { +// this.components = components; +// } +// @Override +// public boolean test(T t) { +// // Avoid using the Iterator to avoid generating garbage (issue 820). +// for (int i = 0; i < components.size(); i++) { +// if (components.get(i).test(t)) { +// return true; +// } +// } +// return false; +// } +// @Override public int hashCode() { +// // add a random number to avoid collisions with AndPredicate +// return components.hashCode() + 0x053c91cf; +// } +// @Override public boolean equals(Object obj) { +// if (obj instanceof OrPredicate) { +// OrPredicate that = (OrPredicate) obj; +// return components.equals(that.components); +// } +// return false; +// } +// @Override public String toString() { +// return "Predicates.or(" + COMMA_JOINER.join(components) + ")"; +// } +// private static final long serialVersionUID = 0; +// } + + /** @see Predicates#equalTo(Object) */ + private static class IsEqualToPredicate + implements Predicate, Serializable { + private final T target; + + private IsEqualToPredicate(T target) { + this.target = target; + } + @Override + public boolean test(T t) { + return target.equals(t); + } +// @Override public int hashCode() { +// return target.hashCode(); +// } +// @Override public boolean equals(Object obj) { +// if (obj instanceof IsEqualToPredicate) { +// IsEqualToPredicate that = (IsEqualToPredicate) obj; +// return target.equals(that.target); +// } +// return false; +// } +// @Override public String toString() { +// return "Predicates.equalTo(" + target + ")"; +// } +// private static final long serialVersionUID = 0; + } + + /** @see Predicates#instanceOf(Class) */ + + private static class InstanceOfPredicate + implements Predicate, Serializable { + private final Class clazz; + + private InstanceOfPredicate(Class clazz) { + this.clazz = clazz; + } + @Override + public boolean test(Object o) { + return clazz.isInstance(o); + } +// @Override public int hashCode() { +// return clazz.hashCode(); +// } +// @Override public boolean equals(Object obj) { +// if (obj instanceof InstanceOfPredicate) { +// InstanceOfPredicate that = (InstanceOfPredicate) obj; +// return clazz == that.clazz; +// } +// return false; +// } +// @Override public String toString() { +// return "Predicates.instanceOf(" + clazz.getName() + ")"; +// } +// private static final long serialVersionUID = 0; + } + + /** @see Predicates#assignableFrom(Class) */ + +// private static class AssignableFromPredicate +// implements Predicate>, Serializable { +// private final Class clazz; +// +// private AssignableFromPredicate(Class clazz) { +// this.clazz = checkNotNull(clazz); +// } +// @Override +// public boolean test(Class input) { +// return clazz.isAssignableFrom(input); +// } +// @Override public int hashCode() { +// return clazz.hashCode(); +// } +// @Override public boolean equals(Object obj) { +// if (obj instanceof AssignableFromPredicate) { +// AssignableFromPredicate that = (AssignableFromPredicate) obj; +// return clazz == that.clazz; +// } +// return false; +// } +// @Override public String toString() { +// return "Predicates.assignableFrom(" + clazz.getName() + ")"; +// } +// private static final long serialVersionUID = 0; +// } + + /** @see Predicates#in(Collection) */ + private static class InPredicate implements Predicate, Serializable { + private final Collection target; + + private InPredicate(Collection target) { + this.target = target; + } + + @Override + public boolean test(T t) { + try { + return target.contains(t); + } catch (NullPointerException e) { + return false; + } catch (ClassCastException e) { + return false; + } + } + +// @Override public boolean equals(Object obj) { +// if (obj instanceof InPredicate) { +// InPredicate that = (InPredicate) obj; +// return target.equals(that.target); +// } +// return false; +// } +// +// @Override public int hashCode() { +// return target.hashCode(); +// } + +// @Override public String toString() { +// return "Predicates.in(" + target + ")"; +// } +// private static final long serialVersionUID = 0; + } + + /** @see Predicates#compose(Predicate, Function) */ + private static class CompositionPredicate + implements Predicate, Serializable { + final Predicate p; + final Function f; + + private CompositionPredicate(Predicate p, Function f) { + this.p = p; + this.f = f; + } + + @Override + public boolean test(A a) { + return p.test(f.apply(a)); + } + +// @Override public boolean equals(Object obj) { +// if (obj instanceof CompositionPredicate) { +// CompositionPredicate that = (CompositionPredicate) obj; +// return f.equals(that.f) && p.equals(that.p); +// } +// return false; +// } +// +// @Override public int hashCode() { +// return f.hashCode() ^ p.hashCode(); +// } + +// @Override public String toString() { +// return p.toString() + "(" + f.toString() + ")"; +// } +// +// private static final long serialVersionUID = 0; + } + + /** @see Predicates#contains(Pattern) */ + +// private static class ContainsPatternPredicate +// implements Predicate, Serializable { +// final Pattern pattern; +// +// ContainsPatternPredicate(Pattern pattern) { +// this.pattern = checkNotNull(pattern); +// } +// +// @Override +// public boolean test(CharSequence t) { +// return pattern.matcher(t).find(); +// } +// +// @Override public int hashCode() { +// // Pattern uses Object.hashCode, so we have to reach +// // inside to build a hashCode consistent with equals. +// +// return Arrays.hashCode(new Object[] {pattern.pattern(), pattern.flags()}); +// } +// +// @Override public boolean equals(Object obj) { +// if (obj instanceof ContainsPatternPredicate) { +// ContainsPatternPredicate that = (ContainsPatternPredicate) obj; +// +// // Pattern uses Object (identity) equality, so we have to reach +// // inside to compare individual fields. +// return Objects.equal(pattern.pattern(), that.pattern.pattern()) +// && Objects.equal(pattern.flags(), that.pattern.flags()); +// } +// return false; +// } +// +//// @Override public String toString() { +//// String patternString = Objects.toStringHelper(pattern) +//// .add("pattern", pattern.pattern()) +//// .add("pattern.flags", pattern.flags()) +//// .toString(); +//// return "Predicates.contains(" + patternString + ")"; +//// } +// +// private static final long serialVersionUID = 0; +// } +// +// /** @see Predicates#containsPattern(String) */ +// +// private static class ContainsPatternFromStringPredicate +// extends ContainsPatternPredicate { +// +// ContainsPatternFromStringPredicate(String string) { +// super(Pattern.compile(string)); +// } +// +//// @Override public String toString() { +//// return "Predicates.containsPattern(" + pattern.pattern() + ")"; +//// } +// +// private static final long serialVersionUID = 0; +// } + + private static List> asList( + Predicate first, Predicate second) { + // TODO(kevinb): understand why we still get a warning despite @SafeVarargs! + return Arrays.>asList(first, second); + } + + private static List defensiveCopy(T... array) { + return defensiveCopy(Arrays.asList(array)); + } + + static List defensiveCopy(Iterable iterable) { + ArrayList list = new ArrayList(); + for (T element : iterable) { + list.add(element); + } + return list; + } +} diff --git a/java/src/game/util/SkinConverter.java b/java/src/game/util/SkinConverter.java new file mode 100755 index 0000000..5cb618f --- /dev/null +++ b/java/src/game/util/SkinConverter.java @@ -0,0 +1,321 @@ +package game.util; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import game.log.Log; + +public abstract class SkinConverter { + private static BufferedImage convertSkin(BufferedImage image) { + BufferedImage img = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB); + Graphics graphics = img.getGraphics(); + graphics.drawImage(image, 0, 0, null); + graphics.drawImage(img, 24, 48, 20, 52, 4, 16, 8, 20, null); + graphics.drawImage(img, 28, 48, 24, 52, 8, 16, 12, 20, null); + graphics.drawImage(img, 20, 52, 16, 64, 8, 20, 12, 32, null); + graphics.drawImage(img, 24, 52, 20, 64, 4, 20, 8, 32, null); + graphics.drawImage(img, 28, 52, 24, 64, 0, 20, 4, 32, null); + graphics.drawImage(img, 32, 52, 28, 64, 12, 20, 16, 32, null); + graphics.drawImage(img, 40, 48, 36, 52, 44, 16, 48, 20, null); + graphics.drawImage(img, 44, 48, 40, 52, 48, 16, 52, 20, null); + graphics.drawImage(img, 36, 52, 32, 64, 48, 20, 52, 32, null); + graphics.drawImage(img, 40, 52, 36, 64, 44, 20, 48, 32, null); + graphics.drawImage(img, 44, 52, 40, 64, 40, 20, 44, 32, null); + graphics.drawImage(img, 48, 52, 44, 64, 52, 20, 56, 32, null); + graphics.dispose(); + return img; + } + + private static BufferedImage convertSlim(BufferedImage image) { + BufferedImage img = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = img.createGraphics(); + graphics.drawImage(image, 0, 0, null); + graphics.setBackground(new Color(0xffffffff, true)); + graphics.clearRect(47, 16, 9, 16); + graphics.clearRect(37, 48, 11, 16); + graphics.setBackground(new Color(0x00000000, true)); + graphics.clearRect(47, 32, 9, 16); + graphics.clearRect(53, 48, 11, 16); + + graphics.drawImage(image, 47, 16, 48, 20, 46, 16, 47, 20, null); // + graphics.drawImage(image, 48, 16, 51, 20, 47, 16, 50, 20, null); + graphics.drawImage(image, 51, 16, 52, 20, 49, 16, 50, 20, null); // + graphics.drawImage(image, 47, 20, 48, 32, 46, 20, 47, 32, null); // + graphics.drawImage(image, 48, 20, 52, 32, 47, 20, 51, 32, null); + graphics.drawImage(image, 53, 20, 56, 32, 51, 20, 54, 32, null); + graphics.drawImage(image, 52, 20, 53, 32, 51, 20, 52, 32, null); // + + graphics.drawImage(image, 47, 32, 48, 36, 46, 32, 47, 36, null); // + graphics.drawImage(image, 48, 32, 51, 36, 47, 32, 50, 36, null); + graphics.drawImage(image, 51, 32, 52, 36, 49, 32, 50, 36, null); // + graphics.drawImage(image, 47, 36, 48, 48, 46, 36, 47, 48, null); // + graphics.drawImage(image, 48, 36, 52, 48, 47, 36, 51, 48, null); + graphics.drawImage(image, 53, 36, 56, 48, 51, 36, 54, 48, null); + graphics.drawImage(image, 52, 36, 53, 48, 51, 36, 52, 48, null); // + + graphics.drawImage(image, 37, 48, 40, 52, 36, 48, 39, 52, null); + graphics.drawImage(image, 41, 48, 44, 52, 39, 48, 42, 52, null); + graphics.drawImage(image, 40, 48, 41, 52, 39, 48, 40, 52, null); // + graphics.drawImage(image, 37, 52, 40, 64, 36, 52, 39, 64, null); + graphics.drawImage(image, 40, 52, 44, 64, 39, 52, 43, 64, null); + graphics.drawImage(image, 44, 52, 47, 64, 43, 52, 46, 64, null); + graphics.drawImage(image, 47, 52, 48, 64, 45, 52, 46, 64, null); // + + graphics.drawImage(image, 53, 48, 56, 52, 52, 48, 55, 52, null); + graphics.drawImage(image, 57, 48, 60, 52, 55, 48, 58, 52, null); + graphics.drawImage(image, 56, 48, 57, 52, 55, 48, 56, 52, null); // + graphics.drawImage(image, 53, 52, 56, 64, 52, 52, 55, 64, null); + graphics.drawImage(image, 56, 52, 60, 64, 55, 52, 59, 64, null); + graphics.drawImage(image, 60, 52, 63, 64, 59, 52, 62, 64, null); + graphics.drawImage(image, 63, 52, 64, 64, 61, 52, 62, 64, null); // + + graphics.dispose(); + return img; + } + + private static void copyData(int[] img1, int[] img2, int xo, int yo, int w, int h, boolean blank, boolean alpha) { + for(int y = yo; y < h+yo; y++) { + for(int x = xo; x < w+xo; x++) { + img2[y*64+x] = blank ? 0x00000000 : (img1[y*64+x] | (alpha ? 0x00000000 : 0xff000000)); + } + } + } + + private static void copyData(int[] img1, int[] img2, int xo, int yo, int w, int h, int xd, int yd) { + for(int y = 0; y < h; y++) { + for(int x = 0; x < w; x++) { + img2[(yd+y)*64+xd+x] = img1[(yo+y)*64+xo+x]; + } + } + } + + private static int[] filterImage(int[] img1, int[] img2) { + copyData(img1, img2, 0, 0, 8, 8, true, true); + copyData(img1, img2, 8, 0, 16, 8, false, false); + copyData(img1, img2, 24, 0, 8, 8, true, true); + copyData(img1, img2, 0, 8, 32, 8, false, false); + copyData(img1, img2, 32, 0, 8, 8, true, true); + copyData(img1, img2, 40, 0, 16, 8, false, true); + copyData(img1, img2, 56, 0, 8, 8, true, true); + copyData(img1, img2, 32, 8, 32, 8, false, true); + + copyData(img1, img2, 0, 16, 4, 4, true, true); + copyData(img1, img2, 4, 16, 8, 4, false, false); + copyData(img1, img2, 12, 16, 8, 4, true, true); + copyData(img1, img2, 20, 16, 16, 4, false, false); + copyData(img1, img2, 36, 16, 8, 4, true, true); + copyData(img1, img2, 44, 16, 8, 4, false, false); + copyData(img1, img2, 52, 16, 4, 4, true, true); + copyData(img1, img2, 0, 20, 56, 12, false, false); + copyData(img1, img2, 56, 16, 8, 32, true, true); + + copyData(img1, img2, 0, 32, 4, 4, true, true); + copyData(img1, img2, 4, 32, 8, 4, false, true); + copyData(img1, img2, 12, 32, 8, 4, true, true); + copyData(img1, img2, 20, 32, 16, 4, false, true); + copyData(img1, img2, 36, 32, 8, 4, true, true); + copyData(img1, img2, 44, 32, 8, 4, false, true); + copyData(img1, img2, 52, 32, 4, 4, true, true); + copyData(img1, img2, 0, 36, 56, 12, false, true); + + copyData(img1, img2, 0, 48, 4, 4, true, true); + copyData(img1, img2, 4, 48, 8, 4, false, true); + copyData(img1, img2, 12, 48, 4, 4, true, true); + copyData(img1, img2, 0, 52, 16, 12, false, true); + copyData(img1, img2, 16, 48, 4, 4, true, true); + copyData(img1, img2, 20, 48, 8, 4, false, false); + copyData(img1, img2, 28, 48, 8, 4, true, true); + copyData(img1, img2, 36, 48, 8, 4, false, false); + copyData(img1, img2, 44, 48, 4, 4, true, true); + copyData(img1, img2, 16, 52, 32, 12, false, false); + copyData(img1, img2, 48, 48, 4, 4, true, true); + copyData(img1, img2, 52, 48, 8, 4, false, true); + copyData(img1, img2, 60, 48, 4, 4, true, true); + copyData(img1, img2, 48, 52, 16, 12, false, true); + + return img2; + } + + private static void relocateIntermediary(int[] img1, int[] img2) { + copyData(img1, img2, 0, 0, 64, 64, 0, 0); + + copyData(img1, img2, 4, 16, 8, 4, 20, 48); + copyData(img1, img2, 44, 16, 8, 4, 4, 16); + copyData(img1, img2, 0, 20, 16, 12, 16, 52); + copyData(img1, img2, 40, 20, 16, 12, 0, 20); + + copyData(img1, img2, 4, 32, 8, 4, 4, 48); + copyData(img1, img2, 44, 32, 8, 4, 4, 32); + copyData(img1, img2, 0, 36, 16, 12, 0, 52); + copyData(img1, img2, 40, 36, 16, 12, 0, 36); + + copyData(img1, img2, 4, 48, 8, 4, 52, 48); + copyData(img1, img2, 20, 48, 8, 4, 36, 48); + copyData(img1, img2, 36, 48, 8, 4, 44, 16); + copyData(img1, img2, 52, 48, 8, 4, 44, 32); + copyData(img1, img2, 0, 52, 16, 12, 48, 52); + copyData(img1, img2, 16, 52, 16, 12, 32, 52); + copyData(img1, img2, 32, 52, 16, 12, 40, 20); + copyData(img1, img2, 48, 52, 16, 12, 40, 36); + } + + public static boolean convertSkin(File source, File dir, boolean slim) { + BufferedImage img; + try { + img = ImageIO.read(source); + } + catch(IOException e) { + Log.JNI.error(e, "Konnte kein Bild von " + source + " laden"); + return false; + } + if(img == null) { + Log.JNI.warn("Konnte kein Bild von " + source + " laden"); + return false; + } + Log.JNI.info("Bild von " + source + " geladen"); + if(img.getWidth() == 64 && img.getHeight() == 32) { + img = convertSkin(img); + Log.JNI.info("Skin " + source + " konvertiert"); + } + else if(img.getWidth() != 64 || img.getHeight() != 64) { + Log.JNI.warn("Falsche Bildgröße von " + source + ": " + img.getWidth() + "x" + img.getHeight()); + return false; + } + String name = source.getName(); + int ext = name.lastIndexOf('.'); + if(ext >= 0) + name = name.substring(0, ext); + if(name.isEmpty()) + name = "skin"; + if(slim) { + img = convertSlim(img); + Log.JNI.info("Skin " + source + " von 'Slim' konvertiert"); + if(!name.startsWith("slim_")) + name = "slim_" + name; + } + File file = new File(dir, name + ".png"); + int z = 1; + while(file.exists()) { + file = new File(dir, name + "_" + (++z) + ".png"); + } +// Graphics2D g = img.createGraphics(); +// g.setBackground(new Color(0x7fff00ff, true)); +// g.clearRect(0, 0, 64, 64); + int[] data = img.getRGB(0, 0, 64, 64, new int[64*64], 0, 64); + int[] data2 = new int[data.length]; + relocateIntermediary(data, data2); + data = data2; + filterImage(data, data); + img.setRGB(0, 0, 64, 64, data, 0, 64); + try { + ImageIO.write(img, "png", file); + } + catch(Exception e) { + Log.JNI.error(e, "Konnte Bild nicht speichern"); + return false; + } + Log.JNI.info("Skin " + source + " gespeichert als " + file.getName()); + return true; + } + +// public static void main(String[] args) { +// if(args.length < 1) { +// System.err.println("Verwendung: SkinConverter [-s | -n | -i] "); +// System.exit(1); +// } +// int n = 0; +// boolean slim = false; +//// boolean intermediary = false; +// for(String file : args) { +// if(file.equals("-s")) { +// slim = true; +// continue; +// } +//// else if(file.equals("-i")) { +//// intermediary = true; +//// continue; +//// } +// else if(file.equals("-n")) { +// slim = false; +//// intermediary = false; +// continue; +// } +// else if(new File(file).isDirectory()) { +// String[] files = new File(file).list(); +// if(files != null && files.length > 0) { +// for(int z = 0; z < files.length; z++) { +// files[z] = file + File.separator + files[z]; +// } +// if(slim) { // || intermediary) { +// String[] files2 = new String[files.length + /* (slim && intermediary ? 2 : */ 1]; // )]; +// int pos = 0; +// if(slim) +// files2[pos++] = "-s"; +//// if(intermediary) +//// files2[pos++] = "-i"; +// System.arraycopy(files, 0, files2, pos, files.length); +// files = files2; +// } +// main(files); +// } +// continue; +// } +// else if(file.endsWith("-converted.png")) +// continue; +// String out = (file.endsWith(".png") ? file.substring(0, file.length() - 4) : file) + "-converted.png"; +// BufferedImage img; +// try { +// img = ImageIO.read(new File(file)); +// } +// catch(Exception e) { +// System.err.println("Konnte Bild '" + file + "' nicht laden"); +// e.printStackTrace(); +// continue; +// } +// if(img == null) { +// System.err.println("Konnte Bild '" + file + "' nicht öffnen"); +// continue; +// } +// if(img.getWidth() == 64 && img.getHeight() == 32) { +// img = convertSkin(img); +// System.out.println("Skin '" + file + "' von 64x32 nach 64x64 konvertiert"); +// } +// else if(img.getWidth() != 64 || img.getHeight() != 64) { +// System.err.println("Falsche Bildgröße für '" + file + "': " + img.getWidth() + "x" + img.getHeight()); +// continue; +// } +// if(slim) { +// img = convertSlim(img); +// System.out.println("Skin '" + file + "' von 'Slim' nach 64x64/'Schlank' konvertiert"); +// } +// int[] data = img.getRGB(0, 0, 64, 64, new int[64*64], 0, 64); +//// if(intermediary) { +// int[] data2 = new int[data.length]; +// relocateIntermediary(data, data2); +// data = data2; +//// } +//// else { +// filterImage(data, data); +//// } +// img.setRGB(0, 0, 64, 64, data, 0, 64); +// try { +// ImageIO.write(img, "png", new File(out)); +// } +// catch(Exception e) { +// System.err.println("Konnte Bild '" + out + "' nicht speichern"); +// e.printStackTrace(); +// continue; +// } +// System.out.println("Skin von '" + file + "' nach '" + out + "' konvertiert"); +// n++; +// } +// if(n > 0) +// System.out.println(n + " Skins wurden konvertiert"); +// } +} diff --git a/java/src/game/util/Splashes.java b/java/src/game/util/Splashes.java new file mode 100644 index 0000000..c35c9df --- /dev/null +++ b/java/src/game/util/Splashes.java @@ -0,0 +1,414 @@ +package game.util; + +public abstract class Splashes { + public static final String[] SPLASHES = { + "Aus der TV-Werbung!", + "Toll!", + "0% pur!", + "Kann Nüsse enthalten!", + "Besser als Crysis!", + "Mehr Polygone!", + "Sexy!", + "Limitierte Edition!", + "Blinkende Buchstaben!", + "Erstellt von Notch!", + "Es ist hier!", + "Das Beste seiner Klasse!", + "Es ist vollendet!", + "Mehr oder weniger frei von Drachen!", + "Aufregung!", + "Weniger als -5 verkauft!", + "Einzigartig!", + "Einen Haufen Scheiße auf YouTube!", + "Indev!", + "Spinnen überall!", + "Schau es dir an!", + "Heilige Kuh, mann!", + "Es ist ein Spiel!", + "Hergestellt in Schweden!", + "Benutzt LWJGL!", + "Retikulierende Splinen!", + "Meine Kraft!", + "Hurraaa!", + "Einzelspieler!", + "Tastatur ist kompatibel!", + "Undokumentiert!", + "Barren!", + "Explodierende Sonnen!", + "Das ist ein Mond!", + "l33t!", + "Erschaffe!", + "Überlebe!", + "Verlies!", + "Exklusiv!", + "Die Knie der Biene!", + "Weg mit O.P.P.!", + "Mit Quellcode (mehr oder weniger)!", + "Mit Klasse(n)!", + "Wow!", + "Immer noch nicht auf Steam - und das ist auch gut so!", + "Oh, mann!", + "Grauenvolle Community!", + "Pixel!", + "Teetsuuuuoooo!", + "Kaaneeeedaaaa!", + "Jetzt ohne Schwierigkeit!", + "Verbessert!", + "9% frei von Bugs!", + "Schön!", + "13 Kräuter und Gewürze!", + "Fettfrei!", + "Absolut keine Memes!", + "Kostenlose Zähne!", + "Fragen Sie Ihnen Arzt oder Apotheker!", + "Alle Bergleute sind willkommen!", + "Cloud-Computing!", + "Legal in Finnland!", + "Schwer zu beschreiben!", + "Technisch gesehen gut!", + "Bringe den Speck nach Hause!", + "Indie!", + "GOTY!", + "Ceci n'est pas une title screen!", + "Euklidisch!", + "Jetzt in 3D!", + "Bietet Inspiration!", + "Herregud!", + "Komplexe Zellvorgänge!", + "Ja, Sir!", + "Von Cowboys gespielt!", + "OpenGL 1.5 oder höher!", + "Tausende von Farben!", + "Probiere es!", + "Age of Wonders ist besser!", + "Probiere die Pilzsuppe!", + "Sensationell!", + "Heiße Tamale, heiße heiße Tamale!", + "Spiele ihn runter, Klavierkatze!", + "Garantiert!", + "Makroskopisch!", + "Dann komm doch her!", + "Zufälliger Text!", + "Ruf deine Mutter an!", + "Monster-Streitigkeiten!", + "Von Melonen geliebt!", + "Ultimative Edition!", + "Merkwürdig!", + "Du hast einen nagelneuen Schlüssel bekommen!", + "Wasserfest!", + "Nicht brennbar!", + "Oha, du!", + "Alles inklusive!", + "Sag es deinen Freunden!", + "NP ist nicht in P!", + "Musik von C418 (DLC)!", + "Viel zu oft live gestreamt!", + "Heimgesucht!", + "Polynomial!", + "Terrestrisch!", + "Alles ist voller Zerstörung!", + "Voll mit Sternen, Planeten und Monden!", + "Wissenschaftlich!", + "Nicht so cool wie Spock!", + "Trage nix bei und höre weg!", + "Grabe niemals nach unten, wenn du keine Erze brauchst!", + "Mache nie Pause!", + "Nicht linear!", + "Han hat zuerst geschossen!", + "Schön dich zu sehen!", + "Eimer mit Lava!", + "Reite auf dem Schwein!", + "Größer als die Erde!", + "sqrt(-1)ch liebe dich!", + "Phobos-Anomalie!", + "Holz schlagen!", + "Von Klippen fallen!", + "0% Zucker!", + "150% hyperbol!", + "Synecdoche!", + "Lasst uns tanzne!", + "Geheeimes Freitags-Update!", + "Referenz-Implementation!", + "Frei mit zwei.. äähhh fünf Typen mit Essen!", + "Küsse den Himmel!", + "20 GOTO 10!", + "Verlet-Intregration!", + "Peter Griffin!", + "Verteile die Erde gut!", + "Cogito ergo sum!", + "4815162342 Zeilen Quellcode (287228 am 30.7.)!", + "Ein Skelett fiel heraus!", + "Das Werk von Notch!", + "Die Summe seiner Teile!", + "BTAF war mal gut!", + "Ich vermisse ADOM!", + "umop-apisdn!", + "GTX750Ti!", + "Bringe mir Mentos und Cola!", + "Finger-leckend!", + "Thematisch!", + "Pneumatisch!", + "Erhaben!", + "Achteckig!", + "Une baguette!", + "Gargamel spielt es!", + "Rita ist der neue beste Hund!", + "SWM für immer!", + "Repräsentiert Edsbyn!", + "Matt Damon!", + "Supercalifragilisticexpialidocious!", + "Vollende V's!", + "Kuh-Werkzeuge!", + "Doppelt gepuffert!", + "Fan-Fiction!", + "Flaxkikare!", + "Jason! Jason! Jason!", + "Heißer als die Sonne!", + "Internet-Funktionalität!", + "Autonom!", + "Engagiere!", + "Fantasie!", + "DRR! DRR! DRR!", + "Stoß es Wurzel runter!", + "Regionale Ressourcen!", + "Jaa, facepunch!", + "Jaa, somethingawful!", + "Jaa, /v/!", + "Jaa, tigsource!", + "Jaa, weinkraftforum!", + "Jaa, worldofweinkraft!", + "Buu, reddit!", + "Jaa, 2pp!", + "Goggle anllyticsed:DD :DDD:D!", + "Unterstützt jetzt äöü!", + "Gebt uns Gordon!", + "Gib deinem Kellner Trinkgeld!", + "Macht viel Spaß!", + "12345 ist ein schlechtes Passwort!", + "Stimme für Netz-Neutralität!", + "Lebt in einer Ananas unter dem Meer!", + "MAP11 hat zwei Namen!", + "Allmächtig!", + "Huch!", + "...!", + "Bienen, Bienen, Bienen, Bienen!", + "Jag känner en bot!", + "Dieser Text ist schwer bei der Standard-Auflösung zu lesen, aber auf 1080p ist es in Ordnung!", + "Haha, LOL!", + "Hampsterdance!", + "Schalter und Erze!", + "Menger-Schwamm!", + "idspispopd!", + "Eple (originale Version)!", + "So frisch, so sauber!", + "Schnell reagierende Portale!", + "Probiere den Warp aus!", + "Schaue nicht direkt auf die Bugs!", + "Oh, ok, NPCs!", + "Endlich mit Leitern!", + "Gruselig!", + "Spiele Minenkraft, schaue Topgear, bekomme Schwein!", + "Darüber gewittert!", + "Spring hoch, spring hoch, und komme runter!", + "Joel ist klasse!", + "Ein Rätsel, in einen Mythos verwoben!", + "Riesige Landeszüge voll mit TNT!", + "Willkommen zu deinem Ende! Muahahahahahaha!", + "Bleib ein Bisschen, bleib für immer!", + "Bleib ein Bisschen und höre zu!", + "Behandlung für Ihren Hautausschlag!", + "\"Autologisch\" ist!", + "Informationen wollen frei sein!", + "\"Fast nie\" ist ein interessantes Konzept!", + "Eine Menge Wahrheitigkeit!", + "Der TNT-Block ist ein Spion!", + "Turing-vollständig!", + "Es ist bahnbrechend!", + "Lasst unsere Schlachten beginnen!", + "Der Himmel ist die Grenze - oder auch nicht!", + "Jeb hat tolle Haare!", + "Ryan hat auch tolle Haare!", + "Gelegentliches Spielen!", + "Unbesiegt!", + "Ein Bisschen wie Lemmings!", + "Folge dem Zug, CJ!", + "Macht von Synergie Verwendung!", + "Diese Nachricht wird niemals als Splash-Text erscheinen, ist das nicht komisch?", + "DungeonQuest ist unfair!", + "0815!", + "666!", + "Geh zu den fernen Ländern und weiter!", + "Tyrion würde es lieben!", + "Probiere auch Stellaris!", + "Probiere auch Garry's Mod!", + "Probiere auch GZDoom!", + "Probiere auch OpenTTD!", + "Probiere auch Kaffee!", + "Probiere auch Vodka!", + "Probiere auch Tee!", + "Probiere auch Wasser!", + "Probiere auch Saft!", + "Das ist super!", + "Brot ist Schmerz!", + "Lese mehr Bücher!", + "Khaaaaaaaaan!", + "Weniger süchtig machend als TV Tropes!", + "Mehr süchtig machend als Limonade!", + "Größer als eine Brotkiste!", + "Millionen von Pfirsichen!", + "Fnord!", + "Dies ist meine echte Gestalt! Muahahahaha!", + "Habe Dre vollkommen vergessen!", + "Verschwende keine Zeit mit den Klonen!", + "Kürbiskopf!", + "Hobo humping slobo babe!", + "Erstellt von Jeb!", + "Hat kein Ende!", + "Endlich vollständig!", + "Voll mit Features!", + "Stiefel mit dem Fell!", + "Stop, hammertime!", + "Testificates!", + "Nicht konventionell!", + "Homeomorphisch zu einer 3-Kugel!", + "Vermeidet nicht doppelte Verneinung!", + "Platziere ALL die Blöcke!", + "Macht Walzen!", + "Erfüllt Erwartungen!", + "Spielen am PC seit 1873!", + "Ghoughpteighbteau tchoghs!", + "Déjà vu!", + "Déjà vu!", + "Hab deine Nase!", + "Haley liebt Elan!", + "Hat keine Angst vor der großen, schwarzen Fledermaus!", + "Benutzt nicht das U-Wort!", + "Nicht wirklich leicht!", + "Bis nächsten Freitag oder so!", + "Von den Straßen von Södermalm!", + "150 BPM für 400000 Minuten!", + "Technologisch!", + "Funk Soul Bruder!", + "Pumpa kungen!", + "Hallo Japan!", + "Hallo Korea!", + "Hallo Wales!", + "Hallo Polen!", + "Hallo China!", + "Hallo Russland!", + "Hallo Griechenland!", + "Mein Leben für Aiur!", + "Lenny lenny = new Lenny(\"(°^°)\");", + "Ich sehe dein Wortschatz hat sich verbessert!", + "Wer hat es dort hin getan?", + "Das kannst du nicht erklären! - Oder etwa doch??", + "if not ok then return end", + "Mehrfarbig!", + "FUNKY LOL", + "SOPA bedeutet LOSER in Schwedisch!", + "Große Spitze Zähne!", + "Mein Shizun bewacht das Tor!", + "Mmmph, mmph!", + "Füttere keine Avocados an Papageien!", + "Schwerter für alle!", + "Bitteee antworte meinem Tweet! (Nutzer wurde gebannt)", + ".party()!", + "Nehme ihr Kissen!", + "Lege diesen Keks weg!", + "Extrem gruselig!", + "Ich habe einen Vorschlag.", + "Jetzt mit extra Sprengstoff!", + "Nicht kompatibel zu Java 6!", + "Oha.", + "HURNERJSGER?", + "Was'n los, Doc?", + "Enthält jetzt 0 zufällige tägliche Katzen!", + "Das ist Numberwang!", + "((pls rt)) -- Der Vogel ist tot!", + "Willst du meinem Server beitreten?", + "Mach einen großen Zaun drum herum! Oder du wirst v-", + "Lege eine Landmine drüber!", + "Eines Tages, irgendwann in der Zukunft, wird mein Werk zitiert werden!", + "Jetzt mit zusätzlichem Zeug!", + "Zusätzliche Dinge!", + "Hurra, Atombomben für alle!", + "So süß, wie ein schöner Bon-Bon!", + "Poppende Tags!", + "Sehr einflussreich in seinem Kreis!", + "Jetzt mit Mehrspieler!", + "Stehe aus deinem Grab auf!", + "Warnung! Ein großes Kampfschiff \"SHEN\" nähert sich schnell!", + "Der blaue Krieger hat das Essen beschossen!", + "Renn, Feigling! Ich hunger!", + "Geschmack ohne Würze!", + "Seltsam, aber nicht fremd!", + "Härter als Diamanten, Reich wie Creme!", + "Mach dich bereit zum Ruinieren!", + "Mach dich bereit zum Experimentieren!", + "Mach dich bereit zum Kollabieren!", + "Mach dich bereit zum Explodieren!", + "Mach dich bereit zum Implodieren!", + "Mach dich bereit zum Implizieren!", + "Es schwingt, es veräppelt!", + "Fahre Straßen entlang für Gold!", + "Nimm einen Schneebesen und haue ihn gegen eine Bratpfanne!", + "Bau mir einen Tisch, einen funkigen Tisch!", + "Nehm den Aufzug in die Hölle!", + "Hör auf vernünftig zu sein, das hier ist das Internet!", + "/give @a tnt 67108864 7", + "Das ist gut für 3D Realms.", + "Jeder Computer ist ein Laptop, wenn du tapfer genug bist!", + "Mach es alles, jede Sache!", + "Wo ist kein Licht, da kann Spinne!", + "GNU Terry Pratchett", + "Jetzt Java 8!", + "MeinKraft!", + "Immer noch zu viele Bugs!", + "Wird nicht laggen!", + "Er hat es ruiniert!", + "Maus nicht kompatibel!", + "OpenGL 2.0+ (definitiv nicht unterstützt)!", + "Keine Segfaults (nicht) möglich!", + "Keine Abstürze (un)möglich!", + "Alpha!", + "Enthält Bugs!", + "Enthält Mäuse!", + "Enthält Gewalt!", + "Grabe immer nach unten >:)>!", + "Weg mit O.O.P.!", + "Du hattest eine. aufgabe.", + "Spinnen können TNT1 A 0 sein!", + "RTFM!", + "Vorherrschaft des Imperiums!", + "Vorherrschaft der Eldar!", + "Vorherrschaft der Drukhari!", + "Vorherrschaft der Necrons!", + "Vorherrschaft der Orks!", + "Jeder Laptop ist ein Tablet, wenn du tapfer genug bist!", + "Jedes Handy ist ein Klapphandy, wenn du tapfer genug bist!", + "Quadcores altern wie feiner Wein (außer mit JS)!", + "Speicherzugriffsfehler (Speicherzug im Riff stehen geblieben)!", + "Eingedeutscht (naja fast)!", + "Ketzerei!", + "WAAAGH!", + "WAAAAGH!", + "WAAAAAGH!", + "WAAAAAAGH!", + "WAAAAAAAGH!", + "WAAAAAAAAGH!", + "WAAAAAAAAAGH!", + "WAAAAAAAAAAGH!", + "X ist nix!", + "Quadratisch, praktisch, gut!", + "Rund, unpraktisch, schlecht!", + "Verschreibungspflichtig!", + "Grüne, radioaktive Blöcke!", + "Blaue, nicht radioaktive Blöcke!", + "Exterminatus!", + "Nein! Doch! Ohh!", + "Eimer mit Wasser!", + "Hergestellt in Deutschland!", + "Hergestellt in China!", + "Jetzt mit Einzelspieler!" + }; +} diff --git a/java/src/game/util/Timing.java b/java/src/game/util/Timing.java new file mode 100644 index 0000000..59f312d --- /dev/null +++ b/java/src/game/util/Timing.java @@ -0,0 +1,30 @@ +package game.util; + +public class Timing { + public static long tmr_timer; + public static long tmr_start; + public static long tmr_current; + public static long tmr_last; + + public static long tmr_delta; + public static long tmr_update; + public static long tmr_frames; + public static long tmr_iters; + + public static long tick_torun; + public static long tick_done; + public static long tick_total; + public static long tick_time; + public static long tick_stime; + public static long tick_ftime; + + public static long tick_ttime; + public static long tick_update; + + public static double tick_fraction; + public static float framerate; + public static float tickrate; + public static float fdelta; + public static int tickTarget; + public static int tickFrame; +} diff --git a/java/src/game/util/Util.java b/java/src/game/util/Util.java new file mode 100644 index 0000000..88dfeee --- /dev/null +++ b/java/src/game/util/Util.java @@ -0,0 +1,261 @@ +package game.util; + +import java.util.function.Function; + +import game.log.Log; +import game.properties.IStringSerializable; + +public abstract class Util { + public static String strip(String str, int offset, int len, char newl, char tab, char unk) { + StringBuilder sb = new StringBuilder(); + for(int pos = offset; pos < offset + len; pos++) { + char c = str.charAt(pos); + if(c == '\n') { + if(newl == 0) + return sb.toString(); + sb.append(newl); + } + else if((c == '\t') && tab != 0) { + for(int z = 0; z < 4; z++) + sb.append(tab); + } + else if(c == Log.CHR_UNK) { + if(unk != 0) + sb.append(unk); + } + else if(c >= Log.CHR_SPC && c <= 0xff) { + sb.append(c); + } + } + return sb.toString(); + } + +/* +uint utf_read(const char **ptr) { + uint ch; + byte utf; + char c = *((*ptr)++); + for(utf = 0; (utf < 6) && (c & (0x80 >> utf)); utf++) { + ; + } + if(utf == 1) + return CHR_UNK; + for(ch = ((!utf) || ((((uint)c) << 6) | (((**ptr) & 0x3f) & ~(0xff >> utf)))) ? (c & (0x7f >> utf)) : 0; utf > 1; utf--) { + if(((c = **ptr) & 0xc0) == 0x80) { + // if(ch) { + ch <<= 6; + ch |= c & 0x3f; + // } + } + else { + return c ? CHR_UNK : 0; + } + (*ptr)++; + } + // fprintf(stderr, "%d / %c\n", ch, ch); + return (utf && !ch) ? CHR_UNK : ch; +} + +uint utf_readn(const char *ptr, int *pos) { + const char *str = &ptr[*pos]; + uint ch = utf_read(&str); + *pos = (int)(str-ptr); + return ch; +} + +byte utf_write(char **ptr, int *len, uint ch) { + uint test; + uint mask = 0xffffff80; + char utf; + char c; + if(ch & 0x80000000) { + return 1; + } + for(utf = 0; ch & mask & ~(test = (0xffffffff << ((utf + 1) * 6 + (5 - utf)))); utf++) { + mask &= test; + } + // fprintf(stderr, "%d\n", utf); + if(utf + 1 >= (*len)) { + return 0; + } + (*len) -= utf + 1; + *((*ptr)++) = utf ? (~(0x7f >> utf) | (((uint)(ch >> (utf * 6))) & (0x3f >> utf))) : ch; + for(--utf; utf >= 0; utf--) { + *((*ptr)++) = 0x80 | (((uint)(ch >> (utf * 6))) & 0x3f); + } + return 1; +} + +byte utf_rwriten(char *ptr, int *pos, int len, uint ch) { + char *str = &ptr[*pos]; + len -= (*pos); + byte res = utf_write(&str, &len, ch); + *pos = (int)(str-ptr); + return res; +} + +uint utf_rread(const char **ptr, const char *start) { + const char *tp = *ptr; + uint ch; + char c; + do { + if(tp == start) + return 0; + tp--; + } while(((c = (*tp)) & 0xc0) == 0x80); + *ptr = tp; + return (ch = utf_read(&tp)) ? ch : CHR_UNK; +} + +uint utf_rreadn(const char *ptr, int *pos) { + const char *str = &ptr[*pos]; + uint ch = utf_rread(&str, ptr); + *pos = (int)(str-ptr); + return ch; +} + +int utf_len(const char *str) { + int len; + for(len = 0; utf_read(&str); len++) { + ; + } + return len; +} +*/ + + public static int compareLower(String str1, String str2) { + if(str2.length() > str1.length()) + return 0; + for(int z = 0; z < str2.length(); z++) { + if(Character.toLowerCase(str1.charAt(z)) != Character.toLowerCase(str2.charAt(z))) + return 0; + } + return str2.length() == str1.length() ? 0x7fffffff : str2.length(); + } + + public static Integer parseInt(String str, int base) { + char c; + boolean tbase = false; + int digits = 0; + long v = 0; + long nbase = base != 0 ? (base < 0 ? -base : base) : 10; + long nsign = 1; + for(int pos = 0; pos < str.length(); pos++) { + c = Character.toLowerCase(str.charAt(pos)); + if(pos == 0 && ((c == '+') || ((c == '-') && (base >= 0)))) + nsign = (c == '+') ? 1 : -1; + else if(pos == 0 && c == '0') { + tbase = true; + digits++; + } + else if(tbase && pos == 1 && c == 'x') { + nbase = 16; + digits--; + } + else if(((nbase == 16) && (c >= 'a' && c <= 'f')) || (c >= '0' && c <= '9')) { + v *= nbase; + v += ((long)((c >= '0' && c <= '9') ? (c - '0') : (10 + (c - 'a')))); + digits++; + } + else + return null; + } + if(digits == 0) + return null; + v *= nsign; + if((base < 0) ? (v < 0L || v > 0xffffffffL) : (v < -0x80000000L || v > 0x7fffffffL)) { + return null; + } + return (int)((base < 0) ? (v & 0xffffffff) : (((v >> 32) & 0x80000000) | (v & 0x7fffffff))); + } + + public static T parseEnum(Class clazz, String str) { + boolean name = IStringSerializable.class.isAssignableFrom(clazz); + T[] values = clazz.getEnumConstants(); + Integer value; + if((value = parseInt(str, 0)) != null && (value >= 0) && (value < values.length)) { + return values[value]; + } + int comp; + int max = 0; + T best = null; + for(int z = 0; z < values.length; z++) { + if((comp = compareLower(name ? ((IStringSerializable)values[z]).getName() : values[z].toString(), str)) > max) { + max = comp; + best = values[z]; + } + } + return best; + } + + public static T parseEnum(Class base, String str, Class ... enums) { + int comp; + int max = 0; + T best = null; + for(Class clazz : enums) { + if(!base.isAssignableFrom(clazz)) + throw new IllegalArgumentException("Klasse " + clazz.getSimpleName() + " ist nicht " + base.getSimpleName() + " untergeordnet"); + boolean name = IStringSerializable.class.isAssignableFrom(clazz); + Enum[] values = clazz.getEnumConstants(); + for(int z = 0; z < values.length; z++) { + if((comp = compareLower(name ? ((IStringSerializable)values[z]).getName() : values[z].toString(), str)) > max) { + max = comp; + best = (T)values[z]; + } + } + } + return best; + } + + public static int indexOf(T[] array, T elem) { + for(int z = 0; z < array.length; z++) { + if(array[z] == elem) + return z; + } + return -1; + } + + public static int indexOfChecked(T[] array, T elem) { + for(int z = 0; z < array.length; z++) { + if(array[z] == elem) + return z; + } + throw new IllegalArgumentException("Objekt ist nicht in Array"); + } + + public static Boolean parseBoolean(String str) { + if("1".equals(str) || "true".equalsIgnoreCase(str) || "on".equalsIgnoreCase(str) || "yes".equalsIgnoreCase(str) || "y".equalsIgnoreCase(str)) + return true; + else if("0".equals(str) || "false".equalsIgnoreCase(str) || "off".equalsIgnoreCase(str) || "no".equalsIgnoreCase(str) || "n".equalsIgnoreCase(str)) + return false; + return null; + } + + public static String buildLines(String separator, Function func, Iterable elems) { + StringBuilder sb = new StringBuilder(); + for(T elem : elems) { + if(sb.length() > 0) + sb.append(separator); + sb.append(func.apply(elem)); + } + return sb.toString(); + } + + public static String buildLines(Function func, Iterable elems) { + return buildLines("\n", func, elems); + } + + public static String buildLines(String separator, Function func, T ... elems) { + StringBuilder sb = new StringBuilder(); + for(T elem : elems) { + if(sb.length() > 0) + sb.append(separator); + sb.append(func.apply(elem)); + } + return sb.toString(); + } + + public static String buildLines(Function func, T ... elems) { + return buildLines("\n", func, elems); + } +} diff --git a/java/src/game/vars/BaseVar.java b/java/src/game/vars/BaseVar.java new file mode 100644 index 0000000..2029a09 --- /dev/null +++ b/java/src/game/vars/BaseVar.java @@ -0,0 +1,38 @@ +package game.vars; + +import java.lang.reflect.Field; + +public abstract class BaseVar implements CVar { + public static interface VarFunction { + } + + protected final String name; + protected final String display; + protected final Field field; + protected final Object object; + protected final CVarCategory category; + + public BaseVar(String name, String display, Field field, Object object, CVarCategory category) { + this.name = name; + this.display = display; + this.field = field; + this.object = object; + this.category = category; + } + + public final String getCVarName() { + return this.name; + } + + public final String getDisplay() { + return this.display; + } + + public final CVarCategory getCategory() { + return this.category; + } + + public void setDefault() { + this.parse(this.getDefault()); + } +} diff --git a/java/src/game/vars/BoolVar.java b/java/src/game/vars/BoolVar.java new file mode 100644 index 0000000..fb3b9aa --- /dev/null +++ b/java/src/game/vars/BoolVar.java @@ -0,0 +1,72 @@ +package game.vars; + +import java.lang.reflect.Field; + +import game.color.TextColor; +import game.gui.element.Toggle; +import game.util.Util; + +public class BoolVar extends BaseVar { + public static interface BoolFunction extends VarFunction { + void apply(BoolVar cv, boolean value); + } + + private final BoolFunction func; + private final boolean def; + + public BoolVar(String name, String display, Field field, Object object, CVarCategory category, BoolFunction func) { + super(name, display, field, object, category); + this.func = func; + try { + this.def = field.getBoolean(object); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public String getType() { + return TextColor.MAGENTA + "bool"; + } + + public boolean parse(String str) { + Boolean value = Util.parseBoolean(str); + if(value == null) + return false; + try { + this.field.setBoolean(this.object, value); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + if(this.func != null) + this.func.apply(this, value); + return true; + } + + public String format() { + try { + return "" + this.field.getBoolean(this.object); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public String getDefault() { + return "" + this.def; + } + + public Toggle selector(int x, int y, int w, int h) { + try { + return new Toggle(x, y, w, h, this.def, this.field.getBoolean(this.object), new Toggle.Callback() { + public void use(Toggle elem, boolean value) { + BoolVar.this.parse("" + value); + } + }, this.display); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} diff --git a/java/src/game/vars/CVar.java b/java/src/game/vars/CVar.java new file mode 100644 index 0000000..bddcd04 --- /dev/null +++ b/java/src/game/vars/CVar.java @@ -0,0 +1,18 @@ +package game.vars; + +import game.gui.element.Element; +import game.util.Displayable; + +public interface CVar extends Displayable { + String getType(); + CVarCategory getCategory(); + String getCVarName(); + boolean parse(String str); + String format(); + String getDefault(); + void setDefault(); + default String getValues() { + return null; + } + Element selector(int x, int y, int w, int h); +} diff --git a/java/src/game/vars/CVarCategory.java b/java/src/game/vars/CVarCategory.java new file mode 100644 index 0000000..db5f46c --- /dev/null +++ b/java/src/game/vars/CVarCategory.java @@ -0,0 +1,26 @@ +package game.vars; + +import game.color.TextColor; + +public enum CVarCategory { + SYSTEM(TextColor.RED + "system"), + WINDOW(TextColor.BLUE + "window"), + GUI(TextColor.GREEN + "gui"), + STYLE(TextColor.VIOLET + "style"), + RENDER(TextColor.NEON + "render"), + BIND(TextColor.ORANGE + "bind"), + CONSOLE(TextColor.YELLOW + "console"), + PHYSICS(TextColor.CYAN + "physics"), + WORLD(TextColor.MAGENTA + "world"), + SOUND(TextColor.CRIMSON + "sound"); + + private final String name; + + private CVarCategory(String name) { + this.name = name; + } + + public String toString() { + return this.name; + } +} diff --git a/java/src/game/vars/ColorVar.java b/java/src/game/vars/ColorVar.java new file mode 100644 index 0000000..4a98027 --- /dev/null +++ b/java/src/game/vars/ColorVar.java @@ -0,0 +1,51 @@ +package game.vars; + +import java.lang.reflect.Field; + +import game.color.TextColor; +import game.gui.element.Label; +import game.gui.element.Slider; +import game.gui.element.Textbox; +import game.gui.element.Textbox.Action; +import game.util.Util; + +public class ColorVar extends IntVar { + private final boolean alpha; + + public ColorVar(String name, String display, Field field, Object object, CVarCategory category, boolean alpha, IntFunction func) { + super(name, display, field, object, category, Integer.MIN_VALUE, Integer.MAX_VALUE, func, null, 0); + this.alpha = alpha; + } + + public String getType() { + return this.alpha ? (TextColor.GRAY + "color32") : (TextColor.LGRAY + "color"); + } + + protected Integer parseValue(String str) { + if(str.length() != (this.alpha ? 8 : 6)) + return null; + Integer value = Util.parseInt(str, -16); + return this.alpha || (value & 0xff000000) == 0 ? (this.alpha ? value : (0xff000000 | value)) : null; + } + + protected String formatValue(int value) { + return String.format(this.alpha ? "%08x" : "%06x", this.alpha ? value : (value & 0x00ffffff)); + } + + public Slider selector(int x, int y, int w, int h) { + throw new UnsupportedOperationException("Kann keinen Schieberegler für Farben erstellen"); + } + + public Label label(int x, int y, int w, int h) { + return new Label(x, y, w, h, this.display); + } + + public Textbox editor(int x, int y, int w, int h) { + return new Textbox(x, y, w, h, this.alpha ? 8 : 6, true, new Textbox.Callback() { + public void use(Textbox elem, Textbox.Action value) { + if(value == Action.SEND || value == Action.UNFOCUS) + ColorVar.this.parse(elem.getText()); + } + }, this.format()); + } +} diff --git a/java/src/game/vars/EnumVar.java b/java/src/game/vars/EnumVar.java new file mode 100644 index 0000000..f1f84f2 --- /dev/null +++ b/java/src/game/vars/EnumVar.java @@ -0,0 +1,98 @@ +package game.vars; + +import java.lang.reflect.Field; + +import game.color.TextColor; +import game.gui.element.Dropdown; +import game.gui.element.Switch; +import game.properties.IStringSerializable; +import game.util.Util; + +public class EnumVar extends BaseVar { + public static interface EnumFunction extends VarFunction { + void apply(EnumVar cv, T value); + } + + private final EnumFunction func; + private final String values; + private final T def; + + public EnumVar(String name, String display, Field field, Object object, CVarCategory category, EnumFunction func) { + super(name, display, field, object, category); + this.func = func; + StringBuilder sb = new StringBuilder(); + for(T value : (T[])field.getType().getEnumConstants()) { + if(sb.length() > 0) + sb.append(','); + sb.append(value instanceof IStringSerializable ? ((IStringSerializable)value).getName() : value.toString()); + } + this.values = sb.toString(); + try { + this.def = (T)field.get(object); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public String getType() { + return TextColor.CYAN + "enum"; + } + + public boolean parse(String str) { + T value = (T)Util.parseEnum((Class)this.field.getType(), str); + try { + this.field.set(this.object, value); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + if(this.func != null) + this.func.apply(this, value); + return true; + } + + public String format() { + try { + T value = (T)this.field.get(this.object); + return value instanceof IStringSerializable ? ((IStringSerializable)value).getName() : value.toString(); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public String getDefault() { + return this.def instanceof IStringSerializable ? ((IStringSerializable)this.def).getName() : this.def.toString(); + } + + public String getValues() { + return this.values; + } + + public Dropdown selector(int x, int y, int w, int h) { + try { + return new Dropdown(x, y, w, h, false, (T[])this.field.getType().getEnumConstants(), this.def, (T)this.field.get(this.object), new Dropdown.Callback() { + public void use(Dropdown elem, T value) { + EnumVar.this.parse(value instanceof IStringSerializable ? ((IStringSerializable)value).getName() : value.toString()); + } + }, this.display); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public Switch switcher(int x, int y, int w, int h) { + try { + return new Switch(x, y, w, h, (T[])this.field.getType().getEnumConstants(), this.def, (T)this.field.get(this.object), new Switch.Callback() { + public void use(Switch elem, T value) { + EnumVar.this.parse(value instanceof IStringSerializable ? ((IStringSerializable)value).getName() : value.toString()); + } + }, this.display); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} diff --git a/java/src/game/vars/FloatVar.java b/java/src/game/vars/FloatVar.java new file mode 100644 index 0000000..cbac18e --- /dev/null +++ b/java/src/game/vars/FloatVar.java @@ -0,0 +1,103 @@ +package game.vars; + +import java.lang.reflect.Field; + +import game.color.TextColor; +import game.gui.element.Slider; +import game.util.ExtMath; + +public class FloatVar extends BaseVar { + public static interface FloatFunction extends VarFunction { + void apply(FloatVar cv, float value); + } + + private final String unit; + private final String format; + private final int precision; + private final float divider; + private final FloatFunction func; + private final float min; + private final float max; + private final float def; + + public static float getDivider(int precision) { + int div = 1; + for(int z = 0; z < precision; z++) { + div *= 10; + } + return (float)div; + } + + public FloatVar(String name, String display, Field field, Object object, CVarCategory category, float min, float max, FloatFunction func, String unit, int precision) { + super(name, display, field, object, category); + this.func = func; + this.min = min; + this.max = max; + this.unit = unit; + this.precision = precision; + this.format = "%." + precision + "f"; + this.divider = getDivider(precision); + try { + this.def = field.getFloat(object); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public String getType() { + return TextColor.YELLOW + "float"; + } + + public boolean parse(String str) { + float value; + try { + value = Float.parseFloat(str); + } + catch(NumberFormatException e) { + return false; + } + value = ExtMath.clampf(value, this.min, this.max); + int round = (int)(value * this.divider); + value = (float)round / this.divider; + try { + this.field.setFloat(this.object, value); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + if(this.func != null) + this.func.apply(this, value); + return true; + } + + public String format() { + try { + return String.format(this.format, this.field.getFloat(this.object)); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public String getDefault() { + return String.format(this.format, this.def); + } + + public String getValues() { + return String.format(this.format + ".." + this.format, this.min, this.max); + } + + public Slider selector(int x, int y, int w, int h) { + try { + return new Slider(x, y, w, h, this.unit.equals("%") ? -1 : this.precision, this.min, this.max, this.def, this.field.getFloat(this.object), new Slider.FloatCallback() { + public void use(Slider elem, float value) { + FloatVar.this.parse(String.format(FloatVar.this.format, value)); + } + }, this.display, this.unit); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} diff --git a/java/src/game/vars/IntVar.java b/java/src/game/vars/IntVar.java new file mode 100644 index 0000000..95f791d --- /dev/null +++ b/java/src/game/vars/IntVar.java @@ -0,0 +1,95 @@ +package game.vars; + +import java.lang.reflect.Field; + +import game.color.TextColor; +import game.gui.element.Slider; +import game.util.ExtMath; +import game.util.Util; + +public class IntVar extends BaseVar { + public static interface IntFunction extends VarFunction { + void apply(IntVar cv, int value); + } + + private final String unit; + private final int precision; + private final IntFunction func; + private final int min; + private final int max; + private final int def; + + public IntVar(String name, String display, Field field, Object object, CVarCategory category, int min, int max, IntFunction func, String unit, int precision) { + super(name, display, field, object, category); + this.func = func; + this.min = min; + this.max = max; + this.unit = unit; + this.precision = precision; + try { + this.def = field.getInt(object); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public String getType() { + return TextColor.GREEN + "int"; + } + + protected Integer parseValue(String str) { + return Util.parseInt(str, 0); + } + + protected String formatValue(int value) { + return "" + value; + } + + public boolean parse(String str) { + Integer value = this.parseValue(str); + if(value == null) + return false; + value = ExtMath.clampi(value, this.min, this.max); + try { + this.field.setInt(this.object, value); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + if(this.func != null) + this.func.apply(this, value); + return true; + } + + public String format() { + try { + return this.formatValue(this.field.getInt(this.object)); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public String getDefault() { + return this.formatValue(this.def); + } + + public String getValues() { + return this.min == Integer.MIN_VALUE && this.max == Integer.MAX_VALUE ? null : ((this.min == Integer.MIN_VALUE ? "" : ("" + this.min)) + + ".." + (this.max == Integer.MAX_VALUE ? "" : ("" + this.max))); + } + + public Slider selector(int x, int y, int w, int h) { + try { + return new Slider(x, y, w, h, this.precision, this.min, this.max, this.def, this.field.getInt(this.object), new Slider.Callback() { + public void use(Slider elem, int value) { + IntVar.this.parse(IntVar.this.formatValue(value)); + } + }, this.display, this.unit); + } + catch(IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} diff --git a/java/src/game/vars/Variable.java b/java/src/game/vars/Variable.java new file mode 100644 index 0000000..668d42a --- /dev/null +++ b/java/src/game/vars/Variable.java @@ -0,0 +1,27 @@ +package game.vars; + +import static java.lang.annotation.ElementType.FIELD; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import game.vars.BaseVar.VarFunction; + +@Target(FIELD) +@Retention(value = RetentionPolicy.RUNTIME) +public @interface Variable { + public static enum IntType { + INT, COLOR, ALPHA; + } + + String name(); + String display() default ""; + CVarCategory category(); + float min() default (float)Integer.MIN_VALUE; + float max() default (float)Integer.MAX_VALUE; + IntType type() default IntType.INT; + int precision() default 0; + String unit() default ""; + Class callback() default VarFunction.class; +} diff --git a/java/src/game/window/Bind.java b/java/src/game/window/Bind.java new file mode 100644 index 0000000..d10f7a3 --- /dev/null +++ b/java/src/game/window/Bind.java @@ -0,0 +1,227 @@ +package game.window; + +import game.Game; +import game.color.TextColor; +import game.gui.element.Element; +import game.properties.IStringSerializable; +import game.util.Util; +import game.vars.CVar; +import game.vars.CVarCategory; + +public enum Bind implements IStringSerializable, CVar { + FORWARD("forward", "Vorwärts", Keysym.W), + LEFT("left", "Nach links", Keysym.A), + BACKWARD("backward", "Rückwärts", Keysym.S), + RIGHT("right", "Nach rechts", Keysym.D), + UP("up", "Aufwärts, Springen", Keysym.SPACE), + DOWN("down", "Abwärts, Langsam", Keysym.LEFT_CONTROL), + FAST("fast", "Schneller", Keysym.LEFT_SHIFT), + INVENTORY("inventory", "Inventar", Keysym.E), + PRIMARY("primary", "Primäre Aktion", Button.MOUSE_LEFT), + SECONDARY("secondary", "Sekundäre Aktion", Button.MOUSE_RIGHT), + TERTIARY("tertiary", "Tertiäre Aktion", Button.MOUSE_MIDDLE), + QUARTERNARY("quarternary", "Quartäre Aktion", Keysym.R), + THROW("throw", "Weg werfen", Keysym.Q), + SELECT1("select1", "Auswahl #1", Keysym.N1), + SELECT2("select2", "Auswahl #2", Keysym.N2), + SELECT3("select3", "Auswahl #3", Keysym.N3), + SELECT4("select4", "Auswahl #4", Keysym.N4), + SELECT5("select5", "Auswahl #5", Keysym.N5), + SELECT6("select6", "Auswahl #6", Keysym.N6), + SELECT7("select7", "Auswahl #7", Keysym.N7), + SELECT8("select8", "Auswahl #8", Keysym.N8), + SELECT9("select9", "Auswahl #9", Keysym.N9), + COMMAND("command", "Befehl / Chat", Keysym.C), + INFO("info", "Infos einblenden", Keysym.TAB), + PERSPECTIVE("perspective", "Perspektive ändern", Keysym.F5), + ZOOM("zoom", "Kamera zoomen", Keysym.Y), + MENU("menu", "Menü", Keysym.ESCAPE), + SCREENSHOT("screenshot", "Bildschirmfoto", Keysym.F10), + SHOW("overlay", "Perf.-Anzeige", Keysym.F2), + FULLSCREEN("fullscreen", "Vollbild", Keysym.F12), + CHEAT("cheat", "Schummeln / Debug", Keysym.F3); + + private static boolean windowActive; + private static boolean inputEnabled; + private static boolean mouseEnabled; + private static Bind waitingFor; + private static Keysym keyRelease; + + private final String id; + private final String name; + private final Input defInput; + + private Input input; + private boolean pressed; + private boolean active; + + public static void updateBinds() { + for(Bind bind : values()) { + bind.update(); + } + mouseEnabled = true; + for(Wheel wheel : Wheel.values()) { + wheel.reset(); + } + } + + public static void disableMouse() { + mouseEnabled = false; + } + + public static boolean isInputEnabled() { + return inputEnabled; + } + + public static void disableInput(Bind wait) { + inputEnabled = false; + waitingFor = wait; + } + + public static void disableInput(Keysym release) { + inputEnabled = false; + keyRelease = release; + } + + public static Bind getWaiting() { + return waitingFor; + } + + public static void unsetWaiting() { + waitingFor = null; + } + + public static void enableInput() { + if(waitingFor == null && (keyRelease == null || !keyRelease.read())) + inputEnabled = true; + } + + public static void setBind(Input input, boolean release) { + if(waitingFor != null) { + if(release) { + if(input == keyRelease) { + waitingFor.input = input; + waitingFor = null; + keyRelease = null; + Game.getGame().setDirty(); + if(Game.getGame().open != null) + Game.getGame().open.reformat(); + } + } + else if(keyRelease == null) { + if(input instanceof Keysym) { + keyRelease = (Keysym)input; + } + else { + waitingFor.input = input; + waitingFor = null; + Game.getGame().setDirty(); + if(Game.getGame().open != null) + Game.getGame().open.reformat(); + } + } + } + } + + public static boolean isWindowActive() { + return windowActive; + } + + public static void setWindowActive(boolean active) { + windowActive = active; + for(Wheel wheel : Wheel.values()) { + wheel.reset(); + } + } + + private Bind(String id, String name, Input input) { + this.id = id; + this.name = name; + this.input = this.defInput = input; + } + + private void update() { + boolean last = this.pressed; + this.pressed = inputEnabled && windowActive && this.input != null && this.input.read(); + if(inputEnabled && this.input instanceof Button && !mouseEnabled) + last = this.pressed; + this.active = this.pressed && !last; + } + + public void setInput(Input input) { + this.input = input; + } + + public Input getInput() { + return this.input; + } + + public String getName() { + return this.id; + } + + public String getDisplay() { + return this.name; + } + + public boolean isDown() { + return inputEnabled && this.pressed; + } + + public boolean isPressed() { + return inputEnabled && this.active; + } + + public String getCVarName() { + return "key_" + this.id; + } + + public String getType() { + return TextColor.VIOLET + "key"; + } + + public CVarCategory getCategory() { + return CVarCategory.BIND; + } + + public boolean parse(String str) { + if("none".equalsIgnoreCase(str)) { + this.input = null; + return true; + } + Input input = Util.parseEnum(Input.class, str, Keysym.class, Button.class, Wheel.class); + if(input != null) + this.input = input; + return input != null; + } + + public String format() { + return this.input != null ? this.input.getName() : "none"; + } + + public String getDefault() { + return this.defInput != null ? this.defInput.getName() : "none"; + } + + public void setDefault() { + this.input = this.defInput; + } + + public Element selector(int x, int y, int w, int h) { + throw new UnsupportedOperationException("Kann kein Element für Tastenbelegung erstellen"); + } + + public boolean isDefault() { + return this.input == this.defInput; + } + + public boolean isDupe() { + if(this.input == null) + return false; + for(Bind bind : values()) { + if(this != bind && bind.input == this.input) + return true; + } + return false; + } +} diff --git a/java/src/game/window/Button.java b/java/src/game/window/Button.java new file mode 100644 index 0000000..89cd8f8 --- /dev/null +++ b/java/src/game/window/Button.java @@ -0,0 +1,51 @@ +package game.window; + +import game.Game; + +public enum Button implements Input { + MOUSE_LEFT("lmb", "Linke Maustaste"), + MOUSE_RIGHT("rmb", "Rechte Maustaste"), + MOUSE_MIDDLE("mmb", "Mittlere Maustaste"), + MOUSE_BTN_X("xmb", "Maustaste Seite 1"), + MOUSE_BTN_Y("ymb", "Maustaste Seite 2"), + MOUSE_BTN_A("m6", "Maustaste 6"), + MOUSE_BTN_B("m7", "Maustaste 7"), + MOUSE_BTN_C("m8", "Maustaste 8"); + + private static int buttons; + + private final String id; + private final String name; + + private boolean down; + + public static boolean isMouseDown() { + return buttons != 0; + } + + private Button(String id, String name) { + this.id = id; + this.name = name; + } + + public String getName() { + return this.id; + } + + public String getDisplay() { + return this.name; + } + + public boolean read() { + return Game.getGame().open == null && this.down; + } + + public void setDown(boolean down) { + this.down = down; + buttons = (buttons & ~(1 << this.ordinal())) | (down ? 1 << this.ordinal() : 0); + } + + public boolean isDown() { + return this.down; + } +} diff --git a/java/src/game/window/DisplayMode.java b/java/src/game/window/DisplayMode.java new file mode 100644 index 0000000..c734e4d --- /dev/null +++ b/java/src/game/window/DisplayMode.java @@ -0,0 +1,26 @@ +package game.window; + +public class DisplayMode { + public static final int VID_MODES = 28; + + public final int width; + public final int height; + public final int refresh; + + public DisplayMode(int width, int height, int refresh) { + this.width = width; + this.height = height; + this.refresh = refresh; + } + + public String toString() { + return String.format("%dx%d @ %d Hz", this.width, this.height, this.refresh); + } + + public boolean equals(Object obj) { + if(!(obj instanceof DisplayMode)) + return false; + DisplayMode other = (DisplayMode)obj; + return this.width == other.width && this.height == other.height && this.refresh == other.refresh; + } +} diff --git a/java/src/game/window/Input.java b/java/src/game/window/Input.java new file mode 100644 index 0000000..848f2b6 --- /dev/null +++ b/java/src/game/window/Input.java @@ -0,0 +1,8 @@ +package game.window; + +import game.properties.IStringSerializable; +import game.util.Displayable; + +public interface Input extends IStringSerializable, Displayable { + public boolean read(); +} diff --git a/java/src/game/window/KeyEvent.java b/java/src/game/window/KeyEvent.java new file mode 100644 index 0000000..d4101ae --- /dev/null +++ b/java/src/game/window/KeyEvent.java @@ -0,0 +1,7 @@ +package game.window; + +public enum KeyEvent { + RELEASE, + PRESS, + REPEAT; +} diff --git a/java/src/game/window/Keysym.java b/java/src/game/window/Keysym.java new file mode 100644 index 0000000..84bdcea --- /dev/null +++ b/java/src/game/window/Keysym.java @@ -0,0 +1,141 @@ +package game.window; + +public enum Keysym implements Input { + N0('0'), + N1('1'), + N2('2'), + N3('3'), + N4('4'), + N5('5'), + N6('6'), + N7('7'), + N8('8'), + N9('9'), + + A('a'), + B('b'), + C('c'), + D('d'), + E('e'), + F('f'), + G('g'), + H('h'), + I('i'), + J('j'), + K('k'), + L('l'), + M('m'), + N('n'), + O('o'), + P('p'), + Q('q'), + R('r'), + S('s'), + T('t'), + U('u'), + V('v'), + W('w'), + X('x'), + Y('y'), + Z('z'), + + F1("f1", "F1"), + F2("f2", "F2"), + F3("f3", "F3"), + F4("f4", "F4"), + F5("f5", "F5"), + F6("f6", "F6"), + F7("f7", "F7"), + F8("f8", "F8"), + F9("f9", "F9"), + F10("f10", "F10"), + F11("f11", "F11"), + F12("f12", "F12"), + + KP_0("kp0", "Num 0"), + KP_1("kp1", "Num 1"), + KP_2("kp2", "Num 2"), + KP_3("kp3", "Num 3"), + KP_4("kp4", "Num 4"), + KP_5("kp5", "Num 5"), + KP_6("kp6", "Num 6"), + KP_7("kp7", "Num 7"), + KP_8("kp8", "Num 8"), + KP_9("kp9", "Num 9"), + + SPACE("space", "Leertaste"), + CIRCUMFLEX('^'), + SHARP_S('ß'), + ACUTE('´'), + UE('ü'), + PLUS('+'), + OE('ö'), + AE('ä'), + NUMBER_SIGN('#'), + LESS_THAN('<'), + COMMA(','), + PERIOD('.'), + HYPHEN('-'), + + KP_DECIMAL("kp.", "Num ."), + KP_DIVIDE("kp/", "Num /"), + KP_MULTIPLY("kp*", "Num *"), + KP_SUBTRACT("kp-", "Num -"), + KP_ADD("kp+", "Num +"), + KP_ENTER("enter", "Num Enter"), + KP_EQUAL("kp=", "Num ="), + + CAPS_LOCK("caps", "Feststellen"), + SCROLL_LOCK("scroll", "Scroll Lock"), + NUM_LOCK("num", "Num Lock"), + + ESCAPE("esc", "Esc"), + RETURN("return", "Enter"), + TAB("tab", "Tab"), + BACKSPACE("bksp", "Rücktaste"), + INSERT("ins", "Einfg"), + DELETE("del", "Entf"), + RIGHT("right", "Pfeil rechts"), + LEFT("left", "Pfeil links"), + DOWN("down", "Pfeil unten"), + UP("up", "Pfeil oben"), + PAGE_UP("pgup", "Bild auf"), + PAGE_DOWN("pgdn", "Bild ab"), + HOME("home", "Pos1"), + END("end", "Ende"), + PRINT_SCREEN("print", "Druck"), + PAUSE("pause", "Pause"), + LEFT_SHIFT("lshift", "Umschalt links"), + LEFT_CONTROL("lctrl", "Strg links"), + ALT("alt", "Alt"), + LEFT_LINUX("llinux", "Linux links"), + RIGHT_SHIFT("rshift", "Umschalt rechts"), + RIGHT_CONTROL("rctrl", "Strg rechts"), + ALT_GRAPH("altgr", "Alt Gr"), + RIGHT_LINUX("rlinux", "Linux rechts"), + MENU("menu", "Menü"); + + private final String id; + private final String name; + + private Keysym(String id, String name) { + this.id = id; + this.name = name; + } + + private Keysym(char character) { + this(Character.toString(character), "<" + Character.toUpperCase(character) + ">"); + } + + public String getName() { + return this.id; + } + + public String getDisplay() { + return this.name; + } + + public boolean read() { + return WCF.getKey(this.ordinal() + 1); + } +} diff --git a/java/src/game/window/WCF.java b/java/src/game/window/WCF.java new file mode 100644 index 0000000..702afad --- /dev/null +++ b/java/src/game/window/WCF.java @@ -0,0 +1,535 @@ +package game.window; + +public abstract class WCF { + public static final int GL_EXP = 0x800; + public static final int GL_LIGHT_MODEL_AMBIENT = 0xB53; + public static final int GL_COLOR_MATERIAL = 0xB57; + public static final int GL_FOG = 0xB60; + public static final int GL_FOG_DENSITY = 0xB62; + public static final int GL_FOG_START = 0xB63; + public static final int GL_FOG_END = 0xB64; + public static final int GL_FOG_MODE = 0xB65; + public static final int GL_FOG_COLOR = 0xB66; + public static final int GL_LIGHT0 = 0x4000; + public static final int GL_LIGHT1 = 0x4001; + public static final int GL_AMBIENT = 0x1200; + public static final int GL_DIFFUSE = 0x1201; + public static final int GL_SPECULAR = 0x1202; + public static final int GL_POSITION = 0x1203; + public static final int GL_COMPILE = 0x1300; + public static final int GL_AMBIENT_AND_DIFFUSE = 0x1602; + public static final int GL_MODELVIEW = 0x1700; + public static final int GL_PROJECTION = 0x1701; + public static final int GL_CLAMP = 0x2900; + public static final int GL_VERTEX_ARRAY = 0x8074; + public static final int GL_NORMAL_ARRAY = 0x8075; + public static final int GL_COLOR_ARRAY = 0x8076; + public static final int GL_TEXTURE_COORD_ARRAY = 0x8078; + + public static final int GL_DEPTH_BUFFER_BIT = 0x00000100; + public static final int GL_STENCIL_BUFFER_BIT = 0x00000400; + public static final int GL_COLOR_BUFFER_BIT = 0x00004000; + public static final int GL_FALSE = 0; + public static final int GL_TRUE = 1; + public static final int GL_POINTS = 0x0000; + public static final int GL_LINES = 0x0001; + public static final int GL_LINE_LOOP = 0x0002; + public static final int GL_LINE_STRIP = 0x0003; + public static final int GL_TRIANGLES = 0x0004; + public static final int GL_TRIANGLE_STRIP = 0x0005; + public static final int GL_TRIANGLE_FAN = 0x0006; + public static final int GL_NEVER = 0x0200; + public static final int GL_LESS = 0x0201; + public static final int GL_EQUAL = 0x0202; + public static final int GL_LEQUAL = 0x0203; + public static final int GL_GREATER = 0x0204; + public static final int GL_NOTEQUAL = 0x0205; + public static final int GL_GEQUAL = 0x0206; + public static final int GL_ALWAYS = 0x0207; + public static final int GL_ZERO = 0; + public static final int GL_ONE = 1; + public static final int GL_SRC_COLOR = 0x0300; + public static final int GL_ONE_MINUS_SRC_COLOR = 0x0301; + public static final int GL_SRC_ALPHA = 0x0302; + public static final int GL_ONE_MINUS_SRC_ALPHA = 0x0303; + public static final int GL_DST_ALPHA = 0x0304; + public static final int GL_ONE_MINUS_DST_ALPHA = 0x0305; + public static final int GL_DST_COLOR = 0x0306; + public static final int GL_ONE_MINUS_DST_COLOR = 0x0307; + public static final int GL_SRC_ALPHA_SATURATE = 0x0308; + public static final int GL_NONE = 0; + public static final int GL_FRONT_LEFT = 0x0400; + public static final int GL_FRONT_RIGHT = 0x0401; + public static final int GL_BACK_LEFT = 0x0402; + public static final int GL_BACK_RIGHT = 0x0403; + public static final int GL_FRONT = 0x0404; + public static final int GL_BACK = 0x0405; + public static final int GL_LEFT = 0x0406; + public static final int GL_RIGHT = 0x0407; + public static final int GL_FRONT_AND_BACK = 0x0408; + public static final int GL_NO_ERROR = 0; + public static final int GL_INVALID_ENUM = 0x0500; + public static final int GL_INVALID_VALUE = 0x0501; + public static final int GL_INVALID_OPERATION = 0x0502; + public static final int GL_OUT_OF_MEMORY = 0x0505; + public static final int GL_CW = 0x0900; + public static final int GL_CCW = 0x0901; + public static final int GL_POINT_SIZE = 0x0B11; + public static final int GL_POINT_SIZE_RANGE = 0x0B12; + public static final int GL_POINT_SIZE_GRANULARITY = 0x0B13; + public static final int GL_LINE_SMOOTH = 0x0B20; + public static final int GL_LINE_WIDTH = 0x0B21; + public static final int GL_LINE_WIDTH_RANGE = 0x0B22; + public static final int GL_LINE_WIDTH_GRANULARITY = 0x0B23; + public static final int GL_POLYGON_MODE = 0x0B40; + public static final int GL_POLYGON_SMOOTH = 0x0B41; + public static final int GL_CULL_FACE = 0x0B44; + public static final int GL_CULL_FACE_MODE = 0x0B45; + public static final int GL_FRONT_FACE = 0x0B46; + public static final int GL_DEPTH_RANGE = 0x0B70; + public static final int GL_DEPTH_TEST = 0x0B71; + public static final int GL_DEPTH_WRITEMASK = 0x0B72; + public static final int GL_DEPTH_CLEAR_VALUE = 0x0B73; + public static final int GL_DEPTH_FUNC = 0x0B74; + public static final int GL_STENCIL_TEST = 0x0B90; + public static final int GL_STENCIL_CLEAR_VALUE = 0x0B91; + public static final int GL_STENCIL_FUNC = 0x0B92; + public static final int GL_STENCIL_VALUE_MASK = 0x0B93; + public static final int GL_STENCIL_FAIL = 0x0B94; + public static final int GL_STENCIL_PASS_DEPTH_FAIL = 0x0B95; + public static final int GL_STENCIL_PASS_DEPTH_PASS = 0x0B96; + public static final int GL_STENCIL_REF = 0x0B97; + public static final int GL_STENCIL_WRITEMASK = 0x0B98; + public static final int GL_VIEWPORT = 0x0BA2; + public static final int GL_DITHER = 0x0BD0; + public static final int GL_BLEND_DST = 0x0BE0; + public static final int GL_BLEND_SRC = 0x0BE1; + public static final int GL_BLEND = 0x0BE2; + public static final int GL_LOGIC_OP_MODE = 0x0BF0; + public static final int GL_DRAW_BUFFER = 0x0C01; + public static final int GL_READ_BUFFER = 0x0C02; + public static final int GL_SCISSOR_BOX = 0x0C10; + public static final int GL_SCISSOR_TEST = 0x0C11; + public static final int GL_COLOR_CLEAR_VALUE = 0x0C22; + public static final int GL_COLOR_WRITEMASK = 0x0C23; + public static final int GL_DOUBLEBUFFER = 0x0C32; + public static final int GL_STEREO = 0x0C33; + public static final int GL_LINE_SMOOTH_HINT = 0x0C52; + public static final int GL_POLYGON_SMOOTH_HINT = 0x0C53; + public static final int GL_UNPACK_SWAP_BYTES = 0x0CF0; + public static final int GL_UNPACK_LSB_FIRST = 0x0CF1; + public static final int GL_UNPACK_ROW_LENGTH = 0x0CF2; + public static final int GL_UNPACK_SKIP_ROWS = 0x0CF3; + public static final int GL_UNPACK_SKIP_PIXELS = 0x0CF4; + public static final int GL_UNPACK_ALIGNMENT = 0x0CF5; + public static final int GL_PACK_SWAP_BYTES = 0x0D00; + public static final int GL_PACK_LSB_FIRST = 0x0D01; + public static final int GL_PACK_ROW_LENGTH = 0x0D02; + public static final int GL_PACK_SKIP_ROWS = 0x0D03; + public static final int GL_PACK_SKIP_PIXELS = 0x0D04; + public static final int GL_PACK_ALIGNMENT = 0x0D05; + public static final int GL_MAX_TEXTURE_SIZE = 0x0D33; + public static final int GL_MAX_VIEWPORT_DIMS = 0x0D3A; + public static final int GL_SUBPIXEL_BITS = 0x0D50; + public static final int GL_TEXTURE_1D = 0x0DE0; + public static final int GL_TEXTURE_2D = 0x0DE1; + public static final int GL_TEXTURE_WIDTH = 0x1000; + public static final int GL_TEXTURE_HEIGHT = 0x1001; + public static final int GL_TEXTURE_BORDER_COLOR = 0x1004; + public static final int GL_DONT_CARE = 0x1100; + public static final int GL_FASTEST = 0x1101; + public static final int GL_NICEST = 0x1102; + public static final int GL_BYTE = 0x1400; + public static final int GL_UNSIGNED_BYTE = 0x1401; + public static final int GL_SHORT = 0x1402; + public static final int GL_UNSIGNED_SHORT = 0x1403; + public static final int GL_INT = 0x1404; + public static final int GL_UNSIGNED_INT = 0x1405; + public static final int GL_FLOAT = 0x1406; + public static final int GL_CLEAR = 0x1500; + public static final int GL_AND = 0x1501; + public static final int GL_AND_REVERSE = 0x1502; + public static final int GL_COPY = 0x1503; + public static final int GL_AND_INVERTED = 0x1504; + public static final int GL_NOOP = 0x1505; + public static final int GL_XOR = 0x1506; + public static final int GL_OR = 0x1507; + public static final int GL_NOR = 0x1508; + public static final int GL_EQUIV = 0x1509; + public static final int GL_INVERT = 0x150A; + public static final int GL_OR_REVERSE = 0x150B; + public static final int GL_COPY_INVERTED = 0x150C; + public static final int GL_OR_INVERTED = 0x150D; + public static final int GL_NAND = 0x150E; + public static final int GL_SET = 0x150F; + public static final int GL_TEXTURE = 0x1702; + public static final int GL_COLOR = 0x1800; + public static final int GL_DEPTH = 0x1801; + public static final int GL_STENCIL = 0x1802; + public static final int GL_STENCIL_INDEX = 0x1901; + public static final int GL_DEPTH_COMPONENT = 0x1902; + public static final int GL_RED = 0x1903; + public static final int GL_GREEN = 0x1904; + public static final int GL_BLUE = 0x1905; + public static final int GL_ALPHA = 0x1906; + public static final int GL_RGB = 0x1907; + public static final int GL_RGBA = 0x1908; + public static final int GL_POINT = 0x1B00; + public static final int GL_LINE = 0x1B01; + public static final int GL_FILL = 0x1B02; + public static final int GL_KEEP = 0x1E00; + public static final int GL_REPLACE = 0x1E01; + public static final int GL_INCR = 0x1E02; + public static final int GL_DECR = 0x1E03; + public static final int GL_VENDOR = 0x1F00; + public static final int GL_RENDERER = 0x1F01; + public static final int GL_VERSION = 0x1F02; + public static final int GL_EXTENSIONS = 0x1F03; + public static final int GL_NEAREST = 0x2600; + public static final int GL_LINEAR = 0x2601; + public static final int GL_NEAREST_MIPMAP_NEAREST = 0x2700; + public static final int GL_LINEAR_MIPMAP_NEAREST = 0x2701; + public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702; + public static final int GL_LINEAR_MIPMAP_LINEAR = 0x2703; + public static final int GL_TEXTURE_MAG_FILTER = 0x2800; + public static final int GL_TEXTURE_MIN_FILTER = 0x2801; + public static final int GL_TEXTURE_WRAP_S = 0x2802; + public static final int GL_TEXTURE_WRAP_T = 0x2803; + public static final int GL_REPEAT = 0x2901; + public static final int GL_COLOR_LOGIC_OP = 0x0BF2; + public static final int GL_POLYGON_OFFSET_UNITS = 0x2A00; + public static final int GL_POLYGON_OFFSET_POINT = 0x2A01; + public static final int GL_POLYGON_OFFSET_LINE = 0x2A02; + public static final int GL_POLYGON_OFFSET_FILL = 0x8037; + public static final int GL_POLYGON_OFFSET_FACTOR = 0x8038; + public static final int GL_TEXTURE_BINDING_1D = 0x8068; + public static final int GL_TEXTURE_BINDING_2D = 0x8069; + public static final int GL_TEXTURE_INTERNAL_FORMAT = 0x1003; + public static final int GL_TEXTURE_RED_SIZE = 0x805C; + public static final int GL_TEXTURE_GREEN_SIZE = 0x805D; + public static final int GL_TEXTURE_BLUE_SIZE = 0x805E; + public static final int GL_TEXTURE_ALPHA_SIZE = 0x805F; + public static final int GL_DOUBLE = 0x140A; + public static final int GL_PROXY_TEXTURE_1D = 0x8063; + public static final int GL_PROXY_TEXTURE_2D = 0x8064; + public static final int GL_R3_G3_B2 = 0x2A10; + public static final int GL_RGB4 = 0x804F; + public static final int GL_RGB5 = 0x8050; + public static final int GL_RGB8 = 0x8051; + public static final int GL_RGB10 = 0x8052; + public static final int GL_RGB12 = 0x8053; + public static final int GL_RGB16 = 0x8054; + public static final int GL_RGBA2 = 0x8055; + public static final int GL_RGBA4 = 0x8056; + public static final int GL_RGB5_A1 = 0x8057; + public static final int GL_RGBA8 = 0x8058; + public static final int GL_RGB10_A2 = 0x8059; + public static final int GL_RGBA12 = 0x805A; + public static final int GL_RGBA16 = 0x805B; + public static final int GL_UNSIGNED_BYTE_3_3_2 = 0x8032; + public static final int GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033; + public static final int GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034; + public static final int GL_UNSIGNED_INT_8_8_8_8 = 0x8035; + public static final int GL_UNSIGNED_INT_10_10_10_2 = 0x8036; + public static final int GL_TEXTURE_BINDING_3D = 0x806A; + public static final int GL_PACK_SKIP_IMAGES = 0x806B; + public static final int GL_PACK_IMAGE_HEIGHT = 0x806C; + public static final int GL_UNPACK_SKIP_IMAGES = 0x806D; + public static final int GL_UNPACK_IMAGE_HEIGHT = 0x806E; + public static final int GL_TEXTURE_3D = 0x806F; + public static final int GL_PROXY_TEXTURE_3D = 0x8070; + public static final int GL_TEXTURE_DEPTH = 0x8071; + public static final int GL_TEXTURE_WRAP_R = 0x8072; + public static final int GL_MAX_3D_TEXTURE_SIZE = 0x8073; + public static final int GL_UNSIGNED_BYTE_2_3_3_REV = 0x8362; + public static final int GL_UNSIGNED_SHORT_5_6_5 = 0x8363; + public static final int GL_UNSIGNED_SHORT_5_6_5_REV = 0x8364; + public static final int GL_UNSIGNED_SHORT_4_4_4_4_REV = 0x8365; + public static final int GL_UNSIGNED_SHORT_1_5_5_5_REV = 0x8366; + public static final int GL_UNSIGNED_INT_8_8_8_8_REV = 0x8367; + public static final int GL_UNSIGNED_INT_2_10_10_10_REV = 0x8368; + public static final int GL_BGR = 0x80E0; + public static final int GL_BGRA = 0x80E1; + public static final int GL_MAX_ELEMENTS_VERTICES = 0x80E8; + public static final int GL_MAX_ELEMENTS_INDICES = 0x80E9; + public static final int GL_CLAMP_TO_EDGE = 0x812F; + public static final int GL_TEXTURE_MIN_LOD = 0x813A; + public static final int GL_TEXTURE_MAX_LOD = 0x813B; + public static final int GL_TEXTURE_BASE_LEVEL = 0x813C; + public static final int GL_TEXTURE_MAX_LEVEL = 0x813D; + public static final int GL_SMOOTH_POINT_SIZE_RANGE = 0x0B12; + public static final int GL_SMOOTH_POINT_SIZE_GRANULARITY = 0x0B13; + public static final int GL_SMOOTH_LINE_WIDTH_RANGE = 0x0B22; + public static final int GL_SMOOTH_LINE_WIDTH_GRANULARITY = 0x0B23; + public static final int GL_ALIASED_LINE_WIDTH_RANGE = 0x846E; + public static final int GL_TEXTURE0 = 0x84C0; + public static final int GL_TEXTURE1 = 0x84C1; + public static final int GL_TEXTURE2 = 0x84C2; + public static final int GL_TEXTURE3 = 0x84C3; + public static final int GL_TEXTURE4 = 0x84C4; + public static final int GL_TEXTURE5 = 0x84C5; + public static final int GL_TEXTURE6 = 0x84C6; + public static final int GL_TEXTURE7 = 0x84C7; + public static final int GL_TEXTURE8 = 0x84C8; + public static final int GL_TEXTURE9 = 0x84C9; + public static final int GL_TEXTURE10 = 0x84CA; + public static final int GL_TEXTURE11 = 0x84CB; + public static final int GL_TEXTURE12 = 0x84CC; + public static final int GL_TEXTURE13 = 0x84CD; + public static final int GL_TEXTURE14 = 0x84CE; + public static final int GL_TEXTURE15 = 0x84CF; + public static final int GL_TEXTURE16 = 0x84D0; + public static final int GL_TEXTURE17 = 0x84D1; + public static final int GL_TEXTURE18 = 0x84D2; + public static final int GL_TEXTURE19 = 0x84D3; + public static final int GL_TEXTURE20 = 0x84D4; + public static final int GL_TEXTURE21 = 0x84D5; + public static final int GL_TEXTURE22 = 0x84D6; + public static final int GL_TEXTURE23 = 0x84D7; + public static final int GL_TEXTURE24 = 0x84D8; + public static final int GL_TEXTURE25 = 0x84D9; + public static final int GL_TEXTURE26 = 0x84DA; + public static final int GL_TEXTURE27 = 0x84DB; + public static final int GL_TEXTURE28 = 0x84DC; + public static final int GL_TEXTURE29 = 0x84DD; + public static final int GL_TEXTURE30 = 0x84DE; + public static final int GL_TEXTURE31 = 0x84DF; + public static final int GL_ACTIVE_TEXTURE = 0x84E0; + public static final int GL_MULTISAMPLE = 0x809D; + public static final int GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E; + public static final int GL_SAMPLE_ALPHA_TO_ONE = 0x809F; + public static final int GL_SAMPLE_COVERAGE = 0x80A0; + public static final int GL_SAMPLE_BUFFERS = 0x80A8; + public static final int GL_SAMPLES = 0x80A9; + public static final int GL_SAMPLE_COVERAGE_VALUE = 0x80AA; + public static final int GL_SAMPLE_COVERAGE_INVERT = 0x80AB; + public static final int GL_TEXTURE_CUBE_MAP = 0x8513; + public static final int GL_TEXTURE_BINDING_CUBE_MAP = 0x8514; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; + public static final int GL_PROXY_TEXTURE_CUBE_MAP = 0x851B; + public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; + public static final int GL_COMPRESSED_RGB = 0x84ED; + public static final int GL_COMPRESSED_RGBA = 0x84EE; + public static final int GL_TEXTURE_COMPRESSION_HINT = 0x84EF; + public static final int GL_TEXTURE_COMPRESSED_IMAGE_SIZE = 0x86A0; + public static final int GL_TEXTURE_COMPRESSED = 0x86A1; + public static final int GL_NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2; + public static final int GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3; + public static final int GL_CLAMP_TO_BORDER = 0x812D; + public static final int GL_BLEND_DST_RGB = 0x80C8; + public static final int GL_BLEND_SRC_RGB = 0x80C9; + public static final int GL_BLEND_DST_ALPHA = 0x80CA; + public static final int GL_BLEND_SRC_ALPHA = 0x80CB; + public static final int GL_POINT_FADE_THRESHOLD_SIZE = 0x8128; + public static final int GL_DEPTH_COMPONENT16 = 0x81A5; + public static final int GL_DEPTH_COMPONENT24 = 0x81A6; + public static final int GL_DEPTH_COMPONENT32 = 0x81A7; + public static final int GL_MIRRORED_REPEAT = 0x8370; + public static final int GL_MAX_TEXTURE_LOD_BIAS = 0x84FD; + public static final int GL_TEXTURE_LOD_BIAS = 0x8501; + public static final int GL_INCR_WRAP = 0x8507; + public static final int GL_DECR_WRAP = 0x8508; + public static final int GL_TEXTURE_DEPTH_SIZE = 0x884A; + public static final int GL_TEXTURE_COMPARE_MODE = 0x884C; + public static final int GL_TEXTURE_COMPARE_FUNC = 0x884D; + public static final int GL_BLEND_COLOR = 0x8005; + public static final int GL_BLEND_EQUATION = 0x8009; + public static final int GL_CONSTANT_COLOR = 0x8001; + public static final int GL_ONE_MINUS_CONSTANT_COLOR = 0x8002; + public static final int GL_CONSTANT_ALPHA = 0x8003; + public static final int GL_ONE_MINUS_CONSTANT_ALPHA = 0x8004; + public static final int GL_FUNC_ADD = 0x8006; + public static final int GL_FUNC_REVERSE_SUBTRACT = 0x800B; + public static final int GL_FUNC_SUBTRACT = 0x800A; + public static final int GL_MIN = 0x8007; + public static final int GL_MAX = 0x8008; + public static final int GL_BUFFER_SIZE = 0x8764; + public static final int GL_BUFFER_USAGE = 0x8765; + public static final int GL_QUERY_COUNTER_BITS = 0x8864; + public static final int GL_CURRENT_QUERY = 0x8865; + public static final int GL_QUERY_RESULT = 0x8866; + public static final int GL_QUERY_RESULT_AVAILABLE = 0x8867; + public static final int GL_ARRAY_BUFFER = 0x8892; + + public static native void glAlphaFunc(int func, float ref); + public static native void glBindTexture(int texture); + public static native void glBlendFunc(int sfactor, int dfactor); + public static native void glCallList(int list); + public static native void glClear(int mask); + public static native void glClearColor(float red, float green, float blue, float alpha); + public static native void glClearDepth(double depth); + public static native void glColor4f(float red, float green, float blue, float alpha); + public static native void glColorMask(boolean red, boolean green, boolean blue, boolean alpha); + public static native void glColorMaterial(int face, int mode); + public static native void glColorPointer(int size, int type, int stride, long pointer); + public static native void glCullFace(int mode); + public static native void glDeleteLists(int list, int range); + public static native void glDeleteTextures(int texture); + public static native void glDepthFunc(int func); + public static native void glDepthMask(boolean flag); + public static native void glDisable(int cap); + public static native void glDisableClientState(int cap); + public static native void glDrawArrays(int mode, int first, int count); + public static native void glEnable(int cap); + public static native void glEnableClientState(int cap); + public static native void glEndList(); + public static native void glFogf(int pname, float param); + private static native void glFogfv(int pname, long params); + public static native void glFogi(int pname, int param); + public static native int glGenLists(int range); + public static native int glGenTextures(); + private static native void glGetFloatv(int pname, long params); + private static native void glGetIntegerv(long params); + private static native void glLightfv(int light, int pname, long params); + private static native void glLightModelfv(int pname, long params); + public static native void glLineWidth(float width); + public static native void glLoadIdentity(); + public static native void glMatrixMode(int mode); + private static native void glMultMatrixf(long m); + public static native void glNewList(int list, int mode); + public static native void glNormal3f(float nx, float ny, float nz); + private static native void glNormalPointer(int type, int stride, long pointer); + public static native void glPolygonOffset(float factor, float units); + public static native void glPopMatrix(); + public static native void glPushMatrix(); + public static native void glRotatef(float angle, float x, float y, float z); + public static native void glScalef(float x, float y, float z); + public static native void glShadeModel(int mode); + public static native void glTexCoordPointer(int size, int type, int stride, long pointer); + public static native void glTexImage2D(int width, int height); + public static native void glTexParameteri(int pname, int param); + private static native void glTexSubImage2D(int xoffset, int yoffset, int width, int height, long pixels); + public static native void glTranslatef(float x, float y, float z); + public static native void glVertexPointer(int size, int type, int stride, long pointer); + + public static native void glActiveTexture(int texture); + public static native void glClientActiveTexture(int texture); + public static native void glMultiTexCoord2f(int target, float s, float t); + + public static native void glBlendFuncSeparate(int sfactorRGB, int dfactorRGB, int sfactorAlpha, int dfactorAlpha); + + public static native void glBindBuffer(int buffer); + public static native void glDeleteBuffers(int buffer); + public static native int glGenBuffers(); + private static native void glBufferData(long data_size, long data); + + public static native void glOrtho(double left, double right, double bottom, double top, double near, double far); + public static native String glGetString(int id); + public static native void glScissor(int x, int y, int w, int h); + public static native void glViewport(int x, int y, int w, int h); + private static native void glReadPixels(int x, int y, long data); + public static native void glPolygonMode(boolean line); + public static native void glFlush(); + + + public static native long getTime(); + private static native int[] pollEvents(); + public static native void setWindowed(int xpos, int ypos, int xsize, int ysize); + public static native void setFullscreen(int width, int height, int refresh); + public static native boolean getKey(int code); + public static native void setTitle(String title); + public static native void setIcon(byte[] icon, int w, int h); + public static native String getClipboard(); + public static native void setClipboard(String text); + public static native void swapBuffers(); + public static native void grabCursor(boolean grab); + public static native void setVSync(boolean sync); + private static native int[] getModes(); + private static native int[] getMode(); + public static native boolean createWindow(String id, boolean gldebug); + public static native void destroyWindow(); + public static native void initWindow(int sx, int sy, int wx, int wy); + + public static void glBufferData(java.nio.ByteBuffer data) { + glBufferData(data.remaining(), ((sun.nio.ch.DirectBuffer)data).address() + data.position()); + } + public static void glColorPointer(int size, int type, int stride, java.nio.ByteBuffer pointer) { + glColorPointer(size, type, stride, ((sun.nio.ch.DirectBuffer)pointer).address() + pointer.position()); + } + public static void glFog(int pname, java.nio.FloatBuffer params) { + glFogfv(pname, ((sun.nio.ch.DirectBuffer)params).address() + (params.position() << 2)); + } + public static void glGetFloat(int pname, java.nio.FloatBuffer params) { + glGetFloatv(pname, ((sun.nio.ch.DirectBuffer)params).address() + (params.position() << 2)); + } + public static void glGetInteger(java.nio.IntBuffer params) { + glGetIntegerv(((sun.nio.ch.DirectBuffer)params).address() + (params.position() << 2)); + } + public static void glLight(int light, int pname, java.nio.FloatBuffer params) { + glLightfv(light, pname, ((sun.nio.ch.DirectBuffer)params).address() + (params.position() << 2)); + } + public static void glLightModel(int pname, java.nio.FloatBuffer params) { + glLightModelfv(pname, ((sun.nio.ch.DirectBuffer)params).address() + (params.position() << 2)); + } + public static void glMultMatrix(java.nio.FloatBuffer m) { + glMultMatrixf(((sun.nio.ch.DirectBuffer)m).address() + (m.position() << 2)); + } + public static void glNormalPointer(int type, int stride, java.nio.ByteBuffer pointer) { + glNormalPointer(type, stride, ((sun.nio.ch.DirectBuffer)pointer).address() + pointer.position()); + } + public static void glTexCoordPointer(int size, int type, int stride, java.nio.ByteBuffer pointer) { + glTexCoordPointer(size, type, stride, ((sun.nio.ch.DirectBuffer)pointer).address() + pointer.position()); + } + public static void glTexSubImage2D(int xoffset, int yoffset, int width, int height, java.nio.IntBuffer pixels) { + glTexSubImage2D(xoffset, yoffset, width, height, ((sun.nio.ch.DirectBuffer)pixels).address() + (pixels.position() << 2)); + } + public static void glVertexPointer(int size, int type, int stride, java.nio.ByteBuffer pointer) { + glVertexPointer(size, type, stride, ((sun.nio.ch.DirectBuffer)pointer).address() + pointer.position()); + } + public static void glReadPixels(int x, int y, java.nio.ByteBuffer data) { + glReadPixels(x, y, ((sun.nio.ch.DirectBuffer)data).address() + data.position()); + } + public static WindowEvent[] poll() { + int[] data = pollEvents(); + WindowEvent[] events = new WindowEvent[data.length / 3]; + for(int z = 0; z < events.length; z++) { + events[z] = new WindowEvent(WindowAction.values()[data[z * 3 + 0]], data[z * 3 + 1], data[z * 3 + 2]); + } + return events; + } + public static DisplayMode[] getDisplayModes() { + int[] data = getModes(); + if(data == null) + return null; + DisplayMode[] modes = new DisplayMode[data.length / 3]; + for(int z = 0; z < modes.length; z++) { + modes[z] = new DisplayMode(data[z * 3 + 0], data[z * 3 + 1], data[z * 3 + 2]); + } + return modes; + } + public static DisplayMode getDisplayMode() { + int[] data = getMode(); + if(data == null) + return null; + return new DisplayMode(data[0], data[1], data[2]); + } + public static void init() { + System.setProperty("java.library.path", "lib"); + try { + java.lang.reflect.Field paths = ClassLoader.class.getDeclaredField("sys_paths"); + paths.setAccessible(true); + paths.set(null, null); + paths.setAccessible(false); + } + catch(NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + java.io.File dir = new java.io.File("lib"); + dir.mkdirs(); + java.io.InputStream in = WCF.class.getResourceAsStream("/libwcf.so"); + if(in == null) + throw new RuntimeException(new java.io.FileNotFoundException("libwcf.so")); + try { + java.nio.file.Files.copy(in, new java.io.File(dir, "libwcf.so").toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); + } + catch(java.io.IOException e) { + throw new RuntimeException(e); + } + System.loadLibrary("wcf"); + } +} diff --git a/java/src/game/window/Wheel.java b/java/src/game/window/Wheel.java new file mode 100644 index 0000000..fff8d68 --- /dev/null +++ b/java/src/game/window/Wheel.java @@ -0,0 +1,40 @@ +package game.window; + +import game.Game; + +public enum Wheel implements Input { + SCROLL_UP("scrup", "Mausrad aufwärts"), + SCROLL_DOWN("scrdn", "Mausrad abwärts"), + SCROLL_LEFT("scrl", "Mausrad links"), + SCROLL_RIGHT("scrr", "Mausrad rechts"); + + private final String id; + private final String name; + + private boolean used; + + private Wheel(String id, String name) { + this.id = id; + this.name = name; + } + + public String getName() { + return this.id; + } + + public String getDisplay() { + return this.name; + } + + public boolean read() { + return Game.getGame().open == null && this.used; + } + + public void setUsed() { + this.used = true; + } + + public void reset() { + this.used = false; + } +} diff --git a/java/src/game/window/WindowAction.java b/java/src/game/window/WindowAction.java new file mode 100644 index 0000000..e775b65 --- /dev/null +++ b/java/src/game/window/WindowAction.java @@ -0,0 +1,14 @@ +package game.window; + +public enum WindowAction { + RESIZE, + POSITION, + CURSOR, + SCROLL, + BUTTON, + KEY, + CHARACTER, + REDRAW, + CLOSED, + FOCUS; +} diff --git a/java/src/game/window/WindowEvent.java b/java/src/game/window/WindowEvent.java new file mode 100644 index 0000000..d370a06 --- /dev/null +++ b/java/src/game/window/WindowEvent.java @@ -0,0 +1,13 @@ +package game.window; + +public class WindowEvent { + public final WindowAction action; + public final int param1; + public final int param2; + + public WindowEvent(WindowAction action, int p1, int p2) { + this.action = action; + this.param1 = p1; + this.param2 = p2; + } +}