From b84960ae9cfe22e8f709abcc68ea79fcfbbeaf94 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Fri, 8 May 2020 23:28:01 +0200 Subject: [PATCH] [DEV] add basic test for Textured model --- src/org/atriaSoft/etk/math/Transform3D.java | 12 +- src/org/atriaSoft/gale/Application.java | 11 +- src/org/atriaSoft/gale/backend3d/OpenGL.java | 13 +- src/org/atriaSoft/gale/context/Context.java | 14 +- .../gale/context/LWJGL/ContextLWJGL.java | 475 +++++++++++++----- src/org/atriaSoft/gale/key/Special.java | 8 + .../gale/resource/ResourceProgram.java | 20 +- .../gale/resource/ResourceTexture.java | 325 +++++++----- .../resource/ResourceVirtualArrayObject.java | 49 ++ .../gale/test/sample1/MainApplication.java | 88 ++-- .../atriaSoft/gale/test/sample1/basic.vert | 8 +- src/org/atriaSoft/gale/test/sample2/Log.java | 29 ++ .../gale/test/sample2/MainApplication.java | 193 +++++++ .../atriaSoft/gale/test/sample2/basic.frag | 17 + .../atriaSoft/gale/test/sample2/basic.vert | 21 + .../atriaSoft/gale/test/sample2/sample_2.java | 11 + .../gale/test/sample2/tree_sample.png | Bin 0 -> 99816 bytes src/org/atriaSoft/gale/tools/ImageLoader.java | 49 ++ .../atriaSoft/gale/tools/ImageRawData.java | 34 ++ src/org/atriaSoft/gameEngine/Engine.java | 3 + src/org/atriaSoft/gameEngine/Entity.java | 36 +- .../atriaSoft/gameEngine/Environement.java | 38 +- src/org/atriaSoft/gameEngine/Signal.java | 9 +- .../gameEngine/components/ComponentAI.java | 12 + .../components/ComponentParticle.java | 12 + .../ComponentPosition.java | 14 +- .../components/ComponentRender.java | 13 + .../components/CoponentPhysics.java | 12 + .../gameEngine/engines/EngineAI.java | 51 ++ .../gameEngine/engines/EngineParticle.java | 52 ++ .../gameEngine/engines/EnginePhysics.java | 51 ++ .../gameEngine/engines/EngineRender.java | 51 ++ .../sample/lowPoly/sample_lowPoly.java | 5 + src/shaders/ShaderProgram.java | 4 +- 34 files changed, 1364 insertions(+), 376 deletions(-) create mode 100644 src/org/atriaSoft/gale/test/sample2/Log.java create mode 100644 src/org/atriaSoft/gale/test/sample2/MainApplication.java create mode 100644 src/org/atriaSoft/gale/test/sample2/basic.frag create mode 100644 src/org/atriaSoft/gale/test/sample2/basic.vert create mode 100644 src/org/atriaSoft/gale/test/sample2/sample_2.java create mode 100644 src/org/atriaSoft/gale/test/sample2/tree_sample.png create mode 100644 src/org/atriaSoft/gale/tools/ImageLoader.java create mode 100644 src/org/atriaSoft/gale/tools/ImageRawData.java create mode 100644 src/org/atriaSoft/gameEngine/components/ComponentAI.java create mode 100644 src/org/atriaSoft/gameEngine/components/ComponentParticle.java rename src/org/atriaSoft/gameEngine/{component => components}/ComponentPosition.java (76%) create mode 100644 src/org/atriaSoft/gameEngine/components/ComponentRender.java create mode 100644 src/org/atriaSoft/gameEngine/components/CoponentPhysics.java create mode 100644 src/org/atriaSoft/gameEngine/engines/EngineAI.java create mode 100644 src/org/atriaSoft/gameEngine/engines/EngineParticle.java create mode 100644 src/org/atriaSoft/gameEngine/engines/EnginePhysics.java create mode 100644 src/org/atriaSoft/gameEngine/engines/EngineRender.java create mode 100644 src/org/atriaSoft/gameEngine/sample/lowPoly/sample_lowPoly.java diff --git a/src/org/atriaSoft/etk/math/Transform3D.java b/src/org/atriaSoft/etk/math/Transform3D.java index e76c612..baf3462 100644 --- a/src/org/atriaSoft/etk/math/Transform3D.java +++ b/src/org/atriaSoft/etk/math/Transform3D.java @@ -65,7 +65,7 @@ public class Transform3D { return new Transform3D(invMatrix.multiply(this.position.multiply_new(-1)), invQuaternion); } /// Return an interpolated transform - Transform3D interpolateTransforms(Transform3D old, + public Transform3D interpolateTransforms(Transform3D old, Transform3D newOne, float interpolationFactor) { Vector3f interPosition = old.position.multiply_new(1.0f - interpolationFactor) @@ -75,24 +75,24 @@ public class Transform3D { return new Transform3D(interPosition, interOrientation); } /// Return the transformed vector - Vector3f multiply(Vector3f vector) { + public Vector3f multiply(Vector3f vector) { return this.orientation.getMatrix().multiply(vector).add(this.position); } /// Operator of multiplication of a transform with another one - Transform3D multiply_new(Transform3D transform2) { + public Transform3D multiply_new(Transform3D transform2) { return new Transform3D(this.orientation.getMatrix().multiply(transform2.position).add(this.position), this.orientation.multiply_new(transform2.orientation)); } /// Return true if the two transforms are equal - boolean isEqual(Transform3D transform2) { + public boolean isEqual(Transform3D transform2) { return this.position.isEqual(transform2.position) && this.orientation.isEqual(transform2.orientation); } /// Return true if the two transforms are different - boolean isDifferent(Transform3D transform2) { + public boolean isDifferent(Transform3D transform2) { return this.position.isDifferent(transform2.position) || this.orientation.isDifferent(transform2.orientation); } /// Assignment operator - Transform3D set(Transform3D transform) { + public Transform3D set(Transform3D transform) { this.position = transform.position.clone(); this.orientation = transform.orientation.clone(); return this; diff --git a/src/org/atriaSoft/gale/Application.java b/src/org/atriaSoft/gale/Application.java index 318bdb4..976fac6 100644 --- a/src/org/atriaSoft/gale/Application.java +++ b/src/org/atriaSoft/gale/Application.java @@ -48,7 +48,7 @@ public class Application { * @param[in] context Current gale context. */ public void onRegenerateDisplay(Context context) { - Log.verbose("Regenerate Gale Application"); + //Log.verbose("Regenerate Gale Application"); markDrawingIsNeeded(); } @@ -157,7 +157,11 @@ public class Application { * @param[in] size New size of the window. */ public void onResize(Vector2f size) { - + if (size == null) { + Log.error("Try to set a null size ..."); + return; + } + windowsSize = size; } /** * @brief Set the size of the window (if possible: Android and Ios does not support it) @@ -179,6 +183,9 @@ public class Application { public Vector2f getSize() { return windowsSize; } + public float getAspectRatio() { + return windowsSize.x/windowsSize.y; + } /** * @brief Event generated when user change the position of the window. diff --git a/src/org/atriaSoft/gale/backend3d/OpenGL.java b/src/org/atriaSoft/gale/backend3d/OpenGL.java index 2a3c2f6..2354921 100644 --- a/src/org/atriaSoft/gale/backend3d/OpenGL.java +++ b/src/org/atriaSoft/gale/backend3d/OpenGL.java @@ -195,6 +195,12 @@ public class OpenGL { elem.getValue().mustBeSet = false; } } + public static void resetFlagState() { + for (Map.Entry elem: flagsStates.entrySet()) { + elem.getValue().mustBeSet = false; + } + flagsStatesChange = true; + } private static Map threadHasContext = new HashMap(); /** * @brief Get the current thread context status. @@ -519,7 +525,7 @@ public class OpenGL { * @brief Use openGL program * @param[in] id Id of the program that might be used */ - public static void useProgram(int id) { + public static void programUse(int id) { //Log.verbose("USE prog : " + id); // note : In normal openGL case, the system might call with the program ID and at the end with 0, // here, we wrap this use to prevent over call of glUseProgram == > then we set -1 when the @@ -534,7 +540,7 @@ public class OpenGL { } checkGlError("glUseProgram"); } - public static void unUseProgram(int id) { + public static void programUnUse(int id) { // nothing to do ... } public static void reset() { @@ -859,5 +865,8 @@ public class OpenGL { public static void programLoadUniformMatrix(int location, Matrix4f value, boolean transpose) { GL20.glUniformMatrix4fv(location, transpose, value.getTable()); } + public static void drawElements(RenderMode mode, int vertexCount) { + GL11.glDrawElements(convertRenderMode.get(mode), vertexCount, GL11.GL_UNSIGNED_INT, 0); + } } diff --git a/src/org/atriaSoft/gale/context/Context.java b/src/org/atriaSoft/gale/context/Context.java index cfd7f72..bc4eb07 100644 --- a/src/org/atriaSoft/gale/context/Context.java +++ b/src/org/atriaSoft/gale/context/Context.java @@ -56,6 +56,7 @@ class PeriodicThread extends ThreadAbstract { }; public abstract class Context { + protected final int MAX_MANAGE_INPUT = 15; protected ThreadAbstract periodicThread; protected Application application; //!< Application handle public Application getApplication() { @@ -167,7 +168,7 @@ public abstract class Context { // simulation area: private long previousDisplayTime; // this is to limit framerate ... in case... private Vector msgSystem = new Vector(); - private boolean displayFps = false; + private boolean displayFps = true; private Fps FpsSystemEvent = new Fps("SystemEvent", displayFps); private Fps FpsSystemContext = new Fps("SystemContext", displayFps); private Fps FpsSystem = new Fps("System", displayFps); @@ -264,6 +265,12 @@ public abstract class Context { status); }); } + public void OS_setKeyboard( Special special, + Keyboard type, + Status state, + boolean isARepeateKey) { + OS_setKeyboard(special, type, state, isARepeateKey, (char)0); + } public void OS_setKeyboard( Special special, Keyboard type, Status state, @@ -381,6 +388,7 @@ public abstract class Context { } this.previousDisplayTime = currentTime; OpenGL.threadHasContext(); + OpenGL.resetFlagState(); // process the events if (this.displayFps == true) { this.FpsSystemEvent.tic(); @@ -543,6 +551,10 @@ public abstract class Context { Log.debug("Receive MSG : THREAD_RESIZE : " + context.windowsSize + " ==> " + _size); context.windowsSize = _size; //gale::Dimension::setPixelWindowsSize(_context.windowsSize); + Application tmpAppl = context.getApplication(); + if (tmpAppl != null) { + tmpAppl.onResize(context.windowsSize); + } // call application inside .. context.forceRedrawAll(); }); diff --git a/src/org/atriaSoft/gale/context/LWJGL/ContextLWJGL.java b/src/org/atriaSoft/gale/context/LWJGL/ContextLWJGL.java index 7180f63..ec9ac1a 100644 --- a/src/org/atriaSoft/gale/context/LWJGL/ContextLWJGL.java +++ b/src/org/atriaSoft/gale/context/LWJGL/ContextLWJGL.java @@ -1,44 +1,7 @@ package org.atriaSoft.gale.context.LWJGL; import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks; -import static org.lwjgl.glfw.GLFW.GLFW_FALSE; -import static org.lwjgl.glfw.GLFW.GLFW_KEY_A; -import static org.lwjgl.glfw.GLFW.GLFW_KEY_D; -import static org.lwjgl.glfw.GLFW.GLFW_KEY_ESCAPE; -import static org.lwjgl.glfw.GLFW.GLFW_KEY_Q; -import static org.lwjgl.glfw.GLFW.GLFW_KEY_S; -import static org.lwjgl.glfw.GLFW.GLFW_KEY_SPACE; -import static org.lwjgl.glfw.GLFW.GLFW_KEY_W; -import static org.lwjgl.glfw.GLFW.GLFW_KEY_Z; -import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_LEFT; -import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_RIGHT; -import static org.lwjgl.glfw.GLFW.GLFW_PRESS; -import static org.lwjgl.glfw.GLFW.GLFW_RELEASE; -import static org.lwjgl.glfw.GLFW.GLFW_RESIZABLE; -import static org.lwjgl.glfw.GLFW.GLFW_TRUE; -import static org.lwjgl.glfw.GLFW.GLFW_VISIBLE; -import static org.lwjgl.glfw.GLFW.glfwCreateWindow; -import static org.lwjgl.glfw.GLFW.glfwDefaultWindowHints; -import static org.lwjgl.glfw.GLFW.glfwDestroyWindow; -import static org.lwjgl.glfw.GLFW.glfwGetPrimaryMonitor; -import static org.lwjgl.glfw.GLFW.glfwGetVideoMode; -import static org.lwjgl.glfw.GLFW.glfwGetWindowSize; -import static org.lwjgl.glfw.GLFW.glfwInit; -import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent; -import static org.lwjgl.glfw.GLFW.glfwPollEvents; -import static org.lwjgl.glfw.GLFW.glfwSetCursorPosCallback; -import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback; -import static org.lwjgl.glfw.GLFW.glfwSetKeyCallback; -import static org.lwjgl.glfw.GLFW.glfwSetMouseButtonCallback; -import static org.lwjgl.glfw.GLFW.glfwSetScrollCallback; -import static org.lwjgl.glfw.GLFW.glfwSetWindowPos; -import static org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose; -import static org.lwjgl.glfw.GLFW.glfwShowWindow; -import static org.lwjgl.glfw.GLFW.glfwSwapBuffers; -import static org.lwjgl.glfw.GLFW.glfwSwapInterval; -import static org.lwjgl.glfw.GLFW.glfwTerminate; -import static org.lwjgl.glfw.GLFW.glfwWindowHint; -import static org.lwjgl.glfw.GLFW.glfwWindowShouldClose; +import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; import static org.lwjgl.opengl.GL11.glClear; @@ -49,11 +12,16 @@ import static org.lwjgl.system.MemoryUtil.NULL; import java.nio.IntBuffer; +import org.atriaSoft.etk.Uri; import org.atriaSoft.etk.math.Vector2f; import org.atriaSoft.gale.Application; import org.atriaSoft.gale.Fps; import org.atriaSoft.gale.context.Context; +import org.atriaSoft.gale.key.Keyboard; import org.atriaSoft.gale.key.Special; +import org.atriaSoft.gale.key.Status; +import org.atriaSoft.gale.key.Type; +import org.atriaSoft.gameEngine.Log; import org.lwjgl.Version; import org.lwjgl.glfw.GLFWErrorCallback; import org.lwjgl.glfw.GLFWVidMode; @@ -63,7 +31,9 @@ import org.lwjgl.system.MemoryStack; import renderEngine.DisplayManagerDraw; public class ContextLWJGL extends Context { - + + private boolean[] inputIsPressed = new boolean[MAX_MANAGE_INPUT]; + private Vector2f cursorPos = new Vector2f(0, 0); private static final int WIDTH = 800; private static final int HEIGHT = 600; private static final String TITLE = "Gale basic UI"; @@ -178,99 +148,26 @@ public class ContextLWJGL extends Context { // Setup a key callback. It will be called every time a key is pressed, repeated or released. // https://www.glfw.org/docs/latest/input_guide.html glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> { - if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE ) { - glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop - } - if ( key == GLFW_KEY_Z ) { - if (action == GLFW_PRESS ) { - System.out.println("Key Z is pressed"); - valueZ = true; - } else if (action == GLFW_RELEASE ) { - System.out.println("Key Z is release"); - valueZ = false; - } - } - if ( key == GLFW_KEY_S ) { - if (action == GLFW_PRESS ) { - System.out.println("Key S is pressed"); - valueS = true; - } else if (action == GLFW_RELEASE ) { - System.out.println("Key S is release"); - valueS = false; - } - } - if ( key == GLFW_KEY_Q ) { - if (action == GLFW_PRESS ) { - System.out.println("Key Q is pressed"); - valueQ = true; - } else if (action == GLFW_RELEASE ) { - System.out.println("Key Q is release"); - valueQ = false; - } - } - if ( key == GLFW_KEY_D ) { - if (action == GLFW_PRESS ) { - System.out.println("Key D is pressed"); - valueD = true; - } else if (action == GLFW_RELEASE ) { - System.out.println("Key D is release"); - valueD = false; - } - } - if ( key == GLFW_KEY_A ) { - if (action == GLFW_PRESS ) { - System.out.println("Key A is pressed"); - valueA = true; - } else if (action == GLFW_RELEASE ) { - System.out.println("Key A is release"); - valueA = false; - } - } - if ( key == GLFW_KEY_W ) { - if (action == GLFW_PRESS ) { - System.out.println("Key W is pressed"); - valueW = true; - } else if (action == GLFW_RELEASE ) { - System.out.println("Key W is release"); - valueW = false; - } - } - if ( key == GLFW_KEY_SPACE ) { - if (action == GLFW_PRESS ) { - System.out.println("Key SPACE is pressed"); - valueSPACE = true; - } else if (action == GLFW_RELEASE ) { - System.out.println("Key SPACE is release"); - valueSPACE = false; - } - } + this.keyCallback(window, key, scancode, action, mods); + }); + glfwSetWindowSizeCallback(window, (windows, sizeX, sizeY) -> { + this.windowSizeCallback(window, sizeX, sizeY); + }); + + glfwSetCharCallback(window, (window, key) -> { + this.charCallback(window, key); }); glfwSetCursorPosCallback(window, (window, xpos, ypos) -> { - currentMousePositionX = xpos; - currentMousePositionY = ypos; - + this.cursorPosCallback(window, xpos, ypos); }); glfwSetMouseButtonCallback(window, (window, button, action, mods) -> { - if (button == GLFW_MOUSE_BUTTON_RIGHT) { - if (action == GLFW_PRESS) { - rightButtonStateDown = true; - } else if (action == GLFW_RELEASE) { - rightButtonStateDown = false; - } - } else if (button == GLFW_MOUSE_BUTTON_LEFT) { - if (action == GLFW_PRESS) { - leftButtonStateDown = true; - } else if (action == GLFW_RELEASE) { - leftButtonStateDown = false; - } - } + this.mouseCallback(window, button, action, mods); }); glfwSetScrollCallback(window, (window, xoffset, yoffset) -> { - whellOffsetY += yoffset; - whellOffsetX += xoffset; + this.scrollCallback(window, xoffset, yoffset); }); @@ -304,8 +201,329 @@ public class ContextLWJGL extends Context { lastFrameTime = getCurrentTime(); } + private void windowSizeCallback(long window2, int sizeX, int sizeY) { + OS_Resize(new Vector2f(sizeX, sizeY)); + } - + + private void charCallback(long window, int key) {; + Log.error("keyboard char " + key + " " + (char)key); + } + private void keyCallback(long window, int key, int scancode, int action, int mods) { + boolean find = true; + boolean thisIsAReapeateKey = false; // TODO detect this ... + Keyboard keyInput = Keyboard.unknow; + Log.error("keyboard input " + key + " " + scancode); + switch (key) { + //case 80: // keypad + case GLFW_KEY_UP: keyInput = Keyboard.up; break; + //case 83: // keypad + case GLFW_KEY_LEFT: keyInput = Keyboard.left; break; + //case 85: // keypad + case GLFW_KEY_RIGHT: keyInput = Keyboard.right; break; + //case 88: // keypad + case GLFW_KEY_DOWN: keyInput = Keyboard.down; break; + //case 81: // keypad + case GLFW_KEY_PAGE_UP: keyInput = Keyboard.pageUp; break; + //case 89: // keypad + case GLFW_KEY_PAGE_DOWN: keyInput = Keyboard.pageDown; break; + //case 79: // keypad + case GLFW_KEY_HOME: keyInput = Keyboard.start; break; + //case 87: // keypad + case GLFW_KEY_END: keyInput = Keyboard.end; break; + case GLFW_KEY_PRINT_SCREEN: keyInput = Keyboard.stopDefil; break; + case GLFW_KEY_PAUSE: keyInput = Keyboard.wait; break; + //case 90: // keypad + case GLFW_KEY_INSERT: + keyInput = Keyboard.insert; + if(action == GLFW_RELEASE) { + if (guiKeyBoardMode.getInsert() == true) { + guiKeyBoardMode.setInsert(false); + } else { + guiKeyBoardMode.setInsert(true); + } + } + break; + //case 84: keyInput = KeyboardCenter; break; // Keypad + case GLFW_KEY_F1: keyInput = Keyboard.f1; break; + case GLFW_KEY_F2: keyInput = Keyboard.f2; break; + case GLFW_KEY_F3: keyInput = Keyboard.f3; break; + case GLFW_KEY_F4: keyInput = Keyboard.f4; break; + case GLFW_KEY_F5: keyInput = Keyboard.f5; break; + case GLFW_KEY_F6: keyInput = Keyboard.f6; break; + case GLFW_KEY_F7: keyInput = Keyboard.f7; break; + case GLFW_KEY_F8: keyInput = Keyboard.f8; break; + case GLFW_KEY_F9: keyInput = Keyboard.f9; break; + case GLFW_KEY_F10: keyInput = Keyboard.f10; break; + case GLFW_KEY_F11: keyInput = Keyboard.f11; break; + case GLFW_KEY_F12: keyInput = Keyboard.f12; break; + case GLFW_KEY_CAPS_LOCK: keyInput = Keyboard.capLock; guiKeyBoardMode.setCapsLock (action == GLFW_PRESS); break; + case GLFW_KEY_LEFT_SHIFT: keyInput = Keyboard.shiftLeft; guiKeyBoardMode.setShiftLeft (action == GLFW_PRESS); break; + case GLFW_KEY_RIGHT_SHIFT: keyInput = Keyboard.shiftRight; guiKeyBoardMode.setShiftRight(action == GLFW_PRESS); break; + case GLFW_KEY_LEFT_CONTROL: keyInput = Keyboard.ctrlLeft; guiKeyBoardMode.setCtrlLeft (action == GLFW_PRESS); break; + case GLFW_KEY_RIGHT_CONTROL: keyInput = Keyboard.ctrlRight; guiKeyBoardMode.setCtrlRight (action == GLFW_PRESS); break; + case GLFW_KEY_LEFT_SUPER: keyInput = Keyboard.metaLeft; guiKeyBoardMode.setMetaLeft (action == GLFW_PRESS); break; + case GLFW_KEY_RIGHT_SUPER: keyInput = Keyboard.metaRight; guiKeyBoardMode.setMetaRight (action == GLFW_PRESS); break; + case GLFW_KEY_LEFT_ALT: keyInput = Keyboard.altLeft; guiKeyBoardMode.setAltLeft (action == GLFW_PRESS); break; + case GLFW_KEY_RIGHT_ALT: keyInput = Keyboard.altRight; guiKeyBoardMode.setAltRight (action == GLFW_PRESS); break; + case GLFW_KEY_MENU: keyInput = Keyboard.contextMenu; break; + case GLFW_KEY_NUM_LOCK: keyInput = Keyboard.numLock; guiKeyBoardMode.setNumLock (action == GLFW_PRESS); break; + case GLFW_KEY_DELETE: // Suppr on keypad + find = false; + if(guiKeyBoardMode.getNumLock() == true){ + OS_setKeyboard(guiKeyBoardMode, + Keyboard.character, + (action == GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey, + '.'); + if (thisIsAReapeateKey == true) { + OS_setKeyboard(guiKeyBoardMode, + Keyboard.character, + (action != GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey, + '.'); + } + } else { + OS_setKeyboard(guiKeyBoardMode, + Keyboard.character, + (action == GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey, + (char)0x7F); + if (thisIsAReapeateKey == true) { + OS_setKeyboard(guiKeyBoardMode, + Keyboard.character, + (action != GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey, + (char)0x7F); + } + } + break; + case GLFW_KEY_TAB: // special case for TAB + find = false; + OS_setKeyboard(guiKeyBoardMode, + Keyboard.character, + (action == GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey, + (char)0x09); + if (thisIsAReapeateKey == true) { + OS_setKeyboard(guiKeyBoardMode, + Keyboard.character, + (action!=GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey, + (char)0x09); + } + break; + case GLFW_KEY_A: + case GLFW_KEY_B: + case GLFW_KEY_C: + case GLFW_KEY_D: + case GLFW_KEY_E: + case GLFW_KEY_F: + case GLFW_KEY_G: + case GLFW_KEY_H: + case GLFW_KEY_I: + case GLFW_KEY_J: + case GLFW_KEY_K: + case GLFW_KEY_L: + case GLFW_KEY_M: + case GLFW_KEY_N: + case GLFW_KEY_O: + case GLFW_KEY_P: + case GLFW_KEY_Q: + case GLFW_KEY_R: + case GLFW_KEY_S: + case GLFW_KEY_T: + case GLFW_KEY_U: + case GLFW_KEY_V: + case GLFW_KEY_W: + case GLFW_KEY_X: + case GLFW_KEY_Y: + case GLFW_KEY_Z: + { + find = false; + int tmpKey = key-GLFW_KEY_A + (int)'a'; + if (guiKeyBoardMode.getCapsLock() == true || guiKeyBoardMode.getShift() == true) { + tmpKey += (int)'A' - (int)'a'; + } + OS_setKeyboard(guiKeyBoardMode, + Keyboard.character, + (action==GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey, + (char)tmpKey); + if (thisIsAReapeateKey == true) { + OS_setKeyboard(guiKeyBoardMode, + Keyboard.character, + (action!=GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey, + (char)tmpKey); + } + break; + } + case GLFW_KEY_1: + case GLFW_KEY_2: + case GLFW_KEY_3: + case GLFW_KEY_4: + case GLFW_KEY_5: + case GLFW_KEY_6: + case GLFW_KEY_7: + case GLFW_KEY_8: + case GLFW_KEY_9: + case GLFW_KEY_0: + { + find = false; + int tmpKey = key-GLFW_KEY_0 + (int)'0'; +// if (guiKeyBoardMode.getCapsLock() == true || guiKeyBoardMode.getShift() == true) { +// tmpKey += (int)'A' - (int)'a'; +// } + OS_setKeyboard(guiKeyBoardMode, + Keyboard.character, + (action==GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey, + (char)tmpKey); + if (thisIsAReapeateKey == true) { + OS_setKeyboard(guiKeyBoardMode, + Keyboard.character, + (action!=GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey, + (char)tmpKey); + } + } + default: + find = false; +// { +// char buf[11]; +// //GALE_DEBUG("Keycode: " << event.xkey.keycode); +// // change keystate for simple reson of the ctrl error... +// int32_t keyStateSave = event.xkey.state; +// if (event.xkey.state & (1<<2) ) { +// event.xkey.state = event.xkey.state & 0xFFFFFFFB; +// } +// KeySym keysym; +// Status status = 0; +// //int count = Xutf8LookupString(m_xic, (XKeyPressedEvent*)&event, buf, 10, &keysym, &status); +// int count = Xutf8LookupString(m_xic, &event.xkey, buf, 10, &keysym, &status); +// // retreave real keystate +// event.xkey.state = keyStateSave; +// buf[count] = '\0'; +// // Replace \r error ... +// if (buf[0] == '\r') { +// buf[0] = '\n'; +// buf[1] = '\0'; +// } +// if (count >= 0) { +// // repeated kay from previous element : +// if (count > 0) { +// // transform it in unicode +// m_lastKeyPressed = utf8::convertChar32(buf); +// } +// X11_INFO("event Key : " << event.xkey.keycode << " char=\"" << buf << "\"'len=" << strlen(buf) << " unicode=" << m_lastKeyPressed); +// OS_setKeyboard(m_guiKeyBoardMode, +// gale::key::keyboard::character, +// (event.type==KeyPress?gale::key::status::down:gale::key::status::up), +// thisIsAReapeateKey, +// m_lastKeyPressed); +// if (thisIsAReapeateKey == true) { +// OS_setKeyboard(m_guiKeyBoardMode, +// gale::key::keyboard::character, +// (event.type!=KeyPress?gale::key::status::down:gale::key::status::up), +// thisIsAReapeateKey, +// m_lastKeyPressed); +// } +// } else { +// GALE_WARNING("Unknow event Key : " << event.xkey.keycode << " res='" << buf << "' repeate=" << thisIsAReapeateKey); +// } +// } +// break; + } + if (find == true) { + OS_setKeyboard(guiKeyBoardMode, + keyInput, + (action == GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey); + if (thisIsAReapeateKey == true) { + OS_setKeyboard(guiKeyBoardMode, + keyInput, + (action!=GLFW_PRESS?Status.down:Status.up), + thisIsAReapeateKey); + } + } +// if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE ) { +// glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop +// } + } + private void cursorPosCallback(long window, double xpos, double ypos) { + cursorPos.x = (float)xpos; + cursorPos.y = /*m_currentHeight*/800.0f-(float)ypos; + // For compatibility of the Android system : + boolean findOne = false; + for (int iii=0; iii0) { + inputIsPressed[4] = true; + OS_SetInput(Type.mouse, + Status.down, + 4, + cursorPos); + inputIsPressed[4] = false; + OS_SetInput(Type.mouse, + Status.up, + 4, + cursorPos); + } + } + private void mouseCallback(long window, int button, int action, int mods) { + if (action == GLFW_PRESS) { + if (button < MAX_MANAGE_INPUT) { + inputIsPressed[button] = true; + } + OS_SetInput(Type.mouse, + Status.down, + button, + cursorPos); + } else if (action == GLFW_RELEASE) { + leftButtonStateDown = false; + if (button < MAX_MANAGE_INPUT) { + inputIsPressed[button] = false; + } + OS_SetInput(Type.mouse, + Status.up, + button, + cursorPos); + } + } public static float getFrameTimeSecconds() { return delta; } @@ -379,6 +597,15 @@ public class ContextLWJGL extends Context { System.exit(0); return 0; } + /****************************************************************************************/ + @Override + public void setTitle(String title) { + glfwSetWindowTitle(this.window, title); + } + public void setIcon(Uri inputFile) { + + } + public static Context create(Application application, String[] arg) { // TODO Auto-generated method stub diff --git a/src/org/atriaSoft/gale/key/Special.java b/src/org/atriaSoft/gale/key/Special.java index 64af63b..ab3ea88 100644 --- a/src/org/atriaSoft/gale/key/Special.java +++ b/src/org/atriaSoft/gale/key/Special.java @@ -293,4 +293,12 @@ public class Special { } return false; } + @Override + public String toString() { + return "Special [CapLock=" + valueCapLock + ", Shift=(" + valueShiftLeft + "," + + valueShiftRight + "), Ctrl=(" + valueCtrlLeft + "," + valueCtrlRight + + "), Meta=(" + valueMetaLeft + "," + valueMetaRight + "), Alt=(" + + valueAltLeft + "," + valueAltRight + "), NumLock=" + valueNumLock + + ", Insert=" + valueInsert + "]"; + } } diff --git a/src/org/atriaSoft/gale/resource/ResourceProgram.java b/src/org/atriaSoft/gale/resource/ResourceProgram.java index 3385ffe..74ab03f 100644 --- a/src/org/atriaSoft/gale/resource/ResourceProgram.java +++ b/src/org/atriaSoft/gale/resource/ResourceProgram.java @@ -836,9 +836,9 @@ public class ResourceProgram extends Resource { * @brief Request the processing of this program */ public void use() { - Log.verbose("Will use program : " + this.program); + //Log.verbose("Will use program : " + this.program); // event if it was 0 == > set it to prevent other use of the previous shader display ... - OpenGL.useProgram(this.program); + OpenGL.programUse(this.program); } /** * @brief set the testure Id on the specify uniform element. @@ -886,7 +886,7 @@ public class ResourceProgram extends Resource { * @brief Stop the processing of this program */ public void unUse() { - Log.verbose("Will UN-use program : " + this.program); + //Log.verbose("Will UN-use program : " + this.program); if (this.exist == false) { return; @@ -896,12 +896,8 @@ public class ResourceProgram extends Resource { } this.listOfVBOUsed.clear(); // no need to disable program == > this only generate perturbation on speed ... - OpenGL.useProgram(-1); + OpenGL.programUse(-1); } - public static final int INDICE_VBO_POSITIONS = 0; - public static final int INDICE_VBO_TEXTURE_COORDINATES = 1; - public static final int INDICE_VBO_NORMALS = 2; - public static final int INDICE_VBO_COLORS = 3; /** @@ -925,10 +921,10 @@ public class ResourceProgram extends Resource { OpenGL.programAttach(this.program, this.shaderFragment.getGLID()); } - OpenGL.programBindAttribute(this.program, INDICE_VBO_POSITIONS, "position"); - OpenGL.programBindAttribute(this.program, INDICE_VBO_TEXTURE_COORDINATES, "textureCoords"); - OpenGL.programBindAttribute(this.program, INDICE_VBO_NORMALS, "normal"); - OpenGL.programBindAttribute(this.program, INDICE_VBO_COLORS, "colors"); + OpenGL.programBindAttribute(this.program, ResourceVirtualArrayObject.INDICE_VBO_POSITIONS, "position"); + OpenGL.programBindAttribute(this.program, ResourceVirtualArrayObject.INDICE_VBO_TEXTURE_COORDINATES, "textureCoords"); + OpenGL.programBindAttribute(this.program, ResourceVirtualArrayObject.INDICE_VBO_NORMALS, "normal"); + OpenGL.programBindAttribute(this.program, ResourceVirtualArrayObject.INDICE_VBO_COLORS, "colors"); if (OpenGL.programCompile(this.program) == false) { Log.error("Could not compile'PROGRAM':'" + this.name + "'"); diff --git a/src/org/atriaSoft/gale/resource/ResourceTexture.java b/src/org/atriaSoft/gale/resource/ResourceTexture.java index 1798750..a16c70f 100644 --- a/src/org/atriaSoft/gale/resource/ResourceTexture.java +++ b/src/org/atriaSoft/gale/resource/ResourceTexture.java @@ -1,7 +1,67 @@ package org.atriaSoft.gale.resource; -public class ResourceTexture { +import java.nio.ByteBuffer; +import org.atriaSoft.etk.Uri; +import org.atriaSoft.etk.math.Vector2f; +import org.atriaSoft.etk.math.Vector2i; +import org.atriaSoft.gale.Log; +import org.atriaSoft.gale.backend3d.OpenGL; +import org.atriaSoft.gale.tools.ImageLoader; +import org.atriaSoft.gale.tools.ImageRawData; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL30; + +public class ResourceTexture extends Resource { + private static int[] textureIdBinding = { + GL13.GL_TEXTURE0, + GL13.GL_TEXTURE1, + GL13.GL_TEXTURE2, + GL13.GL_TEXTURE3, + GL13.GL_TEXTURE4, + GL13.GL_TEXTURE5, + GL13.GL_TEXTURE6, + GL13.GL_TEXTURE7, + GL13.GL_TEXTURE8, + GL13.GL_TEXTURE9, + GL13.GL_TEXTURE10, + GL13.GL_TEXTURE11, + GL13.GL_TEXTURE12, + GL13.GL_TEXTURE13, + GL13.GL_TEXTURE14, + GL13.GL_TEXTURE15, + GL13.GL_TEXTURE16, + GL13.GL_TEXTURE17, + GL13.GL_TEXTURE18, + GL13.GL_TEXTURE19, + GL13.GL_TEXTURE20, + GL13.GL_TEXTURE21, + GL13.GL_TEXTURE22, + GL13.GL_TEXTURE23, + GL13.GL_TEXTURE24, + GL13.GL_TEXTURE25, + GL13.GL_TEXTURE26, + GL13.GL_TEXTURE27, + GL13.GL_TEXTURE28, + GL13.GL_TEXTURE29, + GL13.GL_TEXTURE30, + GL13.GL_TEXTURE31 + }; + public enum TextureColorMode { + rgb, //!< red/green/blue data + rgba //!< red/green/blue/alpha data + }; + protected int texId = -1; //!< openGl textureID. + protected Vector2f endPointSize = new Vector2f(-1, -1); //!< some image are not square == > we need to sqared it to prevent some openGl api error the the displayable size is not all the time 0.0 . 1.0. + protected boolean loaded = false; //!< internal state of the openGl system. + // Image properties: + private ByteBuffer data = null; //!< pointer on the image data. + private Vector2i size = new Vector2i(-1,-1); //!< size of the image data. + private TextureColorMode dataColorSpace = TextureColorMode.rgb; //!< Color space of the image. + private int textureUnit = 0; // number of lines and colomns in the texture (multiple texturing in a single texture) + private String filename = ""; /** * @brief get the next power 2 if the input * @param[in] value Value that we want the next power of 2 @@ -18,131 +78,152 @@ public class ResourceTexture { Log.critical("impossible CASE...."); return val; } - public: - enum class color { - mono = 0, //!< Monochrome color - rgb, //!< red/green/blue data - rgba //!< red/green/blue/alpha data - }; - enum dataType { - int16 = 0, //!< Image data are stored on integer 16 bit for each element - float32, //!< Image data are stored on flaoting point value on 32 bit for each element - }; - protected: - int this.texId; //!< openGl textureID. - Vector2f this.endPointSize; //!< some image are not square == > we need to sqared it to prevent some openGl api error the the displayable size is not all the time 0.0 . 1.0. - boolean this.loaded; //!< internal state of the openGl system. - // Gale internal API: - public: - virtual boolean updateContext(){ - ethread::RecursiveLock lock(this.mutex, true); - if (lock.tryLock() == false) { - //Lock error ==> try later ... - return false; - } - if (this.loaded == false) { - // Request a new texture at openGl : - glGenTextures(1, this.texId); - } - // in all case we set the texture properties : - // TODO : check error ??? - glBindTexture(GLTEXTURE2D, this.texId); - // TODO : Check error ??? - //glTexParameteri(GLTEXTURE2D, GLTEXTUREWRAPS, GLREPEAT); - //glTexParameteri(GLTEXTURE2D, GLTEXTUREWRAPT, GLREPEAT); - //--- mode nearest - //glTexParameteri(GLTEXTURE2D, GLTEXTUREMAGFILTER, GLNEAREST); - //glTexParameteri(GLTEXTURE2D, GLTEXTUREMINFILTER, GLNEAREST); - //--- Mode linear - glTexParameteri(GLTEXTURE2D, GLTEXTUREMAGFILTER, GLLINEAR); - glTexParameteri(GLTEXTURE2D, GLTEXTUREMINFILTER, GLLINEAR); - Log.info("TEXTURE: add [" + getId() + "]=" + this.size + " OGlId=" + this.texId); - glTexImage2D(GLTEXTURE2D, // Target - 0, // Level - GLRGBA, // Format internal - this.size.x(), - this.size.y(), - 0, // Border - GLRGBA, // format - GLUNSIGNEDBYTE, // type - ((*this.data)[0]) ); - // now the data is loaded - this.loaded = true; - return true; - } - virtual void removeContext() { - ethread::RecursiveLock lock(this.mutex); - if (true == this.loaded) { - // Request remove texture ... - Log.info("TEXTURE: Rm [" + getId() + "] texId=" + this.texId); - // TODO: Check if we are in the correct thread - glDeleteTextures(1, this.texId); - this.loaded = false; - } - } - virtual void removeContextToLate() { - ethread::RecursiveLock lock(this.mutex); - this.loaded = false; - this.texId=0; - } - // middleware interface: - public: - int getRendererId() { - return this.texId; - }; - Vector2f getUsableSize() { - return this.endPointSize; - }; - Vector2i getOpenGlSize() { - return this.size; - }; // Public API: - protected: - void init( String filename) { - super.init(filename); + protected ResourceTexture(String filename, int textureUnit) { + super(filename + "__" + textureUnit); + this.filename = filename; + this.textureUnit = textureUnit; + addResourceType("gale::resource::Texture"); + } + protected ResourceTexture(Uri filename, int textureUnit) { + super(filename + "__" + textureUnit); + this.filename = filename.get(); + this.textureUnit = textureUnit; + addResourceType("gale::resource::Texture"); + } + protected ResourceTexture() { + super(); + addResourceType("gale::resource::Texture"); + } + public void cleanUp() { + removeContext(); + } + // Gale internal API: + @Override + public boolean updateContext() { + if (this.loaded == true) { + return true; } - void init() { - gale::Resource::init(); + // Request a new texture at openGl : + texId = GL11.glGenTextures(); + GL13.glActiveTexture(textureUnit); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId); + + // All RGB bytes are aligned to each other and each component is 1 byte + GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1); + Log.info("TEXTURE: add [" + getId() + "]=" + this.size + " OGlId=" + this.texId); + if (dataColorSpace == TextureColorMode.rgb) { + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, this.size.x, this.size.y, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, data); + } else { + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, this.size.x, this.size.y, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, data); } - Texture() : - this.texId(0), - this.endPointSize(1,1), - this.loaded(false), - this.size(0,0), - this.dataType(gale::resource::Texture::dataType::int16), - this.dataColorSpace(gale::resource::Texture::color::mono) { - addResourceType("gale::resource::Texture"); + // generate multi-texture mapping + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); + + // Setup the ST coordinate system + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); + + // Setup what to do when the texture has to be scaled + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); + // now the data is loaded + this.loaded = true; + return true; + } + public void removeContext() { + if (true == this.loaded) { + // Request remove texture ... + Log.info("TEXTURE: Rm [" + getId() + "] texId=" + this.texId); + // TODO: Check if we are in the correct thread + GL11.glDeleteTextures(this.texId); + this.loaded = false; + } + } + public void removeContextToLate() { + this.loaded = false; + this.texId = -1; + } + public int getRendererId() { + return this.texId; + }; + public Vector2f getUsableSize() { + return this.endPointSize; + }; + public Vector2i getOpenGlSize() { + return this.size; + }; + // flush the data to send it at the openGl system + public void flush() { + // request to the manager to be call at the next update ... + getManager().update(this); + } + public void setTexture(ByteBuffer data, + Vector2i size, + TextureColorMode dataColorSpace, + int textureUnit) { + this.data = data; + this.size = size; + this.textureUnit = textureUnit; + this.endPointSize.x = (float)size.x; + this.endPointSize.y = (float)size.y; + this.dataColorSpace = dataColorSpace; + flush(); + } + public void bindForRendering(int idTexture) { + if (this.loaded == false) { + return; + } + GL13.glActiveTexture(textureIdBinding[idTexture]); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.texId); + if (dataColorSpace == TextureColorMode.rgba) { + OpenGL.enable(OpenGL.Flag.flag_cullFace); + OpenGL.enable(OpenGL.Flag.flag_back); + } + } + public void unBindForRendering() { + if (this.loaded == false) { + return; + } + if (dataColorSpace == TextureColorMode.rgba) { + OpenGL.disable(OpenGL.Flag.flag_cullFace); + OpenGL.disable(OpenGL.Flag.flag_back); + } + } + + public static ResourceTexture createFromPng(Uri uriTexture) { + return createFromPng(uriTexture, 1); + } + public static ResourceTexture createFromPng(Uri uriTexture, int textureUnit) { + ResourceTexture resource; + Resource resource2; + String name = uriTexture.getValue(); + if (name.isEmpty() == false && name != "---") { + resource2 = getManager().localKeep(name); + } else { + Log.error("Can not create a shader without a filaname"); + return null; + } + if (resource2 != null) { + if (resource2 instanceof ResourceTexture) { + resource2.keep(); + return (ResourceTexture)resource2; } - public: - virtual ~Texture() { - removeContext(); + Log.critical("Request resource file : '" + name + "' With the wrong type (dynamic cast error)"); + return null; } - public: - // flush the data to send it at the openGl system - void flush(){ - ethread::RecursiveLock lock(this.mutex); - // request to the manager to be call at the next update ... - getManager().update(ememory::dynamicPointerCast(sharedFromThis())); + resource = new ResourceTexture(uriTexture, textureUnit); + ImageRawData decodedData = ImageLoader.decodePngFile(uriTexture); + resource.setTexture(decodedData.getBuffer(), + new Vector2i(decodedData.getWidth(), decodedData.getHeight()), + (decodedData.isHasAlpha() == true?TextureColorMode.rgba:TextureColorMode.rgb), + textureUnit); + if (resource.resourceHasBeenCorectlyInit() == false) { + Log.critical("resource Is not correctly init : ResourceProgram" ); + return null; } + getManager().localAdd(resource); + return resource; + } - private: - // Image propoerties: - etk::Vector> this.data; //!< pointer on the image data. - Vector2i this.size; //!< size of the image data. - enum dataType this.dataType; //!< Type of the image. - enum color this.dataColorSpace; //!< Color space of the image. - public: - void setTexture( etk::Vector> data, - Vector2i size, - enum gale::resource::Texture::dataType dataType, - enum gale::resource::Texture::color dataColorSpace) { - ethread::RecursiveLock lock(this.mutex); - this.data = data; - this.size = size; - this.endPointSize = size; - this.dataType = dataType; - this.dataColorSpace = dataColorSpace; - // TODO : Reload ... - flush(); - } -} +} \ No newline at end of file diff --git a/src/org/atriaSoft/gale/resource/ResourceVirtualArrayObject.java b/src/org/atriaSoft/gale/resource/ResourceVirtualArrayObject.java index 18e9cd5..a5617f3 100644 --- a/src/org/atriaSoft/gale/resource/ResourceVirtualArrayObject.java +++ b/src/org/atriaSoft/gale/resource/ResourceVirtualArrayObject.java @@ -11,6 +11,7 @@ import org.atriaSoft.etk.math.Vector2f; import org.atriaSoft.etk.math.Vector3f; import org.atriaSoft.gale.Log; import org.atriaSoft.gale.backend3d.OpenGL; +import org.atriaSoft.gale.backend3d.OpenGL.RenderMode; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; @@ -29,7 +30,54 @@ public class ResourceVirtualArrayObject extends Resource { float[] normals = null; int[] indices = null; int vertexCount = -1; + public static final int INDICE_VBO_POSITIONS = 0; + public static final int INDICE_VBO_TEXTURE_COORDINATES = 1; + public static final int INDICE_VBO_NORMALS = 2; + public static final int INDICE_VBO_COLORS = 3; + public void bindForRendering() { + if (exist == false) { + return; + } + GL30.glBindVertexArray(vaoID); + if (positions != null) { + GL20.glEnableVertexAttribArray(INDICE_VBO_POSITIONS); + } + if (textureCoordinates != null) { + GL20.glEnableVertexAttribArray(INDICE_VBO_TEXTURE_COORDINATES); + } + if (normals != null) { + GL20.glEnableVertexAttribArray(INDICE_VBO_NORMALS); + } + if (colors != null) { + GL20.glEnableVertexAttribArray(INDICE_VBO_COLORS); + } + } + + public void unBindForRendering() { + if (exist == false) { + return; + } + if (positions != null) { + GL20.glDisableVertexAttribArray(INDICE_VBO_POSITIONS); + } + if (textureCoordinates != null) { + GL20.glDisableVertexAttribArray(INDICE_VBO_TEXTURE_COORDINATES); + } + if (normals != null) { + GL20.glDisableVertexAttribArray(INDICE_VBO_NORMALS); + } + if (colors != null) { + GL20.glDisableVertexAttribArray(INDICE_VBO_COLORS); + } + GL30.glBindVertexArray(0); + } + + public void render(RenderMode mode) { + OpenGL.drawElements(mode, vertexCount); + } + + private FloatBuffer storeDataInFloatBuffer(float[] data) { FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length); buffer.put(data); @@ -209,4 +257,5 @@ public class ResourceVirtualArrayObject extends Resource { getManager().localAdd(resource); return resource; } + } diff --git a/src/org/atriaSoft/gale/test/sample1/MainApplication.java b/src/org/atriaSoft/gale/test/sample1/MainApplication.java index 9252ea3..8a0c6cc 100644 --- a/src/org/atriaSoft/gale/test/sample1/MainApplication.java +++ b/src/org/atriaSoft/gale/test/sample1/MainApplication.java @@ -4,36 +4,26 @@ import org.atriaSoft.etk.Color; import org.atriaSoft.etk.Uri; import org.atriaSoft.etk.math.Matrix4f; import org.atriaSoft.etk.math.Vector2f; -import org.atriaSoft.etk.math.Vector2i; import org.atriaSoft.etk.math.Vector3f; import org.atriaSoft.gale.Application; import org.atriaSoft.gale.backend3d.OpenGL; -import org.atriaSoft.gale.backend3d.OpenGL.RenderMode; import org.atriaSoft.gale.context.Context; import org.atriaSoft.gale.resource.ResourceProgram; import org.atriaSoft.gale.resource.ResourceVirtualArrayObject; -import org.atriaSoft.gale.context.Cursor; import org.atriaSoft.gale.key.Keyboard; import org.atriaSoft.gale.key.Special; import org.atriaSoft.gale.key.Status; import org.atriaSoft.gale.key.Type; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL20; -import org.lwjgl.opengl.GL30; public class MainApplication extends Application { private ResourceProgram GLprogram; - private int GLPosition; private int GLMatrixTransformation; private int GLMatrixProjection; private int GLMatrixView; - private int GLColor; private float angle; private ResourceVirtualArrayObject verticesVBO; - private static final int INDICE_VBO_POSITIONS = 0; - private static final int INDICE_VBO_TEXTURE_COORDINATES = 1; - private static final int INDICE_VBO_NORMALS = 2; - private static final int INDICE_VBO_COLORS = 3; + + @Override public void onCreate(Context _context) { this.canDraw = true; @@ -41,16 +31,9 @@ public class MainApplication extends Application { this.angle = 0.0f; this.GLprogram = ResourceProgram.create(new Uri("DATA", "basic.vert"), new Uri("DATA", "basic.frag")); if (this.GLprogram != null) { - //this.GLPosition = this.GLprogram.getAttribute("EW_coord3d"); - //this.GLColor = this.GLprogram.getAttribute("EW_color"); - this.GLMatrixTransformation = this.GLprogram.getUniform("EW_MatrixTransformation"); - this.GLMatrixProjection = this.GLprogram.getUniform("EW_MatrixProjection"); - this.GLMatrixView = this.GLprogram.getUniform("EW_MatrixView"); - -// this.GLprogram.bindAttribute(INDICE_VBO_POSITIONS, "position"); -// //this.GLprogram.bindAttribute(INDICE_VBO_TEXTURE_COORDINATES, "textureCoords"); -// //this.GLprogram.bindAttribute(INDICE_VBO_NORMALS, "normal"); -// this.GLprogram.bindAttribute(INDICE_VBO_COLORS, "colors"); + this.GLMatrixTransformation = this.GLprogram.getUniform("matrixTransformation"); + this.GLMatrixProjection = this.GLprogram.getUniform("matrixProjection"); + this.GLMatrixView = this.GLprogram.getUniform("matrixView"); } float[] vertices = { @@ -81,7 +64,7 @@ public class MainApplication extends Application { @Override public void onDraw(Context _context) { this.angle += 0.01; - Log.info("==> appl Draw ..."); + //Log.info("==> appl Draw ..."); Vector2f size = getSize(); // set the basic openGL view port: (position drawed in the windows) OpenGL.setViewPort(new Vector2f(0,0), size); @@ -111,52 +94,39 @@ public class MainApplication extends Application { Matrix4f viewMatrix = OpenGL.getCameraMatrix(); //Matrix4f tmpMatrix = projMatrix * camMatrix; + this.verticesVBO.bindForRendering(); this.GLprogram.uniformMatrix(this.GLMatrixView, viewMatrix); - this.GLprogram.uniformMatrix(this.GLMatrixTransformation, transforamtionMatrix); this.GLprogram.uniformMatrix(this.GLMatrixProjection, projectionMatrix); - // position: - //this.GLprogram.sendAttributePointer2(this.GLPosition, this.verticesVBO, INDICE_VBO_VERTICES); - //glEnableVertexAttribArray - // color: - //this.GLprogram.sendAttributePointer2(this.GLColor, this.verticesVBO, INDICE_VBO_COLOR); - - GL30.glBindVertexArray(this.verticesVBO.getGLID()); - GL20.glEnableVertexAttribArray(INDICE_VBO_POSITIONS); - GL20.glEnableVertexAttribArray(INDICE_VBO_COLORS); + // Change the position for each element with the same pipeline you need to render ... + this.GLprogram.uniformMatrix(this.GLMatrixTransformation, transforamtionMatrix); + // Request the draw od the elements: - //OpenGL.drawArrays(OpenGL.RenderMode.triangle, 0, 3 /*number of points*/); - Log.warning("Draw 3 points"); - //GL11.glDrawElements(GL11.GL_TRIANGLES, 3 /*number of points*/, GL11.GL_UNSIGNED_INT, 0); - GL11.glDrawElements(GL11.GL_TRIANGLES, 3, GL11.GL_UNSIGNED_INT, 0); - - GL20.glDisableVertexAttribArray(INDICE_VBO_COLORS); - GL20.glDisableVertexAttribArray(INDICE_VBO_POSITIONS); - GL30.glBindVertexArray(0); + this.verticesVBO.render(OpenGL.RenderMode.triangle); + + this.verticesVBO.unBindForRendering(); this.GLprogram.unUse(); // Restore context of matrix OpenGL.pop(); this.markDrawingIsNeeded(); } @Override - public void onPointer(Type _type, - int _pointerID, - Vector2f _pos, - Status _state) { - /* - Log.info("input event: type=" + _type); - Log.info(" id=" + _pointerID); - Log.info(" pos=" + _pos); - Log.info(" state=" + _state); - */ + public void onPointer(Type type, + int pointerID, + Vector2f pos, + Status state) { +// Log.info("input event: type=" + type); +// Log.info(" id=" + pointerID); +// Log.info(" pos=" + pos); +// Log.info(" state=" + state); } @Override - public void onKeyboard( Special _special, - Keyboard _type, - Character _value, - Status _state) { - Log.info("Keyboard event: special=" + _special); - Log.info(" type=" + _type); - Log.info(" value='" + _value + "'"); - Log.info(" state=" + _state); + public void onKeyboard( Special special, + Keyboard type, + Character value, + Status state) { + Log.info("Keyboard event: special=" + special); + Log.info(" type=" + type); + Log.info(" value='" + value + "'"); + Log.info(" state=" + state); } } diff --git a/src/org/atriaSoft/gale/test/sample1/basic.vert b/src/org/atriaSoft/gale/test/sample1/basic.vert index a4f2905..31c4de6 100644 --- a/src/org/atriaSoft/gale/test/sample1/basic.vert +++ b/src/org/atriaSoft/gale/test/sample1/basic.vert @@ -8,14 +8,14 @@ precision mediump int; // Input: attribute vec3 position; attribute vec4 colors; -uniform mat4 EW_MatrixTransformation; -uniform mat4 EW_MatrixProjection; -uniform mat4 EW_MatrixView; +uniform mat4 matrixTransformation; +uniform mat4 matrixProjection; +uniform mat4 matrixView; // output: varying vec4 f_color; void main(void) { - gl_Position = EW_MatrixProjection * EW_MatrixView * EW_MatrixTransformation * vec4(position, 1.0); + gl_Position = matrixProjection * matrixView * matrixTransformation * vec4(position, 1.0); f_color = colors; } diff --git a/src/org/atriaSoft/gale/test/sample2/Log.java b/src/org/atriaSoft/gale/test/sample2/Log.java new file mode 100644 index 0000000..f069a03 --- /dev/null +++ b/src/org/atriaSoft/gale/test/sample2/Log.java @@ -0,0 +1,29 @@ +package org.atriaSoft.gale.test.sample2; + +public class Log { + private static String LIBNAME = "Sample1"; + public static void print(String data) { + System.out.println(data); + } + public static void critical(String data) { + System.out.println("[C] " + LIBNAME + " | " + data); + } + public static void error(String data) { + System.out.println("[E] " + LIBNAME + " | " + data); + } + public static void warning(String data) { + System.out.println("[W] " + LIBNAME + " | " + data); + } + public static void info(String data) { + System.out.println("[I] " + LIBNAME + " | " + data); + } + public static void debug(String data) { + System.out.println("[D] " + LIBNAME + " | " + data); + } + public static void verbose(String data) { + System.out.println("[V] " + LIBNAME + " | " + data); + } + public static void todo(String data) { + System.out.println("[TODO] " + LIBNAME + " | " + data); + } +} diff --git a/src/org/atriaSoft/gale/test/sample2/MainApplication.java b/src/org/atriaSoft/gale/test/sample2/MainApplication.java new file mode 100644 index 0000000..3698ce3 --- /dev/null +++ b/src/org/atriaSoft/gale/test/sample2/MainApplication.java @@ -0,0 +1,193 @@ +package org.atriaSoft.gale.test.sample2; + +import org.atriaSoft.etk.Color; +import org.atriaSoft.etk.Uri; +import org.atriaSoft.etk.math.Matrix4f; +import org.atriaSoft.etk.math.Vector2f; +import org.atriaSoft.etk.math.Vector3f; +import org.atriaSoft.gale.Application; +import org.atriaSoft.gale.backend3d.OpenGL; +import org.atriaSoft.gale.context.Context; +import org.atriaSoft.gale.resource.ResourceProgram; +import org.atriaSoft.gale.resource.ResourceTexture; +import org.atriaSoft.gale.resource.ResourceVirtualArrayObject; +import org.atriaSoft.gale.tools.ImageLoader; +import org.atriaSoft.gale.tools.ImageRawData; +import org.atriaSoft.gale.key.Keyboard; +import org.atriaSoft.gale.key.Special; +import org.atriaSoft.gale.key.Status; +import org.atriaSoft.gale.key.Type; + +public class MainApplication extends Application { + private ResourceProgram GLprogram; + private int GLMatrixTransformation; + private int GLMatrixProjection; + private int GLMatrixView; + private float angleX = 0; + private float angleY = 0; + private float angleZ = 0; + private ResourceVirtualArrayObject verticesVBO; + private ResourceTexture texture; + + + @Override + public void onCreate(Context _context) { + this.canDraw = true; + setSize(new Vector2f(800, 600)); + this.GLprogram = ResourceProgram.create(new Uri("DATA", "basic.vert"), new Uri("DATA", "basic.frag")); + if (this.GLprogram != null) { + this.GLMatrixTransformation = this.GLprogram.getUniform("matrixTransformation"); + this.GLMatrixProjection = this.GLprogram.getUniform("matrixProjection"); + this.GLMatrixView = this.GLprogram.getUniform("matrixView"); + } + + float[] vertices = { + -0.5f,0.5f,-0.5f, + -0.5f,-0.5f,-0.5f, + 0.5f,-0.5f,-0.5f, + 0.5f,0.5f,-0.5f, + + -0.5f,0.5f,0.5f, + -0.5f,-0.5f,0.5f, + 0.5f,-0.5f,0.5f, + 0.5f,0.5f,0.5f, + + 0.5f,0.5f,-0.5f, + 0.5f,-0.5f,-0.5f, + 0.5f,-0.5f,0.5f, + 0.5f,0.5f,0.5f, + + -0.5f,0.5f,-0.5f, + -0.5f,-0.5f,-0.5f, + -0.5f,-0.5f,0.5f, + -0.5f,0.5f,0.5f, + + -0.5f,0.5f,0.5f, + -0.5f,0.5f,-0.5f, + 0.5f,0.5f,-0.5f, + 0.5f,0.5f,0.5f, + + -0.5f,-0.5f,0.5f, + -0.5f,-0.5f,-0.5f, + 0.5f,-0.5f,-0.5f, + 0.5f,-0.5f,0.5f + + }; + + float[] textureCoords = { + 0,0, 0,1, 1,1, 1,0, + 0,0, 0,1, 1,1, 1,0, + 0,0, 0,1, 1,1, 1,0, + 0,0, 0,1, 1,1, 1,0, + 0,0, 0,1, 1,1, 1,0, + 0,0, 0,1, 1,1, 1,0 + }; + + int[] indices = { + 0,1,3, 3,1,2, + 4,5,7, 7,5,6, + 8,9,11, 11,9,10, + 12,13,15, 15,13,14, + 16,17,19, 19,17,18, + 20,21,23, 23,21,22 + + }; + // this is the properties of the buffer requested : "r"/"w" + "-" + buffer type "f"=float "i"=integer + this.verticesVBO = ResourceVirtualArrayObject.create(vertices, textureCoords, null, indices); + if (this.verticesVBO == null) { + Log.error("can not instanciate VBO ..."); + return; + } + // TO facilitate some debugs we add a name of the VBO: + this.verticesVBO.setName("[VBO] of basic SAMPLE"); + // update all the VBO elements ... + this.verticesVBO.flush(); + + this.texture = ResourceTexture.createFromPng(new Uri("DATA", "tree_sample.png")); + if (this.texture == null) { + Log.error("can not instanciate Texture ..."); + return; + } + Log.info("==> Init APPL (END)"); + } + @Override + public void onDraw(Context _context) { + this.angleX += 0.001; + this.angleY += 0.005; + this.angleZ += 0.01; + //Log.info("==> appl Draw ..."); + Vector2f size = getSize(); + //Log.info("==> Windows size = " + size); + // set the basic openGL view port: (position drawed in the windows) + OpenGL.setViewPort(new Vector2f(0,0), size); + // Clear all the stacked matrix ... + OpenGL.setBasicMatrix(Matrix4f.identity()); + // clear background + Color bgColor = new Color(0.0f, 1.0f, 1.0f, 0.75f); + OpenGL.enable(OpenGL.Flag.flag_depthTest); + OpenGL.clearColor(bgColor); + // real clear request: + OpenGL.clear(OpenGL.ClearFlag.clearFlag_colorBuffer); + OpenGL.clear(OpenGL.ClearFlag.clearFlag_depthBuffer); + // create a local matrix environnement. + OpenGL.push(); + + //Matrix4f tmpProjection = Matrix4f.createMatrixOrtho(-getAspectRatio(), getAspectRatio(), -1, 1, -50, 50); + Matrix4f tmpProjection = Matrix4f.createMatrixPerspective(1.30f, getAspectRatio(), 1, 50); + // set internal matrix system: + OpenGL.setMatrix(tmpProjection); + if (this.GLprogram == null) { + Log.info("No shader ..."); + return; + } + //EWOL_DEBUG(" display " + this.coord.size() + " elements" ); + this.GLprogram.use(); + + // set Matrix : translation/positionMatrix + Matrix4f projectionMatrix = tmpProjection; //OpenGL.getMatrix(); + Matrix4f transforamtionMatrix = Matrix4f.identity(); + transforamtionMatrix.multiply(Matrix4f.createMatrixTranslate(new Vector3f(0,0,-1))); + transforamtionMatrix.multiply(Matrix4f.createMatrixRotate(new Vector3f(1,0,0),this.angleX)); + transforamtionMatrix.multiply(Matrix4f.createMatrixRotate(new Vector3f(0,1,0),this.angleY)); + transforamtionMatrix.multiply(Matrix4f.createMatrixRotate(new Vector3f(0,0,1),this.angleZ)); + Matrix4f viewMatrix = OpenGL.getCameraMatrix().multiply_new(Matrix4f.createMatrixTranslate(new Vector3f(0,0,-2))); + //Matrix4f tmpMatrix = projMatrix * camMatrix; + this.verticesVBO.bindForRendering(); + this.GLprogram.uniformMatrix(this.GLMatrixView, viewMatrix); + this.GLprogram.uniformMatrix(this.GLMatrixProjection, projectionMatrix); + // Change the position for each element with the same pipeline you need to render ... + this.GLprogram.uniformMatrix(this.GLMatrixTransformation, transforamtionMatrix); + this.texture.bindForRendering(0); + // update of flags is done asyncronously ==> need update befor drawing... + OpenGL.updateAllFlags(); + // Request the draw od the elements: + this.verticesVBO.render(OpenGL.RenderMode.triangle); + + this.verticesVBO.unBindForRendering(); + this.texture.unBindForRendering(); + this.GLprogram.unUse(); + // Restore context of matrix + OpenGL.pop(); + this.markDrawingIsNeeded(); + } + @Override + public void onPointer(Type type, + int pointerID, + Vector2f pos, + Status state) { +// Log.info("input event: type=" + type); +// Log.info(" id=" + pointerID); +// Log.info(" pos=" + pos); +// Log.info(" state=" + state); + } + @Override + public void onKeyboard( Special special, + Keyboard type, + Character value, + Status state) { + Log.info("Keyboard event: special=" + special); + Log.info(" type=" + type); + Log.info(" value='" + value + "'"); + Log.info(" state=" + state); + } +} diff --git a/src/org/atriaSoft/gale/test/sample2/basic.frag b/src/org/atriaSoft/gale/test/sample2/basic.frag new file mode 100644 index 0000000..a347c03 --- /dev/null +++ b/src/org/atriaSoft/gale/test/sample2/basic.frag @@ -0,0 +1,17 @@ +#version 400 core + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +in vec2 out_textureCoords; + +uniform sampler2D textureBase; + +// output: +out vec4 out_Color; + +void main(void) { + out_Color = texture(textureBase, out_textureCoords); +} diff --git a/src/org/atriaSoft/gale/test/sample2/basic.vert b/src/org/atriaSoft/gale/test/sample2/basic.vert new file mode 100644 index 0000000..439636f --- /dev/null +++ b/src/org/atriaSoft/gale/test/sample2/basic.vert @@ -0,0 +1,21 @@ +#version 400 core + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input: +in vec3 position; +in vec2 textureCoords; +uniform mat4 matrixTransformation; +uniform mat4 matrixProjection; +uniform mat4 matrixView; + +// output: +out vec2 out_textureCoords; + +void main(void) { + gl_Position = matrixProjection * matrixView * matrixTransformation * vec4(position, 1.0); + out_textureCoords = textureCoords; +} diff --git a/src/org/atriaSoft/gale/test/sample2/sample_2.java b/src/org/atriaSoft/gale/test/sample2/sample_2.java new file mode 100644 index 0000000..c84632b --- /dev/null +++ b/src/org/atriaSoft/gale/test/sample2/sample_2.java @@ -0,0 +1,11 @@ +package org.atriaSoft.gale.test.sample2; + +import org.atriaSoft.etk.Uri; +import org.atriaSoft.gale.Gale; + +public class sample_2 { + public static void main(String[] args) { + Uri.setGroup("DATA", "src/org/atriaSoft/gale/test/sample2/"); + Gale.run(new MainApplication(), args); + } +} diff --git a/src/org/atriaSoft/gale/test/sample2/tree_sample.png b/src/org/atriaSoft/gale/test/sample2/tree_sample.png new file mode 100644 index 0000000000000000000000000000000000000000..fbc22918d75033d5a54e1c0d6e3ab2020128272e GIT binary patch literal 99816 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


7{}o8+=)OqOcIR(SsFx0 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 Q`2YX_07*qoM6N<$g1oX!jQ{`u literal 0 HcmV?d00001 diff --git a/src/org/atriaSoft/gale/tools/ImageLoader.java b/src/org/atriaSoft/gale/tools/ImageLoader.java new file mode 100644 index 0000000..589dcfa --- /dev/null +++ b/src/org/atriaSoft/gale/tools/ImageLoader.java @@ -0,0 +1,49 @@ +package org.atriaSoft.gale.tools; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +import org.atriaSoft.etk.Uri; +import org.atriaSoft.gale.test.sample2.Log; + +import de.matthiasmann.twl.utils.PNGDecoder; +import de.matthiasmann.twl.utils.PNGDecoder.Format; + +public class ImageLoader { + + public static ImageRawData decodePngFile(Uri filename) { + ByteBuffer buf = null; + int tWidth = 0; + int tHeight = 0; + boolean hasAlpha = false; + try { + // Open the PNG file as an InputStream + InputStream in = new FileInputStream(filename.get()); + // Link the PNG decoder to this stream + PNGDecoder decoder = new PNGDecoder(in); + // Get the width and height of the texture + tWidth = decoder.getWidth(); + tHeight = decoder.getHeight(); + hasAlpha = decoder.hasAlpha(); + // Decode the PNG file in a ByteBuffer + if (hasAlpha == true) { + buf = ByteBuffer.allocateDirect(4 * decoder.getWidth() * decoder.getHeight()); + //decoder.decodeFlipped(buf, decoder.getWidth() * 4, Format.RGBA); + decoder.decode(buf, decoder.getWidth() * 4, Format.RGBA); + } else { + buf = ByteBuffer.allocateDirect(3 * decoder.getWidth() * decoder.getHeight()); + //decoder.decodeFlipped(buf, decoder.getWidth() * 4, Format.RGBA); + decoder.decode(buf, decoder.getWidth() * 3, Format.RGB); + } + buf.flip(); + in.close(); + } catch (IOException e) { + e.printStackTrace(); + System.err.println("try to load texture " + filename + ", didn't work"); + System.exit(-1); + } + return new ImageRawData(buf, tWidth, tHeight, hasAlpha); + } +} diff --git a/src/org/atriaSoft/gale/tools/ImageRawData.java b/src/org/atriaSoft/gale/tools/ImageRawData.java new file mode 100644 index 0000000..246e4ae --- /dev/null +++ b/src/org/atriaSoft/gale/tools/ImageRawData.java @@ -0,0 +1,34 @@ +package org.atriaSoft.gale.tools; + +import java.nio.ByteBuffer; + +public class ImageRawData { + + private int width; + private int height; + private ByteBuffer buffer; + private boolean hasAlpha; + + public ImageRawData(ByteBuffer buffer, int width, int height, boolean hasAlpha){ + this.buffer = buffer; + this.width = width; + this.height = height; + this.hasAlpha = hasAlpha; + } + + public int getWidth(){ + return width; + } + + public int getHeight(){ + return height; + } + + public ByteBuffer getBuffer(){ + return buffer; + } + + public boolean isHasAlpha() { + return hasAlpha; + } +} diff --git a/src/org/atriaSoft/gameEngine/Engine.java b/src/org/atriaSoft/gameEngine/Engine.java index 477bde2..ab49220 100644 --- a/src/org/atriaSoft/gameEngine/Engine.java +++ b/src/org/atriaSoft/gameEngine/Engine.java @@ -1,5 +1,7 @@ package org.atriaSoft.gameEngine; +import java.util.List; + import org.atriaSoft.gameEngine.camera.Camera; public abstract class Engine { @@ -34,5 +36,6 @@ public abstract class Engine { * @param[in] camera Camera property to render the engine properties ... */ public abstract void renderDebug(long deltaMili, Camera camera); + public abstract String getType(); } diff --git a/src/org/atriaSoft/gameEngine/Entity.java b/src/org/atriaSoft/gameEngine/Entity.java index b9467be..4b4c53b 100644 --- a/src/org/atriaSoft/gameEngine/Entity.java +++ b/src/org/atriaSoft/gameEngine/Entity.java @@ -226,24 +226,24 @@ public abstract class Entity { * @param[in,out] draw Basic system to draw the debug shape and informations * @param[in] camera Current camera for display */ - public void drawDebug(Colored3DObject draw, Camera camera) { - /* - mdebugText.clear(); - mdebugText.setColor(etk::Color<>(0x00, 0xFF, 0x00, 0xFF)); - mdebugText.setPos(Vector3f(-20,32,0)); - mdebugText.print(getType()); - mdebugText.setPos(Vector3f(-20,20,0)); - mdebugText.print("life=("+etk::toString(getLifeRatio())); - */ - //mdebugText.print(String("Axe=(")+String(mtmpAxe.x())+String(",")+etk::UString(mtmpAxe.y())+etk::UString(",")+etk::UString(m_tmpAxe.z())+etk::UString(")")); - /* - // TODO : Keep this it can be usefull to print something in direction of the camera ... - mdebugText.draw( etk::matTranslate(getPosition()) - * etk::matRotate(Vector3f(0,0,1),camera.getAngleZ()) - * etk::matRotate(Vector3f(1,0,0),(MPI/2.0f-camera.getAngleTeta())) - * etk::matScale(Vector3f(0.05,0.05,0.05))); - */ - } +// public void drawDebug(Colored3DObject draw, Camera camera) { +// /* +// mdebugText.clear(); +// mdebugText.setColor(etk::Color<>(0x00, 0xFF, 0x00, 0xFF)); +// mdebugText.setPos(Vector3f(-20,32,0)); +// mdebugText.print(getType()); +// mdebugText.setPos(Vector3f(-20,20,0)); +// mdebugText.print("life=("+etk::toString(getLifeRatio())); +// */ +// //mdebugText.print(String("Axe=(")+String(mtmpAxe.x())+String(",")+etk::UString(mtmpAxe.y())+etk::UString(",")+etk::UString(m_tmpAxe.z())+etk::UString(")")); +// /* +// // TODO : Keep this it can be usefull to print something in direction of the camera ... +// mdebugText.draw( etk::matTranslate(getPosition()) +// * etk::matRotate(Vector3f(0,0,1),camera.getAngleZ()) +// * etk::matRotate(Vector3f(1,0,0),(MPI/2.0f-camera.getAngleTeta())) +// * etk::matScale(Vector3f(0.05,0.05,0.05))); +// */ +// } /** * @brief Event arrive when an Entity has been remove from the system == > this permit to keep pointer of ennemy, and not search them every cycle ... * @param[in] removedEntity Pointer on the Entity removed. diff --git a/src/org/atriaSoft/gameEngine/Environement.java b/src/org/atriaSoft/gameEngine/Environement.java index 55f065e..9282d1d 100644 --- a/src/org/atriaSoft/gameEngine/Environement.java +++ b/src/org/atriaSoft/gameEngine/Environement.java @@ -6,6 +6,10 @@ import java.util.List; import java.util.Map; import org.atriaSoft.gameEngine.camera.Camera; +import org.atriaSoft.gameEngine.engines.EngineRender; +import org.atriaSoft.gameEngine.engines.EngineAI; +import org.atriaSoft.gameEngine.engines.EngineParticle; +import org.atriaSoft.gameEngine.engines.EnginePhysics; import org.atriaSoft.gameEngine.resource.Mesh; public class Environement { @@ -24,7 +28,7 @@ public class Environement { public Environement() { // we add the 4 classical engines (the order is used to the global rendering cycle ... addEngine(new EnginePhysics(this)); - addEngine(new EngineIA(this)); + addEngine(new EngineAI(this)); addEngine(new EngineRender(this)); addEngine(new EngineParticle(this)); } @@ -70,8 +74,8 @@ public class Environement { public void engineComponentRemove(Component ref) { for (Engine it: engine) { - if (it->getType() == ref->getType()) { - it->componentRemove(ref); + if (it.getType().contentEquals(ref.getType())) { + it.componentRemove(ref); return; } } @@ -79,8 +83,8 @@ public class Environement { public void engineComponentAdd(Component ref) { for (Engine it: engine) { - if (it->getType() == ref->getType()) { - it->componentAdd(ref); + if (it.getType().contentEquals(ref.getType())) { + it.componentAdd(ref); return; } } @@ -101,7 +105,7 @@ public class Environement { if(it == null) { continue; } - Log.verbose(" render: " + it->getType()); + Log.verbose(" render: " + it.getType()); it.renderDebug(deltaMilli, camera); } @@ -244,13 +248,13 @@ public class Environement { for (int iii=0; iiigetPosition(); + Vector3f destPosition = mlistEntity[iii].getPosition(); float dist = (sourcePosition - destPosition).length; if (dist == 0 || dist>decreasePower) { continue; } float inpact = (decreasePower-dist)/decreasePower * power; - glistEntity[iii]->setFireOn(groupIdSource, type, -inpact, sourcePosition); + glistEntity[iii].setFireOn(groupIdSource, type, -inpact, sourcePosition); */ } @@ -278,7 +282,7 @@ public class Environement { // for (auto it : mlistCamera) { // if (it.second != null) { // EGEVERBOSE(" update camera : '" + it.first + "'"); -// it.second->periodicCall(curentDelta); +// it.second.periodicCall(curentDelta); // } // } // EGEVERBOSE(" step simulation : " + curentDelta); @@ -286,8 +290,8 @@ public class Environement { // if(it == null) { // continue; // } -// EGEVERBOSE(" update: " + it->getType()); -// it->update(echrono::Duration(double(curentDelta))); +// EGEVERBOSE(" update: " + it.getType()); +// it.update(echrono::Duration(double(curentDelta))); // } // // //EGE.debug("stepSimulation (start)"); @@ -305,12 +309,12 @@ public class Environement { // auto it(mlistEntity.begin()); // while (it != mlistEntity.end()) { // if(*it != null) { -// if ((*it)->needToRemove() == true) { -// if ((*it)->getGroup() > 1) { +// if ((*it).needToRemove() == true) { +// if ((*it).getGroup() > 1) { // numberEnnemyKilled++; // victoryPoint++; // } -// EGEINFO("[" + (*it)->getUID() + "] entity Removing ... " + (*it)->getType()); +// EGEINFO("[" + (*it).getUID() + "] entity Removing ... " + (*it).getType()); // rmEntity((*it)); // it = mlistEntity.begin(); // } else { @@ -359,7 +363,7 @@ public class Environement { * 99999999999.0f; result.entity = null; for (int iii=0; iiigetPosition(); if (sourcePosition == + * destPosition = result.entity.getPosition(); if (sourcePosition == * destPosition) { continue; } result.dist = (sourcePosition - * destPosition).length(); //EGE.debug("Distance : " + distance + " >? " + * distance + " id=" + iii); if (distanceMax>result.dist) { @@ -370,9 +374,9 @@ public class Environement { * resultList.clear(); Environement::ResultNearestEntity result; result.dist = * 99999999999.0f; result.entity = null; for (int iii=0; iiiisFixed() == false) + * (result.entity == null) { continue; } if (result.entity.isFixed() == false) * { continue; } // check distance ... Vector3f destPosition = - * result.entity->getPositionTheoric(); result.dist = (sourcePosition - + * result.entity.getPositionTheoric(); result.dist = (sourcePosition - * destPosition).length(); //EGE.debug("Distance : " + distance + " >? " + * distance + " id=" + iii); if (distanceMax <= result.dist) { continue; } // * try to add the entity at the best positions: int jjj; for (jjj=0; diff --git a/src/org/atriaSoft/gameEngine/Signal.java b/src/org/atriaSoft/gameEngine/Signal.java index 7cdfc1a..ddd3f80 100644 --- a/src/org/atriaSoft/gameEngine/Signal.java +++ b/src/org/atriaSoft/gameEngine/Signal.java @@ -1,5 +1,12 @@ package org.atriaSoft.gameEngine; -public class Signal { +import org.atriaSoft.etk.math.Transform3D; + +public class Signal { + + public void emit(TYPE transform) { + // TODO Auto-generated method stub + + } } diff --git a/src/org/atriaSoft/gameEngine/components/ComponentAI.java b/src/org/atriaSoft/gameEngine/components/ComponentAI.java new file mode 100644 index 0000000..5c9b2bf --- /dev/null +++ b/src/org/atriaSoft/gameEngine/components/ComponentAI.java @@ -0,0 +1,12 @@ +package org.atriaSoft.gameEngine.components; + +import org.atriaSoft.gameEngine.Component; + +public class ComponentAI extends Component { + + @Override + public String getType() { + // TODO Auto-generated method stub + return null; + } +} diff --git a/src/org/atriaSoft/gameEngine/components/ComponentParticle.java b/src/org/atriaSoft/gameEngine/components/ComponentParticle.java new file mode 100644 index 0000000..82ccab6 --- /dev/null +++ b/src/org/atriaSoft/gameEngine/components/ComponentParticle.java @@ -0,0 +1,12 @@ +package org.atriaSoft.gameEngine.components; + +import org.atriaSoft.gameEngine.Component; + +public class ComponentParticle extends Component { + + @Override + public String getType() { + // TODO Auto-generated method stub + return null; + } +} diff --git a/src/org/atriaSoft/gameEngine/component/ComponentPosition.java b/src/org/atriaSoft/gameEngine/components/ComponentPosition.java similarity index 76% rename from src/org/atriaSoft/gameEngine/component/ComponentPosition.java rename to src/org/atriaSoft/gameEngine/components/ComponentPosition.java index 4e7b61a..0dd2c83 100644 --- a/src/org/atriaSoft/gameEngine/component/ComponentPosition.java +++ b/src/org/atriaSoft/gameEngine/components/ComponentPosition.java @@ -1,22 +1,24 @@ -package org.atriaSoft.gameEngine.component; +package org.atriaSoft.gameEngine.components; +import org.atriaSoft.etk.math.Transform3D; import org.atriaSoft.gameEngine.Component; +import org.atriaSoft.gameEngine.Log; +import org.atriaSoft.gameEngine.Signal; -public class ComponentPosition { - public Component { +public class ComponentPosition extends Component { public Signal signalPosition; protected Transform3D transform; /** * @brief Create a basic position component (no orientation and position (0,0,0)) */ - public Component() { + public ComponentPosition() { transform = Transform3D.identity(); } /** * @brief Create a basic position component * @param[in] transform transformation of the position */ - public Component(Transform3D transform) { + public ComponentPosition(Transform3D transform) { this.transform = transform; } /** @@ -27,7 +29,7 @@ public class ComponentPosition { if (this.transform.isEqual(transform)) { return; } - transform = transform; + this.transform = transform; signalPosition.emit(this.transform); } /** diff --git a/src/org/atriaSoft/gameEngine/components/ComponentRender.java b/src/org/atriaSoft/gameEngine/components/ComponentRender.java new file mode 100644 index 0000000..0be9bc3 --- /dev/null +++ b/src/org/atriaSoft/gameEngine/components/ComponentRender.java @@ -0,0 +1,13 @@ +package org.atriaSoft.gameEngine.components; + +import org.atriaSoft.gameEngine.Component; + +public class ComponentRender extends Component { + + @Override + public String getType() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/org/atriaSoft/gameEngine/components/CoponentPhysics.java b/src/org/atriaSoft/gameEngine/components/CoponentPhysics.java new file mode 100644 index 0000000..356b534 --- /dev/null +++ b/src/org/atriaSoft/gameEngine/components/CoponentPhysics.java @@ -0,0 +1,12 @@ +package org.atriaSoft.gameEngine.components; + +import org.atriaSoft.gameEngine.Component; + +public class CoponentPhysics extends Component { + + @Override + public String getType() { + // TODO Auto-generated method stub + return null; + } +} diff --git a/src/org/atriaSoft/gameEngine/engines/EngineAI.java b/src/org/atriaSoft/gameEngine/engines/EngineAI.java new file mode 100644 index 0000000..b94b070 --- /dev/null +++ b/src/org/atriaSoft/gameEngine/engines/EngineAI.java @@ -0,0 +1,51 @@ +package org.atriaSoft.gameEngine.engines; + +import org.atriaSoft.gameEngine.Component; +import org.atriaSoft.gameEngine.Engine; +import org.atriaSoft.gameEngine.Environement; +import org.atriaSoft.gameEngine.camera.Camera; + +public class EngineAI extends Engine { + + public EngineAI(Environement env) { + super(env); + // TODO Auto-generated constructor stub + } + + @Override + public void componentRemove(Component ref) { + // TODO Auto-generated method stub + + } + + @Override + public void componentAdd(Component ref) { + // TODO Auto-generated method stub + + } + + @Override + public void update(long deltaMili) { + // TODO Auto-generated method stub + + } + + @Override + public void render(long deltaMili, Camera camera) { + // TODO Auto-generated method stub + + } + + @Override + public void renderDebug(long deltaMili, Camera camera) { + // TODO Auto-generated method stub + + } + + @Override + public String getType() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/org/atriaSoft/gameEngine/engines/EngineParticle.java b/src/org/atriaSoft/gameEngine/engines/EngineParticle.java new file mode 100644 index 0000000..33ffe90 --- /dev/null +++ b/src/org/atriaSoft/gameEngine/engines/EngineParticle.java @@ -0,0 +1,52 @@ +package org.atriaSoft.gameEngine.engines; + +import org.atriaSoft.gameEngine.Component; +import org.atriaSoft.gameEngine.Engine; +import org.atriaSoft.gameEngine.Environement; +import org.atriaSoft.gameEngine.camera.Camera; + +public class EngineParticle extends Engine { + + public EngineParticle(Environement env) { + super(env); + // TODO Auto-generated constructor stub + } + + @Override + public void componentRemove(Component ref) { + // TODO Auto-generated method stub + + } + + @Override + public void componentAdd(Component ref) { + // TODO Auto-generated method stub + + } + + @Override + public void update(long deltaMili) { + // TODO Auto-generated method stub + + } + + @Override + public void render(long deltaMili, Camera camera) { + // TODO Auto-generated method stub + + } + + @Override + public void renderDebug(long deltaMili, Camera camera) { + // TODO Auto-generated method stub + + } + + @Override + public String getType() { + // TODO Auto-generated method stub + return null; + } + + +} diff --git a/src/org/atriaSoft/gameEngine/engines/EnginePhysics.java b/src/org/atriaSoft/gameEngine/engines/EnginePhysics.java new file mode 100644 index 0000000..ac381d0 --- /dev/null +++ b/src/org/atriaSoft/gameEngine/engines/EnginePhysics.java @@ -0,0 +1,51 @@ +package org.atriaSoft.gameEngine.engines; + +import org.atriaSoft.gameEngine.Component; +import org.atriaSoft.gameEngine.Engine; +import org.atriaSoft.gameEngine.Environement; +import org.atriaSoft.gameEngine.camera.Camera; + +public class EnginePhysics extends Engine { + + public EnginePhysics(Environement env) { + super(env); + // TODO Auto-generated constructor stub + } + + @Override + public void componentRemove(Component ref) { + // TODO Auto-generated method stub + + } + + @Override + public void componentAdd(Component ref) { + // TODO Auto-generated method stub + + } + + @Override + public void update(long deltaMili) { + // TODO Auto-generated method stub + + } + + @Override + public void render(long deltaMili, Camera camera) { + // TODO Auto-generated method stub + + } + + @Override + public void renderDebug(long deltaMili, Camera camera) { + // TODO Auto-generated method stub + + } + + @Override + public String getType() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/org/atriaSoft/gameEngine/engines/EngineRender.java b/src/org/atriaSoft/gameEngine/engines/EngineRender.java new file mode 100644 index 0000000..5e54d83 --- /dev/null +++ b/src/org/atriaSoft/gameEngine/engines/EngineRender.java @@ -0,0 +1,51 @@ +package org.atriaSoft.gameEngine.engines; + +import org.atriaSoft.gameEngine.Component; +import org.atriaSoft.gameEngine.Engine; +import org.atriaSoft.gameEngine.Environement; +import org.atriaSoft.gameEngine.camera.Camera; + +public class EngineRender extends Engine { + + public EngineRender(Environement env) { + super(env); + // TODO Auto-generated constructor stub + } + + @Override + public void componentRemove(Component ref) { + // TODO Auto-generated method stub + + } + + @Override + public void componentAdd(Component ref) { + // TODO Auto-generated method stub + + } + + @Override + public void update(long deltaMili) { + // TODO Auto-generated method stub + + } + + @Override + public void render(long deltaMili, Camera camera) { + // TODO Auto-generated method stub + + } + + @Override + public void renderDebug(long deltaMili, Camera camera) { + // TODO Auto-generated method stub + + } + + @Override + public String getType() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/org/atriaSoft/gameEngine/sample/lowPoly/sample_lowPoly.java b/src/org/atriaSoft/gameEngine/sample/lowPoly/sample_lowPoly.java new file mode 100644 index 0000000..822dd33 --- /dev/null +++ b/src/org/atriaSoft/gameEngine/sample/lowPoly/sample_lowPoly.java @@ -0,0 +1,5 @@ +package org.atriaSoft.gameEngine.sample.lowPoly; + +public class sample_lowPoly { + +} diff --git a/src/shaders/ShaderProgram.java b/src/shaders/ShaderProgram.java index 13ebf0b..49e36c3 100644 --- a/src/shaders/ShaderProgram.java +++ b/src/shaders/ShaderProgram.java @@ -38,10 +38,10 @@ public abstract class ShaderProgram { } public void start() { - OpenGL.useProgram(programID); + OpenGL.programUse(programID); } public void stop() { - OpenGL.unUseProgram(programID); + OpenGL.programUnUse(programID); } public void cleanUp() { stop();