Solution below
I'm trying to disable the clamping of colors, but it does not work. There are the same OpenGL calls, such as a comparable c++ program where they work. To disable the clamping I use the following code:
GL30.glClampColor(GL30.GL_CLAMP_READ_COLOR, GL11.GL_FALSE);
GL30.glClampColor(GL30.GL_CLAMP_VERTEX_COLOR, GL11.GL_FALSE);
GL30.glClampColor(GL30.GL_CLAMP_FRAGMENT_COLOR, GL11.GL_FALSE);
For a better understanding the full code below and also a test class. As you can see, there is a test in swap if the values are below zero. I think the buffer is a floating point buffer and also the clamping is disabled. So I have no clue why it doesn't work. Any suggestions?
Canvas.java:
package render;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import javax.imageio.ImageIO;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.Pbuffer;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.util.glu.GLU;
public class Canvas {
private final int m_width;
private final int m_height;
private Pbuffer m_buffer;
private final FloatBuffer m_readBuffer;
private final float[] m_data;
private final FloatBuffer m_dataBuffer;
public Canvas(final int width, final int height) {
this.m_width = width;
this.m_height = height;
this.m_data = new float[this.m_width * this.m_height * 4];
this.m_dataBuffer = FloatBuffer.wrap(this.m_data);
this.m_readBuffer = BufferUtils.createFloatBuffer(this.m_data.length);
}
public void disable() {
GL11.glPopClientAttrib();
GL11.glPopAttrib();
}
public void disable2D() {
GL11.glPopAttrib();
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPopMatrix();
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPopMatrix();
}
public void enable() {
GL11.glPushClientAttrib(GL11.GL_CLIENT_VERTEX_ARRAY_BIT);
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL30.glClampColor(GL30.GL_CLAMP_READ_COLOR, GL11.GL_FALSE);
GL30.glClampColor(GL30.GL_CLAMP_VERTEX_COLOR, GL11.GL_FALSE);
GL30.glClampColor(GL30.GL_CLAMP_FRAGMENT_COLOR, GL11.GL_FALSE);
}
public void enable2D(final int x, final int y, final int width,
final int height) {
GL11.glViewport(0, 0, this.m_width, this.m_height);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPushMatrix();
GL11.glLoadIdentity();
GLU.gluOrtho2D(0, this.m_width, 0, this.m_height);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPushMatrix();
GL11.glLoadIdentity();
GL11.glPushAttrib(GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDisable(GL11.GL_LIGHTING);
}
public void init() {
try {
if ((Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0) {
System.out.println("Canvas:: No PBuffer support!");
System.exit(-1);
}
final PixelFormat pf = new PixelFormat();
pf.withBitsPerPixel(32);
pf.withFloatingPoint(true);
this.m_buffer = new Pbuffer(this.m_width, this.m_height, pf, null);
this.m_buffer.makeCurrent();
} catch (final LWJGLException e) {
System.err.println("Canvas:: Cannot create buffer!");
e.printStackTrace();
System.exit(-1);
}
if (this.m_buffer.isBufferLost()) {
this.m_buffer.destroy();
System.err.println("Canvas:: Buffer was lost!");
System.exit(-1);
}
System.out.printf("Canvas:: Created canvas (%d %d)\n", this.m_width,
this.m_height);
}
public void swap() {
synchronized (this.m_dataBuffer) {
GL11.glReadPixels(0, 0, this.m_width, this.m_height, GL11.GL_RGBA,
GL11.GL_FLOAT, this.m_readBuffer);
while (this.m_readBuffer.remaining() > 0) {
final float t = this.m_readBuffer.get();
if (t < 0) {
System.out.println(t);
}
this.m_dataBuffer.put(t);
}
this.m_dataBuffer.rewind();
this.m_readBuffer.rewind();
}
}
}
CanvasTest.java:
package OpenGLTests;
import org.lwjgl.opengl.GL11;
import render.Canvas;
public class CanvasTest {
public static void main(final String[] args) {
final Canvas canvas = new Canvas(100, 100);
canvas.init();
canvas.enable2D(0, 0, 100, 100);
canvas.enable();
GL11.glClearColor(-1, -1, -1, 1);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glColor4f(-1, -1, 1, 1);
GL11.glBegin(GL11.GL_TRIANGLES);
GL11.glVertex2f(0.f, 0.f);
GL11.glVertex2f(100.f, 0.f);
GL11.glVertex2f(50.f, 100.f);
GL11.glEnd();
canvas.swap();
canvas.disable();
canvas.disable2D();
System.out.println("end");
}
}
Solution
Now I fixed the problem by using a FBO. I haven't known the difference between FBO and PBO (Pbuffer). But the PBO is apparently outdated and old, and don't support values, which are out of range. So you can see the initialization code of the fbo in the init() method below. Don't forget to bind the FBO when you use it.
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, this.m_fbo);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.m_color);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL30.GL_RGBA32F, this.m_width,
this.m_height, 0, GL11.GL_RGBA, GL11.GL_FLOAT,
(FloatBuffer) null);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,
GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER,
GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S,
GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T,
GL11.GL_CLAMP);
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER,
GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, this.m_color, 0);
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
Try using:
glClampColorARB(GL_CLAMP_READ_COLOR_ARB, GL_FALSE);
glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE);
glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE);
I'm also having problems with lwjgl/unclamped color/floating point framebuffers, but at least
for using glColor3f(2.0F, 1.0F, 1.0F) or such this seems to work (without framebuffers being
involved.) However, as far as I can tell you don't actually have a floating point framebuffer in there, so what this code will do is carry out the color multiplication and then clamp it to [0F, 1F]. This is desired because anything else will be undisplayable, but if you do end up creating an unclamped float framebuffer then you'll need to use GL_RGBA16F as the format and GL_FLOAT as the data type. I have a bit of a lack of understanding of this floating point
FBO stuff (as is shown by the fact I haven't figured it out myself) but nonetheless this has worked for me up to a point. I know some people only need the vertex color set to false, but I'm using all three calls to be sure it works. By the way, for lwjgl these can be found in org.lwjgl.opengl.ARBColorBufferFloat.
GL_FIXED_ONLY_ARB can be used in place of GL_FALSE. Just make sure that your buffer you're rendering to is floating point, since fixed-only will only unclamp if your buffer is floating point - integer (unsigned byte to be precise) is the default.
Just to reiterate once more, however, you won't be able to actually find the outside-of-bounds color results by reading the main display buffer - it'll be clamped, however you'll be able to see the results. As I've tried with those GL30 functions on my mac and it gave me errors to the tune of "unsupported", ARB works for me - but not with framebuffers. I don't understand why but for your purposes I think this will work.
If anyone knows I'm drastically wrong, please correct me.
EDIT: My problems with framebuffers were simply due to my own stupidity. HDR floating-point framebuffers can have HDR textures attached like so:
glTexImage2D(GL_TEXTURE_2D, 0, hdrEnabled ? hdrFormat : GL_RGBA8, width, height, 0, GL_RGB, hdrEnabled ? hdrDataType : GL_UNSIGNED_BYTE, (java.nio.ByteBuffer) null);
There's a little snippet from my code, hdrFormat is an int set to GL_RGBA16F and hdrDataType is set to GL_HALF_FLOAT.
Related
(This is the second time I am asking this question. Last time I got one answer that didn't solve it (the answer there referred a bit of code that was left accidentally from one of my attempts at fixing this). I also changed the question itself slightly - I changed the order of code to put the part where I believe the mistake higher is and added that I am using macOS, which might be the reason that it doesn't work).
So, I just started learning LWJGL 3 and I used a mixture of a couple of tutorials and example code to make something that should render a rectangle to a magenta screen using VAOs and VBOs. There are no errors but the rectangle doesn't appear on screen (all I can see is a magenta screen). I tried using the old LWJGL pipeline (glBegin() and glEnd()) and it does work so I tried changing random things in the rendering code and the loading to VAOs and VBOs. I also tried to bind the VBO too but it didn't change anything. I also tried debugging and it seems like there is a VAO and a VBO that is created.
Can someone take a look at my code and see if something looks wrong? Here it is (sorry if its a bit messy. Like I said, I don't think the problem is in the Main or Window class but I have no idea about LWJGL so I wanted to put it here anyways. If you have time, please also look at them. Otherwise I would really appreciate it if you could look at the Loader and Renderer classes):
(Btw, I am using macOS, and I do have -XstartOnFirstThread on).
The Raw Model class:
package engine.io;
public class RawModel {
private int vaoID;
private int vertexCount;
public RawModel(int vaoID, int vertexCount) {
this.vaoID = vaoID;
this.vertexCount = vertexCount;
}
public int getVaoID() {
return vaoID;
}
public int getVertexCount() {
return vertexCount;
}
}
The loader class:
package engine.io;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.system.MemoryUtil;
public class Loader {
private List<Integer> vaos = new ArrayList<Integer>();
private List<Integer> vbos = new ArrayList<Integer>();
public RawModel loadToVAO(float[] positions) {
int vaoID = createVAO();
storeDataInAttributeList(0, positions);
unbindVAO();
return new RawModel(vaoID, positions.length/3);
}
private int createVAO() {
int vaoID = GL30.glGenVertexArrays();
vaos.add(vaoID);
GL30.glBindVertexArray(vaoID);
return vaoID;
}
private void storeDataInAttributeList(int attributeNumber, float[] data) {
int vboID = GL15.glGenBuffers();
vbos.add(vboID);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
FloatBuffer buffer = storeDataInFloatBuffer(data);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(attributeNumber, 3, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
private void unbindVAO() {
GL30.glBindVertexArray(0);
}
private FloatBuffer storeDataInFloatBuffer(float[] data) {
FloatBuffer buffer = MemoryUtil.memAllocFloat(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
public void cleanUp() {
for (int vao : vaos) {
GL30.glDeleteVertexArrays(vao);
}
for (int vbo : vbos) {
GL15.glDeleteBuffers(vbo);
}
}
}
The renderer class:
package engine.io;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
public class Renderer {
public void prepare() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
GL11.glClearColor(1f, 0f, 1f, 1f);
}
public void render(RawModel model) {
GL30.glBindVertexArray(model.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, model.getVertexCount());
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}
}
Here is the Main class:
import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.*;
import engine.io.Loader;
import engine.io.RawModel;
import engine.io.Renderer;
import engine.io.Window;
import java.nio.*;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.*;
import static org.lwjgl.system.MemoryUtil.*;
public class Main {
private Window window;
Loader loader = new Loader();
Renderer renderer = new Renderer();
float[] vertices = {
// Left bottom triangle
-0.5f, 0.5f, 0f,
-0.5f, -0.5f, 0f,
0.5f, -0.5f, 0f,
// Right top triangle
0.5f, -0.5f, 0f,
0.5f, 0.5f, 0f,
-0.5f, 0.5f, 0f
};
RawModel model;
public void run() {
setup();
loop();
loader.cleanUp();
glfwFreeCallbacks(window.getWindowNum());
glfwDestroyWindow(window.getWindowNum());
glfwTerminate();
glfwSetErrorCallback(null).free();
}
private void loop() {
while ( !glfwWindowShouldClose(window.getWindowNum()) ) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
renderer.render(model);
glfwSwapBuffers(window.getWindowNum()); // swap the color buffers
glfwPollEvents();
}
}
public void setup() {
window = new Window(900, 300, "Flappy Bird");
window.create();
GL.createCapabilities();
GLFW.glfwMakeContextCurrent(window.getWindowNum());
model = loader.loadToVAO(vertices);
renderer.prepare();
GL11.glViewport(0, 0, 900, 300);
}
public static void main(String[] args) {
new Main().run();
}
}
Here is the window class:
package engine.io;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.*;
import java.nio.IntBuffer;
//import static org.lwjgl.glfw.GLFW.*;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.system.MemoryStack;
public class Window {
private int width, height;
private String title;
private long window;
public Window(int width, int height, String title) {
this.width = width;
this.height = height;
this.title = title;
}
public void create() {
GLFWErrorCallback.createPrint(System.err).set();
if (!glfwInit())
throw new IllegalStateException("Unable to initialize GLFW");
// Configure GLFW
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
// Create the window
window = glfwCreateWindow(width, height, "Flappy Bird", NULL, NULL);
if (window == NULL)
throw new RuntimeException("Failed to create the GLFW window");
// Get the thread stack and push a new frame
try (MemoryStack stack = stackPush()) {
IntBuffer pWidth = stack.mallocInt(1); // int*
IntBuffer pHeight = stack.mallocInt(1); // int*
// Get the window size passed to glfwCreateWindow
glfwGetWindowSize(window, pWidth, pHeight);
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center the window
glfwSetWindowPos(window, (vidmode.width() - pWidth.get(0)) / 2, (vidmode.height() - pHeight.get(0)) / 2);
} // the stack frame is popped automatically
// Setup a key callback. It will be called every time a key is pressed, repeated
// or released.
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
});
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Enable v-sync
glfwSwapInterval(1);
// Make the window visible
glfwShowWindow(window);
}
public long getWindowNum() {
return window;
}
}
Since you are on MacOS, I recommend to set up a 3.2 core profile OpenGL Context. See OpenGL Development on OS X:
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Create the window
window = glfwCreateWindow(width, height, "Flappy Bird", NULL, NULL);
The problem
I am having trouble rendering absolutely anything with LWJGL 3.
It will not render anything, whilst creating the GLFW display and clearing the
color successfully.
The tools
Eclipse Neon (Java IDE)
LWJGL 3.1.1 build 16 with GLFW, JAWT and OPENGL bindings, natives.
The code
package init;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.nio.IntBuffer;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;
import org.lwjgl.system.MemoryStack;
import exception.ExceptionHandler;
import util.Time;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.*;
public class DisplayInstance {
public String title = "The SuperMatrix";
public GraphicsDevice gd;
public Game game;
public Config conf;
private long display;
private GLFWErrorCallback glfwerrorcallback;
public DisplayInstance(Game game) {
this.gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
this.game = game;
this.conf = Config.returnConfig(this);
this.glfwerrorcallback = GLFWErrorCallback.createPrint(System.err);
this.glfwerrorcallback.set();
this.start();
}
public void start() {
if (!glfwInit())
ExceptionHandler.handleException(new IllegalStateException("Cannot initialize GLFW"));
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
this.display = glfwCreateWindow(this.conf.width, this.conf.height, this.title, 0, 0);
if (this.display == 0L) {
ExceptionHandler.handleException(new RuntimeException("Cannot create GLFW window"));
}
System.out.println(this.display);
try (MemoryStack stack = stackPush()) {
IntBuffer pWidth = stack.mallocInt(1);
IntBuffer pHeight = stack.mallocInt(1);
glfwGetWindowSize(this.display, pWidth, pHeight);
GLFWVidMode mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(this.display,
(mode.width()-pWidth.get(0))/2,
(mode.height()-pHeight.get(0))/2
);
} catch (Exception e) {
ExceptionHandler.handleException(e);
}
glfwMakeContextCurrent(this.display);
glfwSwapInterval(1);
glfwShowWindow(this.display);
this.loop();
}
public void loop() {
GL.createCapabilities();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,this.conf.width, 0, this.conf.height, -1, 1);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST);
Time time = new Time();
while(!glfwWindowShouldClose(this.display)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwSwapBuffers(this.display);
glfwPollEvents();
glPushMatrix();
glBegin(GL_QUADS);
glColor3f(1,0,1);
glVertex2f(0, 0);
glVertex2f(0, 64);
glVertex2f(64, 64);
glVertex2f(64, 0);
glEnd();
glPopMatrix();
float deltaSeconds = time.getDelta()/Time.SECOND;
float fps = deltaSeconds;
System.out.println(fps);
}
this.destroy();
}
public void destroy() {
glfwFreeCallbacks(this.display);
glfwDestroyWindow(this.display);
glfwTerminate();
this.glfwerrorcallback.free();
this.game.stopGame();
}
}
Thank you. Absolutely any help would be appreciated.
Alright, I finally found the answer.
The cause of the problem
The problem was that I called glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) right before I called glfwSwapBuffers(this.display):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwSwapBuffers(this.display);
This essentially means that I clear the buffers right before I show them.
The fix
To fix this, all I had to do is move glfwSwapBuffers(this.display) down to after the glPopMatrix() call. Here is how the loop() function looks like now:
GL.createCapabilities();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,this.conf.width, 0, this.conf.height, -1, 1);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST);
Time time = new Time();
while(!glfwWindowShouldClose(this.display)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwPollEvents();
glPushMatrix();
glBegin(GL_QUADS);
glColor3f(1,0,1);
glVertex2f(0, 0);
glVertex2f(0, 64);
glVertex2f(64, 64);
glVertex2f(64, 0);
glEnd();
glPopMatrix();
glfwSwapBuffers(this.display);
float deltaSeconds = time.getDelta()/Time.SECOND;
float fps = deltaSeconds;
System.out.println(fps);
}
this.destroy();
Everybody, have a great day!
P.S. Please don't mind the FPS system, I'm still trying to figure it out.
I am attempting to learn more about displaying and interacting with graphics and GUI elements. As part of this, I have been following along with a Tower Defense Tutorial that uses LWJGL and Slick-Util: https://www.youtube.com/watch?v=rfR09erJu7U&list=PLFUqwj4q1Zr8GHs6bO4d6gxMGUh_2pcNg
Extending some things out a bit on my own, I am trying to draw some basic untextured shapes with textured shapes. I can get a 2d line to draw, however, it only appears when drawn after certain textured shapes are drawn, but doesn't appear after other textured shapes are drawn. I'm wondering what I don't understand that is causing this divergent behavior.
Here is my main class, LineTest.java:
package main;
import static helpers.Artist.BeginSession;
import static helpers.Artist.DrawQuadTex;
import static helpers.Artist.QuickLoad;
import static helpers.Artist.drawLine;
import org.lwjgl.opengl.Display;
import org.newdawn.slick.opengl.Texture;
import helpers.Artist;
public class LineTest {
public LineTest() {
BeginSession();
Texture bg = QuickLoad("bg");
//Texture bg = QuickLoad("exitbutton");
while(!Display.isCloseRequested()) {
DrawQuadTex(bg,0,0,Artist.WIDTH,Artist.HEIGHT);
drawLine(0,0,800,800);
Display.update();
Display.sync(60);
}
Display.destroy();
}
public static void main(String[] args) {
new LineTest();
}
}
And my helper class, Artist.java:
package helpers;
import static org.lwjgl.opengl.GL11.GL_BLEND;
import static org.lwjgl.opengl.GL11.GL_LINES;
import static org.lwjgl.opengl.GL11.GL_MODELVIEW;
import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
import static org.lwjgl.opengl.GL11.GL_PROJECTION;
import static org.lwjgl.opengl.GL11.GL_QUADS;
import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glBlendFunc;
import static org.lwjgl.opengl.GL11.glClearColor;
import static org.lwjgl.opengl.GL11.glClearDepth;
import static org.lwjgl.opengl.GL11.glColor4f;
import static org.lwjgl.opengl.GL11.glEnable;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glLoadIdentity;
import static org.lwjgl.opengl.GL11.glMatrixMode;
import static org.lwjgl.opengl.GL11.glOrtho;
import static org.lwjgl.opengl.GL11.glTexCoord2f;
import static org.lwjgl.opengl.GL11.glTranslatef;
import static org.lwjgl.opengl.GL11.glVertex2f;
import java.io.IOException;
import java.io.InputStream;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;
public class Artist {
public static final int WIDTH = 640, HEIGHT = 480;
public static void BeginSession() {
Display.setTitle("Line Test");
try {
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, WIDTH, HEIGHT, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
public static void drawLine(int x1, int y1, int x2, int y2) {
glColor4f(0.0f, 1.0f, 0.2f, 1.0f);
glBegin(GL_LINES);
glVertex2f((float) x1, (float) y1);
glVertex2f((float) x2, (float) y2);
glEnd();
glColor4f(1f,1f,1f,1f);
}
public static void DrawQuadTex(Texture tex, float x, float y, float width, float height) {
tex.bind();
glTranslatef(x, y, 0);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(1, 0);
glVertex2f(width, 0);
glTexCoord2f(1, 1);
glVertex2f(width, height);
glTexCoord2f(0,1);
glVertex2f(0, height);
glEnd();
glLoadIdentity();
}
public static Texture LoadTexture(String path, String fileType) {
Texture tex = null;
InputStream in = ResourceLoader.getResourceAsStream(path);
try {
tex = TextureLoader.getTexture(fileType, in);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
return tex;
}
public static Texture QuickLoad(String name) {
Texture tex = null;
tex = LoadTexture(name + ".png", "PNG");
return tex;
}
}
The important part of my problem is within the main class, right here:
Texture bg = QuickLoad("bg");
//Texture bg = QuickLoad("exitbutton");
while(!Display.isCloseRequested()) {
DrawQuadTex(bg,0,0,Artist.WIDTH,Artist.HEIGHT);
drawLine(0,0,800,800);
When my Texture bg is getting my 'bg' graphic (a solid black PNG file), the drawLine function doesn't seem to actually draw a line. However, if I change my Texture bg to get my 'exitbutton' graphic (a blue square with "Exit" written in it, still a PNG file) the drawLine function does create a visible line.
This imgur album contains the output for both: Texture bg = QuickLoad("bg"); & Texture bg = QuickLoad("exitbutton");
http://imgur.com/a/OVOzD
If necessary, I can also upload both PNG files that I using, but I currently cannot include more than 2 links in my question. bg.png is a mono-black 64x64 PNG. exitbutton.png is 512x512.
Just looking to understand what is causing this. Thank you!
The problem is most likely that you enable texturing in the BeginSession() method, and then keep it enabled for the whole rendering:
glEnable(GL_TEXTURE_2D);
This means that your lines will be textured. Now, you may say: "But... I'm not specifying texture coordinates for the lines!" That does not matter. The immediate mode rendering API in OpenGL is state based, so whichever texture coordinates were specified last are the ones used. Since you call DrawQuadTex() before drawLine(), the last texture coordinates specified in DrawQuadTex() will be your current texture coordinates when drawing the line:
glTexCoord2f(0,1);
So the color of the line will be the texel at position (0, 1) of the currently bound texture, modulated with the color specified for the line:
glColor4f(0.0f, 1.0f, 0.2f, 1.0f);
If the two colors multiplied together result in black, e.g. because the given texel is black, the result will be a black line on black background. Which looks a lot like not rendering anything at all.
The cleanest solution is to enable texturing only while drawing primitives that you want to texture, and disable it afterwards. For example, in the DrawQuadTex() method:
public static void DrawQuadTex(Texture tex, float x, float y, float width, float height) {
tex.bind();
glEnable(GL_TEXTURE_2D);
...
glDisable(GL_TEXTURE_2D);
}
A few hints on how to track down these types of problems, or avoid them altogether:
Set the clear color to something other than black during development. Then you can easily tell if you're rendering black geometry, or nothing at all.
Use shader based rendering. The fixed function pipeline may look easier at first, but it's really not. With shaders, the resulting color is exactly what you implement, not some magic combination of values based on a bunch of fixed state.
While you're at it, you may also want to avoid using immediate mode rendering. While not directly causing this problem, it's just as obsolete as using the fixed function pipeline.
I use eclipse. so in my workspace, under my project, i create a new folder "res" with a subfolder "images" that have all my png's for use as textures. so here is the method im using for loading the textures:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.newdawn.slick.Color;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;
import org.lwjgl.input.Mouse;
import java.util.Random;
public class TextureDemo
{
public int count = 0;
private static Texture wood;
Random random = new Random();
public TextureDemo()
{
initGL(640, 480, "SLICK TEXTURES");
loadTexture("mozilla");
int x = 100, y = 100, count = 0, width = 0, height = 0, counter = 10;
while(true)
{
count++;
if(count == counter)
{
x--; y--; width++; height++; counter += random.nextInt(50) + 1;
}
render(x, y, width, height);
Display.update();
Display.sync(60);
if(Display.isCloseRequested())
{
Display.destroy();
System.exit(0);
}
}
}
private void initGL(int width, int height, String title)
{
try
{
Display.setDisplayMode(new DisplayMode(width, height));
Display.setTitle(title);
Display.create();
}
catch(LWJGLException e)
{
e.printStackTrace();
Display.destroy();
System.exit(1);
}
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
GL11.glDisable(GL11.GL_COLOR_MATERIAL);
GL11.glLoadIdentity();
GL11.glOrtho(0, width, height, 0, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
public void loadTexture(String key)
{
try
{
wood = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("./res/images/"+key+".png"));
System.out.println("working." + wood.getTextureID());
}
catch(FileNotFoundException e)
{
e.printStackTrace();
Display.destroy();
System.exit(1);
}
catch(IOException e)
{
e.printStackTrace();
}
}
public void render(int x, int y, int width, int height)
{
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
System.out.println("working." + wood.getTextureID());
GL11.glBindTexture(GL11.GL_TEXTURE_2D, wood.getTextureID());
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(x, y);
GL11.glTexCoord2f(1, 0);
GL11.glVertex2f(x + wood.getImageWidth(), y);
GL11.glTexCoord2f(1, 1);
GL11.glVertex2f(x + wood.getImageWidth(), y + wood.getImageHeight());
GL11.glTexCoord2f(0, 1);
GL11.glVertex2f(x, y + wood.getImageHeight());
GL11.glEnd();
GL11.glDisable(GL11.GL_BLEND);
System.out.println(wood.getHeight()+ " " +wood.getWidth());
}
public static void main (String[] args)
{
new TextureDemo();
}
}
WHY WHY WHY are my textures black lol? I really don't understand how my code did this. Is it possible that my computer could have problems that are causing that?
Asking the same question twice won't help. However, you should make sure you first call glBindTexture, before you start glBegin.
I'm sorry, however there are many problems with your code. I would recommend taking a look at some opengl tutorials. The arcsynthesis one is very in-depth.
Your problem is that the texture "wood" is never bound to opengl.
In order to bind your texture to the opengl context you must call
glBindTexture(GL_TEXTURE_2D, id);
before glbegin()
The id is the texture id generated by glGentextures or in your case the slick util method.
Also what is wood? In the first code block it is the texture id but in the second block you are calling 'getHeght()' on type wood. I am confused as to what 'wood' is.
Either way, you need to bind the texture for opengl to use it and I again recommending looking at a few tutorials on the opengl basics.
You haven't enabled textures!
In your initGL method call GL11.glEnable(GL11.GL_TEXTURE_2D).
I'm learning OpenGL ES. When I'm using texture for triangle, I meet error. Here is my code:
package com.test;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.app.Activity;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLUtils;
import android.os.Bundle;
public class TexttureTriangleTest extends Activity{
GLSurfaceView glView;
ByteBuffer byteBuffer;
FloatBuffer vertices;
AssetManager assetManager;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
assetManager = getAssets();
int VERTEX_SIZE = (2+2)*4;
byteBuffer = ByteBuffer.allocateDirect(3*VERTEX_SIZE);
byteBuffer.order(ByteOrder.nativeOrder());
vertices = byteBuffer.asFloatBuffer();
vertices.put(new float[] { 0.0f, 0.0f, 1, 0, 0, 1,
319.0f, 0.0f, 0, 1, 0, 1,
160.0f, 479.0f, 0, 0, 1, 1});
vertices.flip();
glView = new GLSurfaceView(this);
glView.setRenderer(new Render());
setContentView(glView);
}
class Render implements Renderer{
#Override
public void onDrawFrame(GL10 gl) {
try { //I think error in this block of code
Bitmap bitmap = BitmapFactory.decodeStream(assetManager.open("bobrgb888.png"));
int textureIds[] = new int[1];
gl.glGenTextures(1, textureIds, 0);
int textureId = textureIds[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);
gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);
bitmap.recycle();
} catch (IOException e) {
throw new RuntimeException("couldn't load asset!");
}
gl.glViewport(0, 0, glView.getWidth(), glView.getHeight());
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(340, 0, 420, 0, 0, 0);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
int VERTEX_SIZE = (2+2)*4;
vertices.position(0);
gl.glVertexPointer(2, GL10.GL_FLOAT, VERTEX_SIZE, vertices);
vertices.position(2);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, VERTEX_SIZE, vertices);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
}
}
}
I think I have met error in function onDrawFrame and in block code try-catch. Who can verify it for me and teach me how to correct it, please.
thanks :)
I'm not a great expert in OpenGL but as far as I can see here are some mistakes in yor code.
At first it's a wrong size for byteBuffer
int VERTEX_SIZE = (2+2)*4;
byteBuffer = ByteBuffer.allocateDirect(3*VERTEX_SIZE);
For your vertices array your need 18 * 4 byte size. 18 is the number of floats in the vertices and 4 is number of bytes for every float in tha array.
In the second why do you think your error in try-catch?
Look for the error line in the log in IDE. Post it here and we can see the problem.
bobrgb888.png file must be present in assets folder.