package engine.object; import engine.graphics.*; import engine.math.*; import static org.lwjgl.glfw.GLFW.glfwGetTime; /** * */ public class ObjectGl { /** * STATE CONST DECLARATION */ public static final int DEFAULT = 0, STICK_BOTTOM = 1, STICK_TOP = 2; private int stick_state; protected VertexArray vertexArray; protected Shader shader; protected Matrix4f transform; /** * Projection and view matrix are set by the engine do not modify */ public static Matrix4f projection; public static Matrix4f view; /** * xPos and yPos will stop to be relevant if you use rotate function */ private float xPos; private float yPos; private float zPos; private float xAngle; private float yAngle; private float zAngle; private float width; // To be used in setTextureWrap private float height; private float scalingFactor; public boolean useTime; private Texture texture; private float[] textureWrap; /** * Create a rectangle shape, use setTextureWrap to correctly align the texture with the model * @param z depth of your model the larger it is the more it will be "close" to the camera * @param w height of the rectangle * @param h width of the rectangle * @param size scaling factor of the rectangle, the model could not show up because this value is too small or too large, a good compromise is between 2 and 15 * @param tex set to null if you don't want a tex on your model * @param color set to null if you don't want a Color on your model */ public ObjectGl(float z, float w, float h, float size, String tex, Vector3f color){ float[] colorBuffer = null; // Check des options if (color != null){ colorBuffer = new float[] { color.x, color.y, color.z, color.x, color.y, color.z, color.x, color.y, color.z, color.x, color.y, color.z }; } if (tex != null){ this.texture = new Texture(tex, 0); } this.xPos = 0.0f; this.yPos = 0.0f; this.zPos = z; this.height = h; this.width = w; this.textureWrap = Primitive.stdTexWrap; this.vertexArray = new VertexArray(Primitive.createRectangle(this.zPos, this.width, this.height), Primitive.rectangle_indices, colorBuffer, Primitive.stdTexWrap); this.scalingFactor = 1; this.transform = Matrix4f.identity(); this.scale(new Vector3f(size, size,1.0f)); this.stick_state = DEFAULT; this.useTime = false; // use different shader for each set of option if (tex == null && color == null){ this.shader = new Shader("shaders/ObjectGl/vert.glsl","shaders/ObjectGl/frag.glsl"); } else if (tex == null){ this.shader = new Shader("shaders/ObjectGlColor/vert.glsl","shaders/ObjectGlColor/frag.glsl"); } else if (color == null){ this.shader = new Shader("shaders/ObjectGlTex/vert.glsl","shaders/ObjectGlTex/frag.glsl"); } else { this.shader = new Shader("shaders/ObjectGlTexColor/vert.glsl","shaders/ObjectGlTexColor/frag.glsl"); } } /** * Reset the transform matrix, the model will appear at the 0.0.0 coordinate, his scaleFactor will be set to zero * Because the model is at position 0 on the z axis he will not show up on screen */ public void resetTransform(){ this.transform = Matrix4f.identity(); this.scalingFactor = 1; this.xPos = 0.0f; this.yPos = 0.0f; this.zPos = 0.0f; } /** * Move the object according to vec, direction can change if rotation method have been used * @param vec Vector3f */ public void translate(Vector3f vec){ this.xPos += vec.x; this.yPos += vec.y; this.zPos += vec.z; vec.divXY(this.scalingFactor); this.transform = this.transform.multiply(Matrix4f.translate(vec)); } /** * Scale the model with the vec vector, the x component is used to mitigate size modification in the behavior of other transformation method * @param vec Vector3f */ public void scale(Vector3f vec){ this.scalingFactor *= vec.x; this.transform = this.transform.multiply(Matrix4f.scale(vec)); } /** * rotate the model by angle degree on the local x axis, beware this will change the behavior of the translate method * @param angle in degree */ public void rotateX(float angle){ this.transform = this.transform.multiply(Matrix4f.rotateX(angle)); } /** * rotate the model by angle degree on the local y axis, beware this will change the behavior of the translate method * @param angle in degree */ public void rotateY(float angle){ this.transform = this.transform.multiply(Matrix4f.rotateY(angle)); } /** * rotate the model by angle degree on the local z axis, beware this will change the behavior of the translate method * @param angle in degree */ public void rotateZ(float angle){ this.transform = this.transform.multiply(Matrix4f.rotateZ(angle)); } /** * Set a new texture to be used on the model. You may need to use setTextureWrap tp get the correct wrap * @param texPath path to the new texture */ public void setTexture(String texPath){ this.texture = new Texture(texPath, 0); } /** * Change the wrapping coordinate * @param x starting wrapping on the horizontal axis * @param y starting wrapping on the vertical axis * @param w the length of the wrapping on the horizontal axis * @param h the length of the wrapping on the vertical axis */ public void setTextureWrap(float x, float y, float w, float h, int sticky){ // TODO set sticky property + precision issue if (this.stick_state != sticky){ // Check if we're using a new dimension if (sticky == STICK_BOTTOM){ this.stick_state = STICK_BOTTOM; this.translate(new Vector3f(0.0f, (h - this.height)*this.scalingFactor, 0.0f)); } else if (sticky == STICK_TOP){ this.stick_state = STICK_TOP; this.translate(new Vector3f(0.0f, (h - this.height)*this.scalingFactor, 0.0f)); } else { this.stick_state = DEFAULT; } } this.height = h; this.width = w; this.vertexArray.swapVertexBufferObject(Primitive.createRectangle(this.zPos, w, h)); int texWidth = this.texture.getWidth(); int texHeight = this.texture.getHeight(); x /= texWidth; w /= texWidth; y /= texHeight; h /= texHeight; float[] result = { x , y , x + w , y , x + w , y + h , x , y + h , }; this.setTextureWrap(result); } /** * Reverse the textureWrap left to right */ public void flipTextureWrapH(){ float[] textureWrapTemp = new float[] { this.textureWrap[2], this.textureWrap[3], this.textureWrap[0], this.textureWrap[1], this.textureWrap[6], this.textureWrap[7], this.textureWrap[4], this.textureWrap[5] }; setTextureWrap(textureWrapTemp); } /** * Set a new shader to be used by this object * @param vert path to glsl Vertex Shader * @param frag path to glsl Fragment Shader */ public void setShader(String vert, String frag){ this.shader = new Shader(vert, frag); } /** * Set a new Color for the object if the shader do not use the color attrib this will make no change. * @param color Vector3f r,g,b format */ public void setColor(Vector3f color){ float[] colorBuffer = new float[] { color.x, color.y, color.z, color.x, color.y, color.z, color.x, color.y, color.z, color.x, color.y, color.z }; this.vertexArray = new VertexArray(Primitive.createRectangle(this.zPos, this.width, this.height), Primitive.rectangle_indices, colorBuffer, Primitive.stdTexWrap); } private void setTextureWrap(float[] texture){ this.textureWrap = texture; this.vertexArray.swapTextureBufferObject(texture); } public float getXPos(){ return xPos; } public float getYPos(){ return yPos; } public float getZPos(){ return zPos; } /** * Do shader binding, texture binding and vertexArray drawing */ public void render(){ this.shader.enable(); if (this.texture != null) this.texture.bind(); if (this.useTime) this.shader.setUniform1f("time", (float) glfwGetTime()); this.shader.setUniformMat4f("projection", projection); this.shader.setUniformMat4f("view", view); this.shader.setUniformMat4f("transform", this.transform); this.vertexArray.render(); if (this.texture != null) this.texture.unbind(); this.shader.disable(); } }