package it.cavallium.warppi.gui.graphicengine.impl.jogl; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.FloatBuffer; import java.nio.file.Files; import javax.imageio.ImageIO; import com.jogamp.common.nio.Buffers; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES1; import com.jogamp.opengl.GLException; import com.jogamp.opengl.util.texture.Texture; import com.jogamp.opengl.util.texture.TextureData; import com.jogamp.opengl.util.texture.TextureIO; import it.cavallium.warppi.Engine; import it.cavallium.warppi.gui.graphicengine.BinaryFont; import it.cavallium.warppi.gui.graphicengine.Renderer; public class JOGLRenderer implements Renderer { public static GL2ES1 gl; private static final int ELEMENTS_MAX_COUNT_PER_BUFFER = 128; private static final int ELEMENT_VERTICES_COUNT = 6; private static final int vertSize = 3; private static final int texSize = 2; private static final int colSize = 4; private static final int vertBuffer = 0; private static final int texBuffer = 1; private static final int colBuffer = 2; private static final int vertMax = JOGLRenderer.vertSize * JOGLRenderer.ELEMENT_VERTICES_COUNT * JOGLRenderer.ELEMENTS_MAX_COUNT_PER_BUFFER; private static final int texMax = JOGLRenderer.texSize * JOGLRenderer.ELEMENT_VERTICES_COUNT * JOGLRenderer.ELEMENTS_MAX_COUNT_PER_BUFFER; private static final int colMax = JOGLRenderer.colSize * JOGLRenderer.ELEMENT_VERTICES_COUNT * JOGLRenderer.ELEMENTS_MAX_COUNT_PER_BUFFER; private int[] handlers; FloatBuffer fbVertices; FloatBuffer fbTextures; FloatBuffer fbColors; int fbElements; float[] currentColor = new float[24]; float[] currentClearColorARGBf = new float[] { 1f, 197f / 255f, 194f / 255f, 175f / 255f }; boolean currentTexEnabled; Texture currentTex; float currentTexWidth; float currentTexHeight; JOGLFont currentFont; @Override public void glColor3i(final int r, final int gg, final int b) { final float red = r / 255f; final float gre = gg / 255f; final float blu = b / 255f; //currentColor = new float[] { red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, }; currentColor = new float[] { red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, }; //OK } @Override public void glColor3f(final float red, final float gre, final float blu) { // currentColor = new float[] { red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, }; currentColor = new float[] { red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, };//OK } @Override public void glColor4f(final float red, final float gre, final float blu, final float alp) { // currentColor = new float[] { red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, }; currentColor = new float[] { red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, };//ok } @Override public void glColor(final int rgb) { final int alpha = rgb >> 24 & 0xFF; final int red = rgb >> 16 & 0xFF; final int green = rgb >> 8 & 0xFF; final int blue = rgb & 0xFF; glColor4i(red, green, blue, alpha); } @Override public int glGetClearColor() { return (int) (currentClearColorARGBf[0] * 255) << 24 | (int) (currentClearColorARGBf[1] * 255) << 16 | (int) (currentClearColorARGBf[2] * 255) << 8 | (int) (currentClearColorARGBf[3] * 255); } @Override public void glClearColor(final int rgb) { final float alpha = (rgb >> 24 & 0xFF) / 255f; final float red = (rgb >> 16 & 0xFF) / 255f; final float green = (rgb >> 8 & 0xFF) / 255f; final float blue = (rgb & 0xFF) / 255f; glClearColor4f(red, green, blue, alpha); } @Override public void glColor4i(final int r, final int g, final int b, final int a) { final float red = r / 255f; final float gre = g / 255f; final float blu = b / 255f; final float alp = a / 255f; //currentColor = new float[] { red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, }; currentColor = new float[] { red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, };//OK } @Override public void glClearColor4i(final int red, final int green, final int blue, final int alpha) { final float ros = red / 255f; final float gre = green / 255f; final float blu = blue / 255f; final float alp = alpha / 255f; currentClearColorARGBf = new float[] { alp, ros, gre, blu }; } @Override public void glClearColor4f(final float red, final float green, final float blue, final float alpha) { currentClearColorARGBf = new float[] { alpha, red, green, blue }; } @Override public void glClear(final int screenWidth, final int screenHeight) { glColor(glGetClearColor()); glFillColor(0, 0, screenWidth, screenHeight); } @Override public void glDrawLine(final float x0, final float y0, final float x1, final float y1) { glFillColor(x0, y0, x1 - x0 + 1, y1 - y0 + 1); } @Override public void glFillRect(final float x, final float y, final float width, final float height, float uvX, float uvY, float uvWidth, float uvHeight) { enableTexture(); if (uvWidth < 0) uvX -= uvWidth; if (uvHeight < 0) uvY -= uvHeight; uvWidth /= currentTexWidth; uvX /= currentTexWidth; uvHeight /= currentTexHeight; uvY = 1 - uvY / currentTexHeight - uvHeight; // final float[] vertices = { x, y, 0.0f, x, y + height, 0.0f, x + width, y, 0.0f, x + width, y + height, 0.0f, }; // final float[] tex_vertices = { uvX, uvY + uvHeight, uvX, uvY, uvX + uvWidth, uvY + uvHeight, uvX + uvWidth, uvY, }; //V0 x, y, 0.0f //V1 x, y + height, 0.0f //V2 x + width, y, 0.0f //V3 x + width, y + height, 0.0f //NV0 = V1 //NV1 = V3 //NV2 = V0 //NV3 = V0 //NV4 = V3 //NV5 = V2 final float[] vertices = { x, y + height, 0.0f, x + width, y + height, 0.0f, x, y, 0.0f, x, y, 0.0f, x + width, y + height, 0.0f, x + width, y, 0.0f }; final float[] tex_vertices = { uvX, uvY, uvX + uvWidth, uvY, uvX, uvY + uvHeight, uvX, uvY + uvHeight, uvX + uvWidth, uvY, uvX + uvWidth, uvY + uvHeight }; fbElements++; fbVertices.put(vertices); fbTextures.put(tex_vertices); fbColors.put(currentColor); } @Override public void glFillColor(final float x0, final float y0, final float w1, final float h1) { disableTexture(); // final float[] vertices = { x0, y0, 0.0f, x0, y0 + h1, 0.0f, x0 + w1, y0, 0.0f, x0 + w1, y0 + h1, 0.0f, }; // final float[] tex_vertices = { 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, }; //V0 x0, y0, 0.0f //V1 x0, y0 + h1, 0.0f //V2 x0 + w1, y0, 0.0f //V3 x0 + w1, y0 + h1, 0.0f //NV0 = V1 //NV1 = V3 //NV2 = V0 //NV3 = V0 //NV4 = V3 //NV5 = V2 final float[] vertices = { x0, y0 + h1, 0.0f, x0 + w1, y0 + h1, 0.0f, x0, y0, 0.0f, x0, y0, 0.0f, x0 + w1, y0 + h1, 0.0f, x0 + w1, y0, 0.0f, }; final float[] tex_vertices = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, }; fbElements++; fbVertices.put(vertices); fbTextures.put(tex_vertices); fbColors.put(currentColor); } @Override public void glDrawStringLeft(final float x, final float y, final String text) { final int txtLen = text.length(); final int[] txtArray = currentFont.getCharIndexes(text); int tableIndexX; int tableIndexY; for (int currentCharIndex = 0; currentCharIndex < txtLen; currentCharIndex++) { tableIndexX = txtArray[currentCharIndex] % currentFont.memoryWidthOfEachColumn; tableIndexY = (txtArray[currentCharIndex] - tableIndexX) / currentFont.memoryWidthOfEachColumn; glFillRect(x + (float) currentCharIndex * (float) currentFont.charW, y, currentFont.charW, currentFont.charH, tableIndexX * currentFont.charW, tableIndexY * currentFont.charH, currentFont.charW, currentFont.charH); } } @Override public void glDrawStringCenter(final float x, final float y, final String text) { glDrawStringLeft(x - currentFont.getStringWidth(text) / 2, y, text); } @Override public void glDrawStringRight(final float x, final float y, final String text) { glDrawStringLeft(x - currentFont.getStringWidth(text), y, text); } @Override public void glDrawCharLeft(final int x, final int y, final char ch) { final int index = currentFont.getCharIndex(ch); final int tableIndexX = index % currentFont.memoryWidthOfEachColumn; final int tableIndexY = (index - tableIndexX) / currentFont.memoryWidthOfEachColumn; glFillRect(x, y, currentFont.charW, currentFont.charH, tableIndexX * currentFont.charW, tableIndexY * currentFont.charH, currentFont.charW, currentFont.charH); } @Override public void glDrawCharCenter(final int x, final int y, final char ch) { glDrawCharLeft(x - currentFont.charW / 2, y, ch); } @Override public void glDrawCharRight(final int x, final int y, final char ch) { glDrawCharLeft(x - currentFont.charW, y, ch); } @Override public BinaryFont getCurrentFont() { return currentFont; } @Deprecated static Texture importTexture(final GL gl, final String string) throws IOException { final FileInputStream f = new FileInputStream("test.png"); final TextureData tx_dat = TextureIO.newTextureData(gl.getGLProfile(), f, false, TextureIO.PNG); final Texture tex = new Texture(gl, tx_dat); tex.setTexParameteri(gl, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); tex.setTexParameteri(gl, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); // tex.setTexParameteri(gl, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); // tex.setTexParameteri(gl, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); return tex; } static OpenedTextureData openTexture(final String file, final boolean isResource) throws GLException, IOException { BufferedImage img = ImageIO.read(isResource ? JOGLRenderer.class.getResource(file) : new File(file).toURI().toURL()); File f; if (isResource) { f = Files.createTempFile("texture-", ".png").toFile(); f.deleteOnExit(); ImageIO.write(img, "png", f); } else f = new File(file); final int imgW = img.getWidth(); final int imgH = img.getHeight(); img = null; Engine.getPlatform().gc(); return new OpenedTextureData(imgW, imgH, f, isResource); } public static class OpenedTextureData { public final int w; public final int h; public final File f; public final boolean deleteOnExit; /** * @param w * @param h * @param f * @param deleteOnExit */ public OpenedTextureData(final int w, final int h, final File f, final boolean deleteOnExit) { this.w = w; this.h = h; this.f = f; this.deleteOnExit = deleteOnExit; } } static Texture importTexture(File f, final boolean deleteOnExit) throws GLException, IOException { final Texture tex = TextureIO.newTexture(f, false); if (deleteOnExit && f.exists()) try { if (Engine.getPlatform().getSettings().isDebugEnabled()) throw new IOException("Delete on exit!"); f.delete(); } catch (final Exception ex) { f.deleteOnExit(); } tex.setTexParameteri(JOGLRenderer.gl, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); tex.setTexParameteri(JOGLRenderer.gl, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); f = null; return tex; } public void initDrawCycle() { final boolean textureChange = precTexEnabled != currentTexEnabled || precTex != currentTex; if (fbVertices == null) { fbVertices = Buffers.newDirectFloatBuffer(JOGLRenderer.vertMax); fbTextures = Buffers.newDirectFloatBuffer(JOGLRenderer.texMax); fbColors = Buffers.newDirectFloatBuffer(JOGLRenderer.colMax); handlers = new int[3]; JOGLRenderer.gl.glGenBuffers(3, handlers, 0); } startDrawSegment(false); if (textureChange) changeTexture(); } public void endDrawCycle() { final boolean textureChange = precTexEnabled != currentTexEnabled || precTex != currentTex; if (textureChange) { if (fbElements > 0) endDrawSegment(); changeTexture(); } else if (fbElements > 0) endDrawSegment(); } private void changeTexture() { precTexEnabled = currentTexEnabled; precTex = currentTex; if (currentTexEnabled) { JOGLRenderer.gl.glEnable(GL.GL_TEXTURE_2D); currentTex.bind(JOGLRenderer.gl); } else JOGLRenderer.gl.glDisable(GL.GL_TEXTURE_2D); firstBufferTexDataCall = true; } public void startDrawSegment(final boolean continuation) { if (!continuation || cycleEnded) fbElements = 0; cycleEnded = false; } private boolean precTexEnabled; private Texture precTex; private boolean cycleEnded = true; public void doDrawSegment() { final boolean textureChange = precTexEnabled != currentTexEnabled || precTex != currentTex; final boolean changeRequired = fbElements >= JOGLRenderer.ELEMENTS_MAX_COUNT_PER_BUFFER; if (textureChange) { if (fbElements > 0) { endDrawSegment(); startDrawSegment(false); } changeTexture(); } else if (fbElements > 0 && changeRequired) { endDrawSegment(); startDrawSegment(true); } } boolean firstBufferDataCall = true; boolean firstBufferTexDataCall = true; public void endDrawSegment() { fbVertices.flip(); fbTextures.flip(); fbColors.flip(); // gl.glVertexPointer(vertSize, GL.GL_FLOAT, 0, fbVertices); JOGLRenderer.gl.glBindBuffer(GL.GL_ARRAY_BUFFER, handlers[JOGLRenderer.vertBuffer]); if (firstBufferTexDataCall) JOGLRenderer.gl.glBufferData(GL.GL_ARRAY_BUFFER, fbVertices.limit() * Buffers.SIZEOF_FLOAT, fbVertices, GL.GL_STATIC_DRAW); else JOGLRenderer.gl.glBufferSubData(GL.GL_ARRAY_BUFFER, 0, fbVertices.limit() * Buffers.SIZEOF_FLOAT, fbVertices); JOGLRenderer.gl.glVertexPointer(JOGLRenderer.vertSize, GL.GL_FLOAT, 0, 0l); // gl.glTexCoordPointer(texSize, GL.GL_FLOAT, 0, fbTextures); JOGLRenderer.gl.glBindBuffer(GL.GL_ARRAY_BUFFER, handlers[JOGLRenderer.texBuffer]); if (firstBufferTexDataCall) JOGLRenderer.gl.glBufferData(GL.GL_ARRAY_BUFFER, fbTextures.limit() * Buffers.SIZEOF_FLOAT, fbTextures, GL.GL_STATIC_DRAW); else JOGLRenderer.gl.glBufferSubData(GL.GL_ARRAY_BUFFER, 0, fbTextures.limit() * Buffers.SIZEOF_FLOAT, fbTextures); JOGLRenderer.gl.glTexCoordPointer(JOGLRenderer.texSize, GL.GL_FLOAT, 0, 0l); // gl.glColorPointer(colSize, GL.GL_FLOAT, 0, fbColors); JOGLRenderer.gl.glBindBuffer(GL.GL_ARRAY_BUFFER, handlers[JOGLRenderer.colBuffer]); if (firstBufferTexDataCall) JOGLRenderer.gl.glBufferData(GL.GL_ARRAY_BUFFER, fbColors.limit() * Buffers.SIZEOF_FLOAT, fbColors, GL.GL_STATIC_DRAW); else JOGLRenderer.gl.glBufferSubData(GL.GL_ARRAY_BUFFER, 0, fbColors.limit() * Buffers.SIZEOF_FLOAT, fbColors); JOGLRenderer.gl.glColorPointer(JOGLRenderer.colSize, GL.GL_FLOAT, 0, 0l); fbVertices.limit(JOGLRenderer.vertMax); fbTextures.limit(JOGLRenderer.texMax); fbColors.limit(JOGLRenderer.colMax); JOGLRenderer.gl.glDrawArrays(GL.GL_TRIANGLES, 0, fbElements * JOGLRenderer.ELEMENT_VERTICES_COUNT); //gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, fbElements * ELEMENT_VERTICES_COUNT); firstBufferDataCall = false; firstBufferTexDataCall = false; cycleEnded = true; // deleteBuffer(fbVertices); // deleteBuffer(txVertices); // deleteBuffer(colVertices); // fbVertices = null; // txVertices = null; // colVertices = null; } @Override public void glClearSkin() { if (currentTex != null) { currentTex = null; doDrawSegment(); } } void disableTexture() { currentTexEnabled = false; doDrawSegment(); } void enableTexture() { currentTexEnabled = true; doDrawSegment(); } void useTexture(final Texture t, final float w, final float h) { currentTex = t; currentTexWidth = w; currentTexHeight = h; enableTexture(); } }