diff --git a/src/main/java/com/surgeplay/visage/distributor/VisageHandler.java b/src/main/java/com/surgeplay/visage/distributor/VisageHandler.java index 2e65ee6..a30a2ef 100644 --- a/src/main/java/com/surgeplay/visage/distributor/VisageHandler.java +++ b/src/main/java/com/surgeplay/visage/distributor/VisageHandler.java @@ -24,6 +24,11 @@ package com.surgeplay.visage.distributor; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -204,7 +209,11 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques } int rounded = Math.round(height / (float) granularity)*granularity; if (rounded != height) { - sendPermanentRedirect(baseUrl+"/"+modeStr+"/"+rounded+"/"+subject, response); + String query = ""; + if (request.getQueryString() != null) { + query = "?"+request.getQueryString(); + } + sendPermanentRedirect(baseUrl+"/"+modeStr+"/"+rounded+"/"+subject+query, response); return; } @@ -258,7 +267,11 @@ public void onProfileLookupFailed(GameProfile profile, Exception e) { return; } else if (result[0] instanceof UUID) { uuid = (UUID) result[0]; - response.sendRedirect(baseUrl+"/"+modeStr+"/"+height+"/"+uuid.toString().replace("-", "")); + String query = ""; + if (request.getQueryString() != null) { + query = "&"+request.getQueryString(); + } + response.sendRedirect(baseUrl+"/"+modeStr+"/"+height+"/"+uuid.toString().replace("-", "")+"?resolvedUsername"+query); j.set(subject, uuid.toString()); j.pexpire(subject, resolverTtlMillis); return; @@ -305,7 +318,6 @@ public void onProfileLookupFailed(GameProfile profile, Exception e) { sj.pexpire(uuid.toString()+":profile", skinTtlMillis); } } - System.out.println(profile); if (skinResp != null && skinResp.length > 3) { skin = skinResp; } else { @@ -352,8 +364,6 @@ public void onProfileLookupFailed(GameProfile profile, Exception e) { } } - System.out.println(profile); - if (mode == RenderMode.SKIN) { write(response, missed, skin, "none"); return; @@ -373,7 +383,40 @@ public void onProfileLookupFailed(GameProfile profile, Exception e) { if (resp == null) { continue; } - write(response, missed, resp.png, resp.renderer); + byte[] png = resp.png; + if (request.getParameter("resolvedUsername") != null) { + BufferedImage img = ImageIO.read(new ByteArrayInputStream(png)); + Graphics2D g = img.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setColor(Color.RED); + g.fillRect(0, 0, img.getWidth(), 8); + g.fillRect(0, 0, 8, img.getHeight()); + g.fillRect(img.getWidth()-8, 0, 8, img.getHeight()); + g.fillRect(0, img.getHeight()-8, img.getWidth(), 8); + if (img.getWidth() >= 480) { + g.setFont(Font.decode("Dialog-Bold").deriveFont(48f)); + g.drawString("USERNAME RENDER", 12, 56); + } else if (img.getWidth() >= 256) { + g.setFont(Font.decode("Dialog-Bold").deriveFont(24f)); + g.drawString("USERNAME RENDER", 12, 32); + } else if (img.getWidth() >= 144) { + g.setFont(Font.decode("Dialog-Bold").deriveFont(12f)); + g.drawString("USERNAME RENDER", 12, 24); + } else if (img.getWidth() >= 96) { + g.setFont(Font.decode("Dialog-Bold").deriveFont(12f)); + g.drawString("USERNAME", 12, 24); + g.drawString("RENDER", 12, 38); + } else if (img.getWidth() >= 64) { + g.setFont(Font.decode("Dialog").deriveFont(8f)); + g.drawString("USERNAME", 10, 18); + g.drawString("RENDER", 10, 26); + } + g.dispose(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(img, "PNG", baos); + png = baos.toByteArray(); + } + write(response, missed, png, resp.renderer); return; } if (ex != null) { diff --git a/src/main/java/com/surgeplay/visage/renderer/RenderContext.java b/src/main/java/com/surgeplay/visage/renderer/RenderContext.java index 0888338..6316814 100644 --- a/src/main/java/com/surgeplay/visage/renderer/RenderContext.java +++ b/src/main/java/com/surgeplay/visage/renderer/RenderContext.java @@ -24,7 +24,6 @@ package com.surgeplay.visage.renderer; -import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -73,7 +72,6 @@ import static org.lwjgl.opengl.GL12.*; import static org.lwjgl.opengl.GL14.*; import static org.lwjgl.opengl.GL15.*; -import static org.lwjgl.opengl.GL20.*; import static org.lwjgl.opengl.GL30.*; import static org.lwjgl.system.MemoryUtil.*; @@ -146,25 +144,27 @@ public class RenderContext extends Thread { }; private static final int CANVAS_WIDTH = 512; - private static final float CANVAS_WIDTHf = CANVAS_WIDTH; private static final int CANVAS_HEIGHT = 832; - private static final float CANVAS_HEIGHTf = CANVAS_HEIGHT; - private static final int SUPERSAMPLING = 4; + private static final int SKIN_SUPERSAMPLING = 16; private static final BufferedImage shadow; + private static final BufferedImage skinUnderlay; static { try { shadow = ImageIO.read(ClassLoader.getSystemResource("shadow.png")); + skinUnderlay = ImageIO.read(ClassLoader.getSystemResource("skin_underlay.png")); } catch (IOException e) { throw new InternalError(e); } } - public int cubeVbo, planeVbo, texture, shadowTexture; + public int cubeVbo, planeVbo, skinTexture, shadowTexture, skinUnderlayTexture; - public int fbo, fboTex; - public int fxaaProgram; + public int fbo, fbo2, swapFbo, swapFboTex; + public int skinFbo, skinFboTex; + + public int renderPass; private static int nextId = 1; public VisageRenderer parent; @@ -211,6 +211,9 @@ public void run() { if (!GL.getCapabilities().OpenGL30) { throw new RuntimeException("OpenGL 3.0 is required"); } + if (!GL.getCapabilities().GL_ARB_texture_multisample) { + throw new RuntimeException("ARB_texture_multisample is required"); + } if (parent.config.getBoolean("continuous") && parent.config.getBoolean("visible")) { glfwSwapInterval(60); @@ -226,11 +229,18 @@ public void run() { planeVbo = ids.get(); checkGLError(); - IntBuffer textures = BufferUtils.createIntBuffer(3); + IntBuffer textures = BufferUtils.createIntBuffer(5); glGenTextures(textures); - texture = textures.get(); + skinTexture = textures.get(); shadowTexture = textures.get(); - fboTex = textures.get(); + skinFboTex = textures.get(); + skinUnderlayTexture = textures.get(); + swapFboTex = textures.get(); + checkGLError(); + + glBindTexture(GL_TEXTURE_2D, skinTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); checkGLError(); Textures.upload(shadow, GL_RGBA8, shadowTexture); @@ -238,31 +248,86 @@ public void run() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); checkGLError(); - glBindTexture(GL_TEXTURE_2D, fboTex); + Textures.upload(skinUnderlay, GL_RGBA8, skinUnderlayTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + checkGLError(); + + glBindTexture(GL_TEXTURE_2D, skinFboTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 64*SKIN_SUPERSAMPLING, 64*SKIN_SUPERSAMPLING, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + checkGLError(); + + glBindTexture(GL_TEXTURE_2D, swapFboTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, CANVAS_WIDTH*SUPERSAMPLING, CANVAS_HEIGHT*SUPERSAMPLING, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, (CANVAS_WIDTH*SUPERSAMPLING)/2, (CANVAS_HEIGHT*SUPERSAMPLING)/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, (CANVAS_WIDTH*SUPERSAMPLING)/4, (CANVAS_HEIGHT*SUPERSAMPLING)/4, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, CANVAS_WIDTH, CANVAS_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + checkGLError(); fbo = glGenFramebuffers(); int depth = glGenRenderbuffers(); + int color = glGenRenderbuffers(); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); glDrawBuffer(GL_COLOR_ATTACHMENT0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0); + glBindRenderbuffer(GL_RENDERBUFFER, depth); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, CANVAS_WIDTH*SUPERSAMPLING, CANVAS_HEIGHT*SUPERSAMPLING); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH_COMPONENT24, CANVAS_WIDTH, CANVAS_HEIGHT); + + glBindRenderbuffer(GL_RENDERBUFFER, color); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_RGBA8, CANVAS_WIDTH, CANVAS_HEIGHT); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color); + checkFramebufferStatus(); + + + fbo2 = glGenFramebuffers(); + + int depth2 = glGenRenderbuffers(); + int color2 = glGenRenderbuffers(); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo2); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + + glBindRenderbuffer(GL_RENDERBUFFER, depth2); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH_COMPONENT24, CANVAS_WIDTH, CANVAS_HEIGHT); + + glBindRenderbuffer(GL_RENDERBUFFER, color2); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_RGBA8, CANVAS_WIDTH, CANVAS_HEIGHT); + + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth2); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color2); + checkFramebufferStatus(); + + + skinFbo = glGenFramebuffers(); + + glBindFramebuffer(GL_FRAMEBUFFER, skinFbo); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, skinFboTex, 0); checkFramebufferStatus(); glBindFramebuffer(GL_FRAMEBUFFER, 0); + swapFbo = glGenFramebuffers(); + + glBindFramebuffer(GL_FRAMEBUFFER, swapFbo); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, swapFboTex, 0); + checkFramebufferStatus(); + + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + FloatBuffer vertexBuffer = BufferUtils.createFloatBuffer(vertices.length); vertexBuffer.put(vertices); vertexBuffer.flip(); @@ -324,6 +389,7 @@ public void run() { .put("X-Alex", ImageIO.read(ClassLoader.getSystemResource("alex.png"))) .put("X-Steve", ImageIO.read(ClassLoader.getSystemResource("steve.png"))) .put("X-Test", ImageIO.read(ClassLoader.getSystemResource("test_skin.png"))) + .put("X-Test-Legacy", ImageIO.read(ClassLoader.getSystemResource("test_legacy_skin.png"))) .put("Falkreon", ImageIO.read(URI.create("https://visage.surgeplay.com/skin/Falkreon").toURL())) .put("unascribed", ImageIO.read(URI.create("https://visage.surgeplay.com/skin/unascribed").toURL())) .put("Dinnerbone", ImageIO.read(URI.create("https://visage.surgeplay.com/skin/Dinnerbone").toURL())) @@ -346,6 +412,8 @@ public void run() { boolean[] showText = {true}; int[] skinIdx = {1}; int[] bgIdx = {1}; + boolean[] skinOnly = {false}; + boolean[] fbos = {true, true}; glfwSetKeyCallback(window, new GLFWKeyCallback() { @Override @@ -368,6 +436,12 @@ public void invoke(long window, int key, int scancode, int action, int mods) { renderers.clear(); } else if (key == GLFW_KEY_G) { bgIdx[0] = (bgIdx[0]+1)%bgs.length; + } else if (key == GLFW_KEY_N) { + skinOnly[0] = !skinOnly[0]; + } else if (key == GLFW_KEY_1) { + fbos[0] = !fbos[0]; + } else if (key == GLFW_KEY_2) { + fbos[1] = !fbos[1]; } } } @@ -386,7 +460,7 @@ public void invoke(long window, int key, int scancode, int action, int mods) { while (run) { glfwPollEvents(); - drawContinuous(skins.get(skinKeys[skinIdx[0]]), skinKeys[skinIdx[0]], bgs[bgIdx[0]], conf, pattern, fontBuffer, showText[0]); + drawContinuous(skins.get(skinKeys[skinIdx[0]]), skinKeys[skinIdx[0]], bgs[bgIdx[0]], conf, pattern, fontBuffer, showText[0], skinOnly[0], fbos[0], fbos[1]); glfwSwapBuffers(window); } } else { @@ -425,7 +499,7 @@ public void invoke(long window, int key, int scancode, int action, int mods) { } // TODO the debug interface should be moved to a separate class - private void drawContinuous(BufferedImage skin, String skinName, String bg, RenderConfiguration conf, ByteBuffer pattern, ByteBuffer fontBuf, boolean showText) throws Exception { + private void drawContinuous(BufferedImage skin, String skinName, String bg, RenderConfiguration conf, ByteBuffer pattern, ByteBuffer fontBuf, boolean showText, boolean skinOnly, boolean fbo1Enabled, boolean fbo2Enabled) throws Exception { glColor3f(1, 1, 1); int h = CANVAS_WIDTH; if (conf.isFull()) { @@ -451,12 +525,18 @@ private void drawContinuous(BufferedImage skin, String skinName, String bg, Rend glPolygonStipple(pattern); glEnable(GL_POLYGON_STIPPLE); glColor3f(fgTone, fgTone, fgTone); - glBegin(GL_QUADS); { - glVertex2f(0, conf.isFull() ? 0 : CANVAS_HEIGHT-CANVAS_WIDTH); - glVertex2f(CANVAS_WIDTH, conf.isFull() ? 0 : CANVAS_HEIGHT-CANVAS_WIDTH); - glVertex2f(CANVAS_WIDTH, CANVAS_HEIGHT); - glVertex2f(0, CANVAS_HEIGHT); - } glEnd(); + if (skinOnly) { + int x = (CANVAS_WIDTH-384)/2; + int y = (CANVAS_HEIGHT-384)/2; + drawQuad(x, y, x+384, y+384); + } else { + glBegin(GL_QUADS); { + glVertex2f(0, conf.isFull() ? 0 : CANVAS_HEIGHT-CANVAS_WIDTH); + glVertex2f(CANVAS_WIDTH, conf.isFull() ? 0 : CANVAS_HEIGHT-CANVAS_WIDTH); + glVertex2f(CANVAS_WIDTH, CANVAS_HEIGHT); + glVertex2f(0, CANVAS_HEIGHT); + } glEnd(); + } glDisable(GL_POLYGON_STIPPLE); } else if (bg.equals("Black")) { glClearColor(0, 0, 0, 1); @@ -469,12 +549,66 @@ private void drawContinuous(BufferedImage skin, String skinName, String bg, Rend glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } + if (isKeyPressed(GLFW_KEY_DELETE)) { + renderers.values().forEach(Renderer::destroy); + renderers.clear(); + } + glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glColor3f(1, 1, 1); glPushMatrix(); draw(conf, CANVAS_WIDTH, h, new GameProfile(new UUID(0L, 0L), "continuous_test"), skin, Collections.emptyMap()); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glDisable(GL_LIGHTING); + glColor3f(1, 1, 1); + glDisable(GL_ALPHA_TEST); + glDisable(GL_CULL_FACE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, CANVAS_WIDTH, 0, CANVAS_HEIGHT, -10, 10); + glViewport(0, 0, CANVAS_WIDTH, h); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glViewport(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); + + if (skinOnly) { + glBindTexture(GL_TEXTURE_2D, skinFboTex); + int x = (CANVAS_WIDTH-384)/2; + int y = (CANVAS_HEIGHT-384)/2; + drawQuad(x, y, x+384, y+384, 0, 1, 1, 0); + } else { + if (fbo1Enabled) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, swapFbo); + glBlitFramebuffer(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, GL_COLOR_BUFFER_BIT, GL_LINEAR); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBindTexture(GL_TEXTURE_2D, swapFboTex); + drawQuad(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); + } + + if (fbo2Enabled) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo2); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, swapFbo); + glBlitFramebuffer(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, GL_COLOR_BUFFER_BIT, GL_LINEAR); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBindTexture(GL_TEXTURE_2D, swapFboTex); + drawQuad(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); + } + } glPopMatrix(); glPushMatrix(); @@ -489,15 +623,23 @@ private void drawContinuous(BufferedImage skin, String skinName, String bg, Rend if (showText) { drawText(fontBuf, false, "backGround: "+bg, 5, color(true, isKeyPressed(GLFW_KEY_G))); drawText(fontBuf, false, "sKin: "+skinName, 15, color(true, isKeyPressed(GLFW_KEY_K))); - drawText(fontBuf, false, "Type: "+conf.getType(), 25, color(true, isKeyPressed(GLFW_KEY_T))); - drawText(fontBuf, true, "Slim ", 5, color(conf.isSlim(), isKeyPressed(GLFW_KEY_S))); - - drawText(fontBuf, true, "fliP ", 5, color(conf.isFlipped(), isKeyPressed(GLFW_KEY_P))); - - drawText(fontBuf, true, "Full", 5, color(conf.isFull(), isKeyPressed(GLFW_KEY_F))); + if (!skinOnly) { + drawText(fontBuf, false, "Type: "+conf.getType(), 25, color(true, isKeyPressed(GLFW_KEY_T))); + drawText(fontBuf, true, "Slim ", 5, color(conf.isSlim(), isKeyPressed(GLFW_KEY_S))); + + drawText(fontBuf, true, "fliP ", 5, color(conf.isFlipped(), isKeyPressed(GLFW_KEY_P))); + + drawText(fontBuf, true, "Full", 5, color(conf.isFull(), isKeyPressed(GLFW_KEY_F))); + drawText(fontBuf, true, "skiN only", 15, color(skinOnly, isKeyPressed(GLFW_KEY_N))); + drawText(fontBuf, true, "1 ", 25, color(fbo1Enabled, isKeyPressed(GLFW_KEY_1))); + drawText(fontBuf, true, "2", 25, color(fbo2Enabled, isKeyPressed(GLFW_KEY_2))); + + drawText(fontBuf, false, "DELETE to clear cache", (CANVAS_HEIGHT/2)-15, color(true, isKeyPressed(GLFW_KEY_DELETE))); + } else { + drawText(fontBuf, true, "skiN only", 5, color(skinOnly, isKeyPressed(GLFW_KEY_N))); + } - drawText(fontBuf, false, "DELETE to clear cache", (CANVAS_HEIGHT/2)-15, color(true, isKeyPressed(GLFW_KEY_DELETE))); drawText(fontBuf, true, "SPACE to hide text", (CANVAS_HEIGHT/2)-15, color(true, isKeyPressed(GLFW_KEY_SPACE))); } @@ -611,6 +753,7 @@ private void processDelivery(Delivery delivery) throws Exception { RenderConfiguration conf = new RenderConfiguration(Type.fromMode(mode), Profiles.isSlim(profile), mode.isTall(), Profiles.isFlipped(profile)); + glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); byte[] pngBys = draw(conf, width, height, profile, skin, params); if (Visage.trace) Visage.log.finest("Got png bytes"); @@ -634,16 +777,6 @@ private byte[] buildResponse(int type, byte[] payload) throws IOException { public byte[] draw(RenderConfiguration conf, int width, int height, GameProfile profile, BufferedImage skin, Map params) throws Exception { //BufferedImage cape; BufferedImage out; - if (skin.getHeight() == 32) { - if (Visage.debug) Visage.log.finer("Skin is legacy; painting onto new-style canvas"); - BufferedImage canvas = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB); - Graphics2D g = canvas.createGraphics(); - g.drawImage(skin, 0, 0, null); - g.drawImage(flipLimb(skin.getSubimage(0, 16, 16, 16)), 16, 48, null); - g.drawImage(flipLimb(skin.getSubimage(40, 16, 16, 16)), 32, 48, null); - g.dispose(); - skin = canvas; - } int color = skin.getRGB(32, 8); boolean equal = true; for (int x = 32; x < 64; x++) { @@ -668,53 +801,89 @@ public byte[] draw(RenderConfiguration conf, int width, int height, GameProfile Renderer renderer = renderers.get(conf); try { if (Visage.trace) Visage.log.finest("Uploading"); - renderer.setSkin(skin); + Textures.upload(skin, GL_RGBA8, skinTexture); if (Visage.trace) Visage.log.finest("Rendering"); - glUseProgram(0); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glBindFramebuffer(GL_FRAMEBUFFER, skinFbo); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - renderer.render(width*SUPERSAMPLING, height*SUPERSAMPLING); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glViewport(0, 0, 64*SKIN_SUPERSAMPLING, 64*SKIN_SUPERSAMPLING); + glOrtho(0, 64, 0, 64, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); glColor3f(1, 1, 1); glDisable(GL_ALPHA_TEST); glDisable(GL_CULL_FACE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBindTexture(GL_TEXTURE_2D, fboTex); - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(-1, 1, -1, 1, -10, 10); - glViewport(0, 0, width, height); + glBindTexture(GL_TEXTURE_2D, skinUnderlayTexture); + drawQuad(0, 0, 64, 64); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); + glBindTexture(GL_TEXTURE_2D, skinTexture); + if (skin.getHeight() == 32) { + drawQuad(0, 0, 64, 32); + drawFlippedLimb(16, 48, 0, 16); + drawFlippedLimb(32, 48, 40, 16); + } else { + drawQuad(0, 0, 64, 64); + } - glViewport(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); - float s = 1f; - glBegin(GL_QUADS); { - glTexCoord2f(0, 0); - glVertex2f(-s, -s); - glTexCoord2f(1, 0); - glVertex2f(s, -s); - glTexCoord2f(1, 1); - glVertex2f(s, s); - glTexCoord2f(0, 1); - glVertex2f(-s, s); - } glEnd(); - glUseProgram(0); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + renderPass = 1; + renderer.render(width, height); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo2); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo2); + glBlitFramebuffer(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, GL_DEPTH_BUFFER_BIT, GL_NEAREST); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo2); + + renderPass = 2; + renderer.render(width, height); + + if (!parent.config.getBoolean("continuous")) { if (Visage.trace) Visage.log.finest("Rendered - reading pixels"); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, swapFbo); + glBlitFramebuffer(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, GL_COLOR_BUFFER_BIT, GL_LINEAR); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBindTexture(GL_TEXTURE_2D, swapFboTex); + drawQuad(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo2); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, swapFbo); + glBlitFramebuffer(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, GL_COLOR_BUFFER_BIT, GL_LINEAR); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBindTexture(GL_TEXTURE_2D, swapFboTex); + drawQuad(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); + out = renderer.readPixels(width, height); } else { out = null; @@ -749,35 +918,40 @@ public byte[] draw(RenderConfiguration conf, int width, int height, GameProfile } } - private BufferedImage flipLimb(BufferedImage in) { - BufferedImage out = new BufferedImage(in.getWidth(), in.getHeight(), BufferedImage.TYPE_INT_ARGB); - - BufferedImage front = flipHorziontally(in.getSubimage(4, 4, 4, 12)); - BufferedImage back = flipHorziontally(in.getSubimage(12, 4, 4, 12)); + private void drawFlippedLimb(int x, int y, int u, int v) { + drawFlippedSkinQuad(x+4, y+4, u+4, v+4, 4, 12); + drawFlippedSkinQuad(x+12, y+4, u+12, v+4, 4, 12); - BufferedImage top = flipHorziontally(in.getSubimage(4, 0, 4, 4)); - BufferedImage bottom = flipHorziontally(in.getSubimage(8, 0, 4, 4)); + drawFlippedSkinQuad(x+4, y+0, u+4, v+0, 4, 4); + drawFlippedSkinQuad(x+8, y+0, u+8, v+0, 4, 4); - BufferedImage left = in.getSubimage(8, 4, 4, 12); - BufferedImage right = in.getSubimage(0, 4, 4, 12); - - Graphics2D g = out.createGraphics(); - g.drawImage(front, 4, 4, null); - g.drawImage(back, 12, 4, null); - g.drawImage(top, 4, 0, null); - g.drawImage(bottom, 8, 0, null); - g.drawImage(left, 0, 4, null); // left goes to right - g.drawImage(right, 8, 4, null); // right goes to left - g.dispose(); - return out; + drawSkinQuad(x+0, y+4, u+8, v+4, 4, 12); + drawSkinQuad(x+8, y+4, u+0, v+4, 4, 12); + } + + private void drawFlippedSkinQuad(int x, int y, int u, int v, int w, int h) { + drawQuad(x, y, x+w, y+h, (u+w)/64f, (v)/32f, (u)/64f, (v+h)/32f); + } + + private void drawSkinQuad(int x, int y, int u, int v, int w, int h) { + drawQuad(x, y, x+w, y+h, (u)/64f, (v)/32f, (u+w)/64f, (v+h)/32f); + } + + private void drawQuad(float x1, float y1, float x2, float y2, float u1, float v1, float u2, float v2) { + glBegin(GL_QUADS); { + glTexCoord2f(u1, v1); + glVertex2f(x1, y1); + glTexCoord2f(u2, v1); + glVertex2f(x2, y1); + glTexCoord2f(u2, v2); + glVertex2f(x2, y2); + glTexCoord2f(u1, v2); + glVertex2f(x1, y2); + } glEnd(); } - private BufferedImage flipHorziontally(BufferedImage in) { - BufferedImage out = new BufferedImage(in.getWidth(), in.getHeight(), BufferedImage.TYPE_INT_ARGB); - Graphics2D g = out.createGraphics(); - g.drawImage(in, 0, 0, in.getWidth(), in.getHeight(), in.getWidth(), 0, 0, in.getHeight(), null); - g.dispose(); - return out; + private void drawQuad(float x1, float y1, float x2, float y2) { + drawQuad(x1, y1, x2, y2, 0, 0, 1, 1); } public void finish() { diff --git a/src/main/java/com/surgeplay/visage/renderer/render/BodyRenderer.java b/src/main/java/com/surgeplay/visage/renderer/render/BodyRenderer.java index 09db968..122e64a 100644 --- a/src/main/java/com/surgeplay/visage/renderer/render/BodyRenderer.java +++ b/src/main/java/com/surgeplay/visage/renderer/render/BodyRenderer.java @@ -27,7 +27,7 @@ import com.surgeplay.visage.renderer.RenderContext; import com.surgeplay.visage.renderer.render.primitive.Cube; import com.surgeplay.visage.renderer.render.primitive.Plane; -import com.surgeplay.visage.renderer.render.primitive.Stage; +import com.surgeplay.visage.renderer.render.primitive.Group; public class BodyRenderer extends Renderer { @@ -38,15 +38,15 @@ public BodyRenderer(RenderContext owner) { @Override protected void initPrimitives(boolean slim, boolean full, boolean flip) { float tilt = -10; - float angle = flip ? -20 : 20; + float angle = 20; - Stage stage = new Stage(); - stage.x = 0; - stage.y = full ? (flip ? -2.7f : -2.8f) : -1f; - stage.z = full ? -10.35f : -6f; - stage.rotX = tilt; - stage.rotY = angle; - addPrimitive(stage); + Group group = new Group(); + group.x = 0; + group.y = full ? (flip ? -2.7f : -2.8f) : -1f; + group.z = full ? -10.35f : -6f; + group.rotX = tilt; + group.rotY = angle; + addPrimitive(group); if (full || flip) { Plane shadow = new Plane(); @@ -56,129 +56,160 @@ protected void initPrimitives(boolean slim, boolean full, boolean flip) { shadow.texture = TextureType.ALL; shadow.lit = false; shadow.alphaMode = AlphaMode.FULL; - stage.members.add(shadow); + group.members.add(shadow); } - Stage stage2 = new Stage(); + Group group2 = new Group(); if (flip) { - stage2.rotZ = 180; - stage2.y = ((-stage.y)*2)+(full ? 0.3f : -0.25f); + group2.rotZ = 180; + group2.y = ((-group.y)*2)+(full ? 0.3f : -0.25f); } - stage.members.add(stage2); + group.members.add(group2); + + Cube head = new Cube(); + head.texture = TextureType.HEAD; + head.alphaMode = AlphaMode.NONE; + + Cube head2 = new Cube(); + head2.scaleX = head2.scaleY = head2.scaleZ = 1.05f; + head2.texture = TextureType.HEAD2; + head2.alphaMode = AlphaMode.FULL; + head2.depthMask = false; + head2.renderPass = 2; + + + + Cube body = new Cube(); + body.y = 2.5f; + body.scaleY = 1.5f; + body.scaleZ = 0.5f; + body.texture = TextureType.BODY; + body.alphaMode = AlphaMode.NONE; + + Cube body2 = new Cube(); + body2.y = 2.5f; + body2.scaleY = 1.55f; + body2.scaleZ = 0.55f; + body2.scaleX = 1.05f; + body2.texture = TextureType.BODY2; + body2.alphaMode = AlphaMode.FULL; + body2.depthMask = false; + body2.renderPass = 2; + + Cube larm = new Cube(); - larm.x = slim ? 1.625f : 1.75f; - larm.y = 2.375f; - larm.z = -0.1f; + larm.x = slim ? 1.375f : 1.5f; + larm.y = 2.5f; larm.scaleY = 1.5f; larm.scaleZ = 0.5f; larm.scaleX = slim ? 0.375f : 0.5f; + larm.anchorX = -larm.scaleX; + larm.anchorY = -larm.scaleY; larm.rotZ = -10f; larm.texture = slim ? TextureType.LARM_SLIM : TextureType.LARM; larm.alphaMode = AlphaMode.NONE; - stage2.members.add(larm); + Cube larm2 = new Cube(); - larm2.x = slim ? 1.575f : 1.7f; - larm2.y = 2.35f; - larm2.z = -0.1f; + larm2.x = slim ? 1.375f : 1.5f; + larm2.y = 2.5f; larm2.scaleY = 1.55f; - larm2.scaleZ = 0.54f; + larm2.scaleZ = 0.55f; larm2.scaleX = slim ? 0.425f : 0.55f; + larm2.anchorX = -larm2.scaleX; + larm2.anchorY = -larm2.scaleY; larm2.rotZ = -10f; larm2.texture = slim ? TextureType.LARM2_SLIM : TextureType.LARM2; - larm2.alphaMode = AlphaMode.MASK; - stage2.members.add(larm2); + larm2.alphaMode = AlphaMode.FULL; + larm2.depthMask = false; + larm2.renderPass = 2; + + + Cube rarm = new Cube(); + rarm.x = slim ? -1.375f : -1.5f; + rarm.y = 2.5f; + rarm.scaleY = 1.5f; + rarm.scaleZ = 0.5f; + rarm.scaleX = slim ? 0.375f : 0.5f; + rarm.anchorX = rarm.scaleX; + rarm.anchorY = -rarm.scaleY; + rarm.rotZ = 10f; + rarm.texture = slim ? TextureType.RARM_SLIM : TextureType.RARM; + rarm.alphaMode = AlphaMode.NONE; + + Cube rarm2 = new Cube(); + rarm2.x = slim ? -1.375f : -1.5f; + rarm2.y = 2.5f; + rarm2.scaleY = 1.55f; + rarm2.scaleZ = 0.55f; + rarm2.scaleX = slim ? 0.425f : 0.55f; + rarm2.anchorX = rarm2.scaleX; + rarm2.anchorY = -rarm2.scaleY; + rarm2.rotZ = 10f; + rarm2.texture = slim ? TextureType.RARM2_SLIM : TextureType.RARM2; + rarm2.alphaMode = AlphaMode.FULL; + rarm2.depthMask = false; + rarm2.renderPass = 2; + Cube lleg = new Cube(); lleg.x = 0.5f; - lleg.y = 5.475f; + lleg.y = 5.5f; lleg.scaleY = 1.5f; lleg.scaleZ = 0.5f; lleg.scaleX = 0.5f; + lleg.anchorY = -lleg.scaleY; lleg.texture = TextureType.LLEG; lleg.alphaMode = AlphaMode.NONE; - stage2.members.add(lleg); + + Cube lleg2 = new Cube(); + lleg2.x = 0.5f; + lleg2.y = 5.5f; + lleg2.scaleY = 1.55f; + lleg2.scaleZ = 0.55f; + lleg2.scaleX = 0.55f; + lleg2.anchorY = -lleg2.scaleY; + lleg2.texture = TextureType.LLEG2; + lleg2.alphaMode = AlphaMode.FULL; + lleg2.depthMask = false; + lleg2.renderPass = 2; + Cube rleg = new Cube(); rleg.x = -0.5f; - rleg.y = 5.475f; + rleg.y = 5.5f; rleg.scaleY = 1.5f; rleg.scaleZ = 0.5f; rleg.scaleX = 0.5f; + rleg.anchorY = -rleg.scaleY; rleg.texture = TextureType.RLEG; rleg.alphaMode = AlphaMode.NONE; - stage2.members.add(rleg); - - Cube body = new Cube(); - body.y = 2.475f; - body.scaleY = 1.5f; - body.scaleZ = 0.5f; - body.texture = TextureType.BODY; - body.alphaMode = AlphaMode.NONE; - stage2.members.add(body); - Cube body2 = new Cube(); - body2.y = 2.5f; - body2.scaleY = 1.55f; - body2.scaleZ = 0.55f; - body2.scaleX = 1.05f; - body2.texture = TextureType.BODY2; - body2.alphaMode = AlphaMode.MASK; - stage2.members.add(body2); - - Cube lleg2 = new Cube(); - lleg2.x = 0.475f; - lleg2.y = 5.4f; - lleg2.scaleY = 1.55f; - lleg2.scaleZ = 0.55f; - lleg2.scaleX = 0.55f; - lleg2.texture = TextureType.LLEG2; - lleg2.alphaMode = AlphaMode.MASK; - stage2.members.add(lleg2); Cube rleg2 = new Cube(); - rleg2.x = -0.525f; - rleg2.y = 5.4f; + rleg2.x = -0.5f; + rleg2.y = 5.5f; rleg2.scaleY = 1.55f; rleg2.scaleZ = 0.55f; rleg2.scaleX = 0.55f; + rleg2.anchorY = -rleg2.scaleY; rleg2.texture = TextureType.RLEG2; - rleg2.alphaMode = AlphaMode.MASK; - stage2.members.add(rleg2); + rleg2.alphaMode = AlphaMode.FULL; + rleg2.depthMask = false; + rleg2.renderPass = 2; - Cube head = new Cube(); - head.y = -0.025f; - head.z = -0.025f; - head.texture = TextureType.HEAD; - head.alphaMode = AlphaMode.NONE; - stage2.members.add(head); - Cube helm = new Cube(); - helm.scaleX = helm.scaleY = helm.scaleZ = 1.05f; - helm.texture = TextureType.HEAD2; - helm.alphaMode = AlphaMode.MASK; - stage2.members.add(helm); + group2.members.add(head); + group2.members.add(body); + group2.members.add(larm); + group2.members.add(rarm); + group2.members.add(lleg); + group2.members.add(rleg); - Cube rarm = new Cube(); - rarm.x = slim ? -1.625f : -1.75f; - rarm.y = 2.325f; - rarm.z = 0.15f; - rarm.scaleY = 1.5f; - rarm.scaleZ = 0.5f; - rarm.scaleX = slim ? 0.375f : 0.5f; - rarm.rotZ = 10f; - rarm.texture = slim ? TextureType.RARM_SLIM : TextureType.RARM; - rarm.alphaMode = AlphaMode.NONE; - stage2.members.add(rarm); - Cube rarm2 = new Cube(); - rarm2.x = slim ? -1.625f : -1.7f; - rarm2.y = 2.3f; - rarm2.z = 0.15f; - rarm2.scaleY = 1.55f; - rarm2.scaleZ = 0.55f; - rarm2.scaleX = slim ? 0.375f : 0.55f; - rarm2.rotZ = 10f; - rarm2.texture = slim ? TextureType.RARM2_SLIM : TextureType.RARM2; - rarm2.alphaMode = AlphaMode.MASK; - stage2.members.add(rarm2); + group2.members.add(lleg2); + group2.members.add(rleg2); + group2.members.add(body2); + group2.members.add(head2); + group2.members.add(larm2); + group2.members.add(rarm2); } } diff --git a/src/main/java/com/surgeplay/visage/renderer/render/FaceRenderer.java b/src/main/java/com/surgeplay/visage/renderer/render/FaceRenderer.java index 62a1a9e..2d690c9 100644 --- a/src/main/java/com/surgeplay/visage/renderer/render/FaceRenderer.java +++ b/src/main/java/com/surgeplay/visage/renderer/render/FaceRenderer.java @@ -26,7 +26,7 @@ import com.surgeplay.visage.renderer.RenderContext; import com.surgeplay.visage.renderer.render.primitive.Plane; -import com.surgeplay.visage.renderer.render.primitive.Stage; +import com.surgeplay.visage.renderer.render.primitive.Group; public class FaceRenderer extends Renderer { @@ -36,7 +36,7 @@ public FaceRenderer(RenderContext owner) { @Override protected void initPrimitives(boolean slim, boolean full, boolean flip) { - Stage stage = new Stage(); + Group stage = new Group(); stage.y = 0; stage.z = -2.5f; stage.rotZ = 0; @@ -53,9 +53,9 @@ protected void initPrimitives(boolean slim, boolean full, boolean flip) { stage.members.add(head); Plane helm = new Plane(); helm.scaleX = helm.scaleY = helm.scaleZ = 1.05f; - helm.z = -0.0001f; helm.texture = TextureType.HEAD2_FRONT; - helm.alphaMode = AlphaMode.MASK; + helm.alphaMode = AlphaMode.FULL; + helm.depthMask = false; stage.members.add(helm); } diff --git a/src/main/java/com/surgeplay/visage/renderer/render/FlatBodyRenderer.java b/src/main/java/com/surgeplay/visage/renderer/render/FlatBodyRenderer.java index 5b8ab49..9881b3b 100644 --- a/src/main/java/com/surgeplay/visage/renderer/render/FlatBodyRenderer.java +++ b/src/main/java/com/surgeplay/visage/renderer/render/FlatBodyRenderer.java @@ -26,7 +26,7 @@ import com.surgeplay.visage.renderer.RenderContext; import com.surgeplay.visage.renderer.render.primitive.Plane; -import com.surgeplay.visage.renderer.render.primitive.Stage; +import com.surgeplay.visage.renderer.render.primitive.Group; public class FlatBodyRenderer extends Renderer { @@ -36,7 +36,7 @@ public FlatBodyRenderer(RenderContext owner) { @Override protected void initPrimitives(boolean slim, boolean full, boolean flip) { - Stage stage = new Stage(); + Group stage = new Group(); if (full) { stage.y = flip ? 1.5f : -1.5f; stage.z = -9.75f; @@ -107,7 +107,8 @@ protected void initPrimitives(boolean slim, boolean full, boolean flip) { helm.scaleX = helm.scaleY = helm.scaleZ = 1.05f; helm.z = -1.5001f; helm.texture = TextureType.HEAD2_FRONT; - helm.alphaMode = AlphaMode.MASK; + helm.alphaMode = AlphaMode.FULL; + helm.depthMask = false; stage.members.add(helm); Plane body2 = new Plane(); @@ -115,7 +116,8 @@ protected void initPrimitives(boolean slim, boolean full, boolean flip) { body2.scaleZ = 1.55f; body2.z = 0.9999f; body2.texture = TextureType.BODY2_FRONT; - body2.alphaMode = AlphaMode.MASK; + body2.alphaMode = AlphaMode.FULL; + body2.depthMask = false; stage.members.add(body2); Plane rarm2 = new Plane(); @@ -124,7 +126,8 @@ protected void initPrimitives(boolean slim, boolean full, boolean flip) { rarm2.z = 0.9999f; rarm2.x = slim ? -1.375f : -1.5f; rarm2.texture = slim ? TextureType.RARM2_SLIM_FRONT : TextureType.RARM2_FRONT; - rarm2.alphaMode = AlphaMode.MASK; + rarm2.alphaMode = AlphaMode.FULL; + rarm2.depthMask = false; stage.members.add(rarm2); Plane larm2 = new Plane(); @@ -133,7 +136,8 @@ protected void initPrimitives(boolean slim, boolean full, boolean flip) { larm2.z = 0.9999f; larm2.x = slim ? 1.375f : 1.5f; larm2.texture = slim ? TextureType.LARM2_SLIM_FRONT : TextureType.LARM2_FRONT; - larm2.alphaMode = AlphaMode.MASK; + larm2.alphaMode = AlphaMode.FULL; + larm2.depthMask = false; stage.members.add(larm2); Plane lleg2 = new Plane(); @@ -142,7 +146,8 @@ protected void initPrimitives(boolean slim, boolean full, boolean flip) { lleg2.scaleZ = 1.55f; lleg2.scaleX = 0.55f; lleg2.texture = TextureType.LLEG2_FRONT; - lleg2.alphaMode = AlphaMode.MASK; + lleg2.alphaMode = AlphaMode.FULL; + lleg2.depthMask = false; stage.members.add(lleg2); Plane rleg2 = new Plane(); @@ -151,7 +156,8 @@ protected void initPrimitives(boolean slim, boolean full, boolean flip) { rleg2.scaleZ = 1.55f; rleg2.scaleX = 0.55f; rleg2.texture = TextureType.RLEG2_FRONT; - rleg2.alphaMode = AlphaMode.MASK; + rleg2.alphaMode = AlphaMode.FULL; + rleg2.depthMask = false; stage.members.add(rleg2); } diff --git a/src/main/java/com/surgeplay/visage/renderer/render/HeadRenderer.java b/src/main/java/com/surgeplay/visage/renderer/render/HeadRenderer.java index 8cc361c..bf8f635 100644 --- a/src/main/java/com/surgeplay/visage/renderer/render/HeadRenderer.java +++ b/src/main/java/com/surgeplay/visage/renderer/render/HeadRenderer.java @@ -27,7 +27,7 @@ import com.surgeplay.visage.renderer.RenderContext; import com.surgeplay.visage.renderer.render.primitive.Cube; import com.surgeplay.visage.renderer.render.primitive.Plane; -import com.surgeplay.visage.renderer.render.primitive.Stage; +import com.surgeplay.visage.renderer.render.primitive.Group; public class HeadRenderer extends Renderer { @@ -41,7 +41,7 @@ protected void initPrimitives(boolean slim, boolean full, boolean flip) { float tilt = -20; float angle = -35; - Stage stage = new Stage(); + Group stage = new Group(); stage.y = -0.25f; stage.z = -5f; stage.rotX = tilt; @@ -65,12 +65,12 @@ protected void initPrimitives(boolean slim, boolean full, boolean flip) { stage.members.add(head); Cube helm = new Cube(); helm.scaleX = helm.scaleY = helm.scaleZ = 1.05f; - helm.z = -0f; if (flip) { helm.rotZ = 180f; } helm.texture = TextureType.HEAD2; - helm.alphaMode = AlphaMode.MASK; + helm.alphaMode = AlphaMode.FULL; + helm.depthMask = false; stage.members.add(helm); } } diff --git a/src/main/java/com/surgeplay/visage/renderer/render/Renderer.java b/src/main/java/com/surgeplay/visage/renderer/render/Renderer.java index 2c6772f..d6fee42 100644 --- a/src/main/java/com/surgeplay/visage/renderer/render/Renderer.java +++ b/src/main/java/com/surgeplay/visage/renderer/render/Renderer.java @@ -35,7 +35,6 @@ import com.surgeplay.visage.Visage; import com.surgeplay.visage.renderer.RenderContext; import com.surgeplay.visage.renderer.render.primitive.Primitive; -import com.surgeplay.visage.renderer.util.Textures; import static com.surgeplay.visage.renderer.util.Errors.checkGLError; import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.opengl.GL12.*; @@ -56,13 +55,6 @@ protected void addPrimitive(Primitive prim) { prims.add(prim); } - public void setSkin(BufferedImage img) { - Textures.upload(img, GL_RGBA8, owner.texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - checkGLError(); - } - protected void preRender(int width, int height) {} protected void postRender(int width, int height) {} @@ -133,6 +125,7 @@ public BufferedImage readPixels(int width, int height) { glReadBuffer(GL_FRONT); ByteBuffer buf = BufferUtils.createByteBuffer(width * height * 4); glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, buf); + checkGLError(); BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); int[] pixels = new int[width*height]; buf.asIntBuffer().get(pixels); diff --git a/src/main/java/com/surgeplay/visage/renderer/render/TextureType.java b/src/main/java/com/surgeplay/visage/renderer/render/TextureType.java index 6c0f95c..3668e27 100644 --- a/src/main/java/com/surgeplay/visage/renderer/render/TextureType.java +++ b/src/main/java/com/surgeplay/visage/renderer/render/TextureType.java @@ -207,7 +207,7 @@ public enum TextureType { // Bottom (Gray) 40, 48, 4, 4, // Left (Yellow) - 48, 52, 4, 12, + 40, 52, 4, 12, // Right (Green) 32, 52, 4, 12 ), @@ -221,7 +221,7 @@ public enum TextureType { // Bottom (Gray) 40, 48, 3, 4, // Left (Yellow) - 48, 52, 4, 12, + 40, 52, 4, 12, // Right (Green) 32, 52, 4, 12 ), @@ -235,7 +235,7 @@ public enum TextureType { // Bottom (Gray) 56, 48, 4, 4, // Left (Yellow) - 64, 52, 4, 12, + 58, 52, 4, 12, // Right (Green) 48, 52, 4, 12 ), @@ -249,7 +249,7 @@ public enum TextureType { // Bottom (Gray) 56, 48, 3, 4, // Left (Yellow) - 64, 52, 4, 12, + 56, 52, 4, 12, // Right (Green) 48, 52, 4, 12 ), @@ -328,17 +328,17 @@ private TextureType(int... assorted) { // slightly shrink the box to prevent texture bleeding - u[idx ] = div(tex_w, x)+0.0001f; - v[idx ] = div(tex_h, edgeY)-0.0001f; + u[idx ] = div(tex_w, x)+0.001f; + v[idx ] = div(tex_h, edgeY)-0.001f; - u[idx+1] = div(tex_w, edgeX)-0.0001f; - v[idx+1] = div(tex_h, edgeY)-0.0001f; + u[idx+1] = div(tex_w, edgeX)-0.001f; + v[idx+1] = div(tex_h, edgeY)-0.001f; - u[idx+2] = div(tex_w, edgeX)-0.0001f; - v[idx+2] = div(tex_h, y)+0.0001f; + u[idx+2] = div(tex_w, edgeX)-0.001f; + v[idx+2] = div(tex_h, y)+0.001f; - u[idx+3] = div(tex_w, x)+0.0001f; - v[idx+3] = div(tex_h, y)+0.0001f; + u[idx+3] = div(tex_w, x)+0.001f; + v[idx+3] = div(tex_h, y)+0.001f; } } diff --git a/src/main/java/com/surgeplay/visage/renderer/render/primitive/Stage.java b/src/main/java/com/surgeplay/visage/renderer/render/primitive/Group.java similarity index 98% rename from src/main/java/com/surgeplay/visage/renderer/render/primitive/Stage.java rename to src/main/java/com/surgeplay/visage/renderer/render/primitive/Group.java index e949c3a..55eeaec 100644 --- a/src/main/java/com/surgeplay/visage/renderer/render/primitive/Stage.java +++ b/src/main/java/com/surgeplay/visage/renderer/render/primitive/Group.java @@ -32,7 +32,7 @@ import com.surgeplay.visage.Visage; import com.surgeplay.visage.renderer.render.Renderer; -public class Stage extends Primitive { +public class Group extends Primitive { public final List members = Lists.newArrayList(); @Override public void render(Renderer renderer) { diff --git a/src/main/java/com/surgeplay/visage/renderer/render/primitive/Primitive.java b/src/main/java/com/surgeplay/visage/renderer/render/primitive/Primitive.java index b5d4542..5eb6640 100644 --- a/src/main/java/com/surgeplay/visage/renderer/render/primitive/Primitive.java +++ b/src/main/java/com/surgeplay/visage/renderer/render/primitive/Primitive.java @@ -38,6 +38,7 @@ public abstract class Primitive { public float scaleY = 1.0f; public float scaleZ = 1.0f; public float x, y, z, rotX, rotY, rotZ; + public float anchorX, anchorY, anchorZ; public boolean lit = true; public boolean textured = true; @@ -46,17 +47,25 @@ public abstract class Primitive { public AlphaMode alphaMode = AlphaMode.FULL; protected boolean inStage = true; + public boolean depthMask = true; + + public int renderPass = 1; + public abstract void render(Renderer renderer); protected void doRender(Renderer renderer, int vbo, int tcbo, float[] vertices) { + if (renderer.owner.renderPass != renderPass) return; glPushMatrix(); + glDepthMask(depthMask); if (Visage.trace) Visage.log.finest("Rendering "+getClass().getSimpleName()); if (Visage.trace) Visage.log.finest("Translating to "+x+", "+y+", "+z); glTranslatef(x, y, z); - if (Visage.trace) Visage.log.finest("Rotating by "+rotX+"°, "+rotY+"°, "+rotZ+"°"); - glRotatef(rotX, 1.0f, 0.0f, 0.0f); - glRotatef(rotY, 0.0f, 1.0f, 0.0f); - glRotatef(rotZ, 0.0f, 0.0f, 1.0f); + if (Visage.trace) Visage.log.finest("Rotating by "+rotX+"°, "+rotY+"°, "+rotZ+"°, anchored at "+anchorX+", "+anchorY+", "+anchorZ); + glTranslatef(anchorX, anchorY, anchorZ); + glRotatef(rotX, 1, 0, 0); + glRotatef(rotY, 0, 1, 0); + glRotatef(rotZ, 0, 0, 1); + glTranslatef(-anchorX, -anchorY, -anchorZ); if (Visage.trace) Visage.log.finest("Scaling by "+scaleX+"x, "+scaleY+"x, "+scaleZ+"x"); glScalef(scaleX, scaleY*-1, scaleZ); @@ -70,7 +79,11 @@ protected void doRender(Renderer renderer, int vbo, int tcbo, float[] vertices) if (textured) { if (Visage.trace) Visage.log.finest("Enabling texturing - texture "+texture); glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, texture == TextureType.ALL ? renderer.owner.shadowTexture : renderer.owner.texture); + if (texture == TextureType.ALL) { + glBindTexture(GL_TEXTURE_2D, renderer.owner.shadowTexture); + } else { + glBindTexture(GL_TEXTURE_2D, renderer.owner.skinFboTex); + } } else { if (Visage.trace) Visage.log.finest("Disabling texturing"); glDisable(GL_TEXTURE_2D); @@ -90,7 +103,7 @@ protected void doRender(Renderer renderer, int vbo, int tcbo, float[] vertices) glBlendFunc(GL_ONE, GL_ZERO); break; case NONE: - if (Visage.trace) Visage.log.finest("No alpha - Enabling ONE/ZERO blend and alpha test"); + if (Visage.trace) Visage.log.finest("No alpha - Enabling ONE/ZERO blend, disabling alpha test"); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ZERO); glDisable(GL_ALPHA_TEST); @@ -140,6 +153,7 @@ protected void doRender(Renderer renderer, int vbo, int tcbo, float[] vertices) glVertex3f(x, y, z); } glEnd();*/ + glDepthMask(true); glPopMatrix(); } } diff --git a/src/main/resources/skin_underlay.png b/src/main/resources/skin_underlay.png new file mode 100644 index 0000000..fb734e0 Binary files /dev/null and b/src/main/resources/skin_underlay.png differ diff --git a/src/main/resources/test_legacy_skin.png b/src/main/resources/test_legacy_skin.png new file mode 100644 index 0000000..ba80c59 Binary files /dev/null and b/src/main/resources/test_legacy_skin.png differ