package engine; import engine.camera.*; import engine.gui.UIDummy; import engine.input.*; import engine.math.*; import engine.object.*; import org.lwjgl.glfw.GLFWFramebufferSizeCallback; import org.lwjgl.glfw.GLFWVidMode; import org.lwjgl.opengl.GL; import java.util.ArrayList; import java.util.List; import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.system.MemoryUtil.NULL; public class Engine { private static long window; private final List objectsGl; public final List uiElements; private boolean running; private final int width; private final int height; private final boolean fullscreen; private float viewXPos; private float viewYPos; private Vector3f transformationView; private final Camera camera; private TrackingDummy tracking; /* Init Method */ /** * Create the engine and initial attributes use .init() to start the engine * Initial projection is -1000;1000 in width and -1000*aspectRatio; 1000*aspectRatio * Initial Camera position is (0, 0, -1) //TODO vérifiez */ public Engine(int width, int height, boolean fullscreen, Vector3f aspectRatio) { this.running = false; this.objectsGl = new ArrayList<>(); this.uiElements = new ArrayList<>(); this.width = width; this.height = height; this.viewXPos = 0.0f; this.viewYPos = 0.0f; this.camera = new Camera(1000, aspectRatio, this); ObjectGl.view = Matrix4f.translate(new Vector3f(0.0f, 0.0f, 1.0f)); this.transformationView = new Vector3f(); this.tracking = null; this.fullscreen = fullscreen; } /** * Start the engine * Create the window * Set the color of the background */ public void init() { if (!glfwInit()){ System.exit(-1); } this.running = true; glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //On utilise la version 3.3 d'openGL glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); //Compatible MAC glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //Le core profile est l'interface 'avancé' d'openGL int width = this.width; int height = this.height; if (fullscreen) { this.setWindow(glfwCreateWindow(width, height, "Boulevard Combattant", glfwGetPrimaryMonitor(), NULL)); } else { this.setWindow(glfwCreateWindow(width, height, "Boulevard Combattant", NULL, NULL)); } assert getWindow() != NULL; // On récupère les informations du moniteur principal GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor()); assert vidmode != null; // On met la fenêtre au centre de l'écran principale glfwSetWindowPos(getWindow(), (vidmode.width() - width) / 2, (vidmode.height() - height) / 2); glfwSetKeyCallback(getWindow(), new KeyboardInput()); glfwSetInputMode(getWindow(), GLFW_STICKY_KEYS, GLFW_TRUE); // Contexte = zone cible des rendus glfwMakeContextCurrent(getWindow()); glfwShowWindow(getWindow()); GL.createCapabilities(); correctViewport(this.width, this.height); glfwSetFramebufferSizeCallback(getWindow(), resizeWindow); glEnable(GL_DEPTH_TEST); // Z-Buffer plus z est grand plus l'objet est proche de la camera limite à 100.0f au dela l'objet disparait glEnable(GL_BLEND); // Transparence glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); System.out.println("OpenGL: " + glGetString(GL_VERSION)); } /* RENDER / UPDATE */ public void render() { glEnable(GL_SCISSOR_TEST); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); objectsGl.sort(new SortZ()); for (ObjectGl objectGl : objectsGl) { objectGl.render(); } int error = glGetError(); if (error != GL_NO_ERROR) System.out.println(error); glfwSwapBuffers(getWindow()); //Envoie le buffer vers le moniteur } /** * */ public void update() { glfwPollEvents(); // METS A JOUR LA POSITION DES ELEMENTS D'INTERFACE for (UIDummy uiElement : this.uiElements){ uiElement.update(); } } /* Window / Viewport Management */ public static void correctViewport(int width, int height){ int heightViewport, widthViewport, x, y; if (width >= height * 4.0f/3.0f){ heightViewport = height; widthViewport = (int) (height * 4.0f/3.0f); y = 0; x = (width - widthViewport)/2; } else { widthViewport = width; heightViewport = (int) (width * 3.0f/4.0f); y = (height - heightViewport)/2; x = 0; } glScissor(x, y, widthViewport, heightViewport); glViewport(x, y, widthViewport, heightViewport); } public boolean shouldClose() { return glfwWindowShouldClose(getWindow()); } /* ObjectGl Management */ /** * Add obj to the render queue * @param obj ObjectGl to render */ public void add_objectGl(ObjectGl obj) { this.objectsGl.add(obj); } public void add_objectsGl(List objs) { this.objectsGl.addAll(objs); } public void remove_objectGl(ObjectGl obj) { obj.delete(); this.objectsGl.remove(obj); } public void remove_objectsGl(List obj) { this.objectsGl.removeAll(obj); } /* UIElement Management */ public void add_uiElement(UIDummy uiElement) { uiElement.init(); this.uiElements.add(uiElement); } public void remove_uiElement(UIDummy uiElement) { this.uiElements.remove(uiElement); uiElement.delete(); } public void setUIElementZoomFactor(float scaleFactor){ for (UIDummy uiElement : this.uiElements){ uiElement.updateScalingFactor(scaleFactor); } } /* CAMERA */ public void translateView(Vector3f vec){ ObjectGl.view = ObjectGl.view.multiply(Matrix4f.translate(vec)); viewXPos += vec.x; this.transformationView = this.transformationView.addXYZ(vec); } /** * Translate la camera pour avoir obj au centre de l'image, comme le cadrage se fait sur le point en haut à gauche * de l'objet un offset peut parfois être nécessaire * @param obj l'objectGl que la camera va suivre * @param xOffset un offSet sur l'axe X */ public void cameraTrackingObjectGl(ObjectGl obj, float xOffset){ Vector3f trackingVector = new Vector3f((- obj.getXPos() - this.viewXPos) + xOffset,0.0f ,0.0f); this.translateView(trackingVector); } public void setCameraTrackingBetweenTwoObjectGl(ObjectGl obj1, ObjectGl obj2, float deadZone){ // obj2 est considéré à droite probablement à modifier this.tracking = new TrackingTore( deadZone, obj1, obj2, this); } public void setCameraTrackingSF3ThirdStrike(ObjectGl obj1, ObjectGl obj2){ this.tracking = new TrackingSF3ThirdStrick(obj1, obj2, this); } public void cameraTracking(){ if (this.tracking == null) System.out.println("Define a tracking first"); else { Vector3f trackingVector = this.tracking.getViewVector(); this.translateView(trackingVector); } } /* CALLBACK */ /** * Est appelé à chaque modification de la taille de la fenêtre, et modifie la taille de la zone de rendu * pour quelle corresponde à la taille de la fenêtre */ private static final GLFWFramebufferSizeCallback resizeWindow = new GLFWFramebufferSizeCallback() { @Override public void invoke(long window, int width, int height) { correctViewport(width, height); } }; /* GET/SET */ public boolean getRunning() { return running; } public void setRunning(boolean b) { running = b; } public float getViewXPos(){ return viewXPos; } public float getViewYPos(){ return viewYPos; } public Vector3f getTransformationView() { return transformationView; } public Camera getCamera(){ return this.camera; } public static long getWindow() { return window; } public void setWindow(long window) { Engine.window = window; } }