Related
I try to render my image in RGBA4444 without converting to RGBA8888,but....
// Define vertices
float vertices[] = {-1.f, 1.f, 0.f, 0.f, 1.f, // left top
1.f, 1.f, 0.f, 1.f, 1.f, // right top
-1.f, -1.f, 0.f, 0.f, 0.f, // left bottom
1.f, -1.f, 0.f, 1.f, 0.f}; // right bottom
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, image.width, image.height, 0, GL_BGRA,
GL_UNSIGNED_SHORT_4_4_4_4_REV, image.pixels.data());
By default OpenGL assumes that the start of each row of an image is aligned to 4 bytes. This is because the GL_UNPACK_ALIGNMENT parameter by default is 4. Since a pixel of an image with the format GL_UNSIGNED_SHORT_4_4_4_4_REV only needs 2 bytes, the size of a row of the image may not be aligned to 4 bytes.
When the image is loaded to a texture object and 2*image.width is not divisible by 4, GL_UNPACK_ALIGNMENT has to be set to 2, before specifying the texture image with glTexImage2D:
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, image.width, image.height, 0, GL_BGRA,
GL_UNSIGNED_SHORT_4_4_4_4_REV, image.pixels.data());
I searched for this and only found a post from 2014 asking about a somewhat similar situation. However, as I couldn't understand what was done there, I'm asking again, specifically for my implementation, hoping this sheds some light on the topic in general as well. I am fairly new to c++ and openGL, so please be so kkind as to excuse stupid mistakes.
I'm trying to implement a simple 2D HUD for my 3D game. Now, my game is fully rendered, due to having a bloom effect in my game, I even rendered my game on a screen quad.
What I now want to do ist placing a HUD over this rendered scene, I, however, can't seem to do that.
My screen quad for the game is drawn like so:
unsigned int quadVAO = 0;
unsigned int quadVBO;
void renderQuad()
{
if (quadVAO == 0)
{
float quadVertices[] = {
// vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
// texCoords
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
// setup plane VAO
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
}
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
What I tried to do, ist change my renderQuad method to a renderHUDquad one by basically just changing the dimensions of the quad to make it appear in the bottom left corner of the screen.
The code looks as follows:
unsigned int HUDquadVAO = 0;
unsigned int HUDquadVBO;
void renderHUDQuad()
{
if (HUDquadVAO == 0)
{
float HUDquadVertices[] = {
// vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
// texCoords
0.0f, 0.02f,
0.0f, 0.0f,
0.2f, 0.0f,
0.0f, 0.02f,
0.2f, 0.0f,
0.2f, 0.02f
};
// setup plane VAO
glGenVertexArrays(1, &HUDquadVAO);
glGenBuffers(1, &HUDquadVBO);
glBindVertexArray(HUDquadVAO);
glBindBuffer(GL_ARRAY_BUFFER, HUDquadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(HUDquadVertices), &HUDquadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
}
glBindVertexArray(HUDquadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
As this only needs to be a small green quad, i.e. a health bar for the player, I was thinking about just assigning it a green texture or sth..
However, when drawing my two quads like this:
// Third pass = Combined bloom pictures
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
bloomShader->use();
// Set uniform for multiple layout uniforms
bloomShader->setUniform("scene", 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorAndLightBuffers[0]);
// Set uniform for multiple layout uniforms
bloomShader->setUniform("bloomBlur", 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, pingpongBuffer[horizontal == 0 ? 1 : 0]);
bloomShader->setUniform("bloom", bloom);
bloomShader->setUniform("exposure", exposure);
renderQuad();
renderHUDQuad();
// Swap buffers
glfwSwapBuffers(window);
I only get the HUD element without any of the stuff I drew before as if the rest of the screen was rendered black. I thought I could just add this to the old buffer, as there a way to do this?
You did screw up your GL state very badly:
void renderHUDQuad() {
if (HUDquadVAO == 0)
{
[...]
glGenVertexArrays(1, &quadVAO);
You actually use quadVAO in the rest of this function, so you overwrite your fullscreen quad by the smaller one, which means the rest of your scene will be scaled down to this quad from the next frame on...
I am writing a 3D graphics renderer in C++ using OpenGL-ES for a handheld system and I am utilizing a decal (texture) shader, as well as a color-fill shader. I have two render passes where I use the respective program and use Array/Element buffers to draw data using glDrawElements.
Although I enable GL_DEPTH_TEST in my application, my decal polygons always render in front of my color-filled polygons.
I have tried reworking how my projection/modelView matrices are built and passed to the shaders, I have tried different glDepthFunc parameters but I am not able to get them to render properly.
This is my draw code - I start each frame with
glClearColor(0.25f, 0.25f, 0.25f, 1.f);
glClearDepthf(1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Then I calculate world-space polygon coordinates and arrange it into GLfloat vectors. I draw the decal data first:
GLuint programId = decalProgramId;
glUseProgram(programId);
// All of my uniform params are setup here - omitting to save space
// Set proj/mv matrices
glUniformMatrix4fv(glGetUniformLocation(programId, "uProjection"), 1, GL_TRUE, static_cast<f32*>(gameEngine.proj));
glUniformMatrix4fv(glGetUniformLocation(programId, "uModelView"), 1, GL_TRUE, static_cast<f32*>(gameEngine.modelView));
// Then I prepare the buffer data
glBindBuffer(GL_ARRAY_BUFFER, decalBufferId);
glBufferData(GL_ARRAY_BUFFER, coordSize + texCoordSize, 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, coordSize, &coords[0]);
glBufferSubData(GL_ARRAY_BUFFER, coordSize, texCoordSize, &texCoords[0]);
// And element array buffer data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, decalElementBufferId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexSize, &indices[0], GL_STATIC_DRAW);
// Enable our vertex attributes
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(coordSize));
// Bind my test texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Draw the elements
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0);
The process is then repeated with my color polygons. Followed by SwapBuffer and WaitVSync commands.
Here is my code for creating one of the triangles and the front face of the cube:
// Add polygon directly to the scene object
scene.AddPolygon(polygonBuilder
.AddVertex(Vector3(0.5f, 0.5f, 0.f), Vector4(0.f, 0.f, 1.f, 1.f))
.AddVertex(Vector3(0.25f, 0.f, 0.f), Vector4(0.f, 1.f, 0.f, 1.f))
.AddVertex(Vector3(0.75f, 0.f, 0.f), Vector4(1.f, 0.f, 0.f, 1.f))
.AddIndex(0).AddIndex(1).AddIndex(2)
.Build()
);
// Create a polygon within the crate object
crateObject.AddPolygon(polygonBuilder
.AddVertex(Vector3(-0.25f, 0.25f, 0.f), Vector2(0.f, 0.f))
.AddVertex(Vector3(-0.25f, -0.25f, 0.f), Vector2(0.f, 1.f))
.AddVertex(Vector3(0.25f, -0.25f, 0.f), Vector2(1.f, 1.f))
.AddVertex(Vector3(0.25f, 0.25f, 0.f), Vector2(1.f, 0.f))
.SetTexture("crate")
.AddIndex(0).AddIndex(1).AddIndex(3)
.AddIndex(3).AddIndex(1).AddIndex(2)
.Build()
);
// Add the crate object as a child within the scene
scene.AddChild(crate);
This screenshot is the current output when I create two colored triangles and one textured cube:
The blue arrow indicates a triangle that should have rendered in the front. Any ideas?
I feel really silly now. My color shader was not properly applying the model-view matrix. It was always rendering at a fixed depth.
I modified my color shader code to apply the matrix the same way as the decal and now it works perfectly.
Cube rendering
Hey, i think there may be a mistake in either how i'm sending the data to the vertex or the way my indices are ordered with GL_CCW
struct Vertex
{
glm::vec3 position;
glm::vec3 color;
glm::vec3 normal;
};
Vertices using Vertex struct
Vertex vertices[] =
{
/*FRONT SQUARE*/
///BOTTOM LEFT
glm::vec3(-0.5f, -0.5f, 1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
///bottom RIGHT
glm::vec3(0.5f, -0.5f, 1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
////TOP RIGHT
glm::vec3(0.5f, 0.5f, 1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
///TOP LEFT
glm::vec3(-0.5f, 0.5f, 1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
///BOTTOM LEFT
glm::vec3(-0.5f, -0.5f, -1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
///bottom RIGHT
glm::vec3(0.5f, -0.5f, -1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
////TOP RIGHT
glm::vec3(0.5f, 0.5f, -1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
///TOP LEFT
glm::vec3(-0.5f, 0.5f, -1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f)
};
unsigned noOfVertices = sizeof(vertices) / sizeof(Vertex);
This is my indices ordering
GLuint indices[] =
{
// /front face
0, 1, 2,
2, 3, 0,
// right
1, 5, 6,
6, 2, 1,
// back
7, 6, 5,
5, 4, 7,
// left
4, 0, 3,
3, 7, 4,
// bottom
4, 5, 1,
1, 0, 4,
// top
3, 2, 6,
6, 7, 3
};
unsigned noOfIndices = sizeof(indices) / sizeof(GLuint);
Main function and initliase the window
int main()
{
Initiase window
///initialise GLFW for Window
if (glfwInit() == GLFW_FALSE)
{
std::cout << "ERROR::GLFW-INTI::FAILED" << "\n";
glfwTerminate();
}
///Create window with functions
GLFWwindow* window;
const int window_height = 480;
int window_width = 680;
int framebuffer_height = window_height;
int framebuffer_width = window_width;
char* title = "mytutorial";
int GLverMAJ = 3;
int GLverMin = 3;
///sets how the window should be drawn and which hints
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, GLverMAJ);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, GLverMin);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
///create the window with the previously set options
window = glfwCreateWindow(window_width, window_height, title, NULL, NULL);
//checks if window created
if (window == nullptr)
{
std::cout << "ERROR:::GLFWCREATEWINDOWFAILED" << "\n";
}
///sets the frame buffer size
glfwGetFramebufferSize(window, &framebuffer_width, &framebuffer_height);
glfwMakeContextCurrent(window);
//need to read on this part
glewExperimental = GL_TRUE;
//initiliase the glew
if (glewInit() != GLEW_OK)
{
std::cout << "ERROR::GLEWINIT::FAILED" << "\n";
}
initiliase opengl options
///enable functions first
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glEnable(GL_CULL_FACE);
//initialise the enabled functions
glCullFace(GL_BACK);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LESS);
///set the way its draw
glFrontFace(GL_CCW);
///set the polygon mode and fill ////Set as GL_LINE TO LOOK AT CUBE MESH
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
This is where i initialise the matrices the view, project and model
///initialise the matrices
///view
///front, position, up then use in lookat
glm::vec3 cameraPos(0.f, 0.f, 1.f);
glm::vec3 cameraUp(0.f, 1.f, 0.f);
glm::vec3 cameraFront(0.f, 0.f, -0.1f);
glm::mat4 ViewMatrix(1.f);
ViewMatrix = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
///set up prespective projection
float fov = 90.f;
float nearPlane = -1.f;
float farPlane = 1000.f;
///projection
glm::mat4 ProjectionMatrix(1.f);
ProjectionMatrix = glm::perspective(glm::radians(fov), static_cast<float>(framebuffer_width / framebuffer_height), nearPlane, farPlane);
//Model Matrix
glm::mat4 ModelMatrix(1.f);
Then i create my shaders
///set up SHADERS
char infolog[512];
GLint success;
GLuint Vertexshader = glCreateShader(GL_VERTEX_SHADER);
///std::string str_src =
std::string temp = "";
std::string src = "";
std::ifstream infile;
infile.open("vert.glsl");
if (infile.is_open())
{
while (std::getline(infile, temp))
src += temp + "\n";
}
infile.close();
const GLchar* source = src.c_str();
///link created shader with shader source
glShaderSource(Vertexshader, 1, &source, NULL);
glCompileShader(Vertexshader);
///error check compilation status
glGetShaderiv(Vertexshader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(Vertexshader, 512, NULL, infolog);
std::cout << infolog;
}
success = 0;
GLuint FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
///std::string str_src =
temp = "";
src = "";
infile.open("frag.glsl");
if (infile.is_open())
{
while (std::getline(infile, temp))
src += temp + "\n";
}
infile.close();
source = src.c_str();
///link created shader with shader source
glShaderSource(FragmentShader, 1, &source, NULL);
glCompileShader(FragmentShader);
///error check compilation status
glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(FragmentShader, 512, NULL, infolog);
std::cout << infolog;
}
Link the created shaders with the program
///create and link the program
success = 0;
GLuint programID;
programID = glCreateProgram();
glAttachShader(programID, Vertexshader);
glAttachShader(programID, FragmentShader);
glLinkProgram(programID);
glGetProgramiv(programID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(programID, 512, NULL, infolog);
std::cout << "ERROR::SHADER::COULD_NOT_LINK_PROGRAM" << "\n";
std::cout << infolog << "\n";
}
after linking unuse and delete buffers
///after linking we unuse the program and delete the shaders
glUseProgram(0);
glDeleteShader(Vertexshader);
glDeleteShader(FragmentShader);
This is where i initiliase VAO VBO AND EBO
///vbo, ebo and vertex array
GLuint VAO;
GLuint VBO;
GLuint EBO;
//gen and bind vao
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
///gen vbo
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, noOfVertices * sizeof(Vertex), vertices, GL_STATIC_DRAW);
///gen EBO
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, noOfIndices * sizeof(GLuint), indices, GL_STATIC_DRAW);
This is the part where i feel like there may be a problem
///tell buffer where data is located
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, position));
glEnableVertexAttribArray(0);
//colour
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, color));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, normal));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
///use program send in uniforms to the shader.
glUseProgram(programID);
///GLuint s = glGetUniformLocation(programID, "ViewMatrix");
GLuint s = glGetUniformLocation(programID, "ModelMatrix");
glUniformMatrix4fv(s, 1, GL_FALSE, glm::value_ptr(ModelMatrix));
s = glGetUniformLocation(programID, "ProjectionMatrix");
glUniformMatrix4fv(s, 1, GL_FALSE, glm::value_ptr(ProjectionMatrix));
s = glGetUniformLocation(programID, "ViewMatrix");
glUniformMatrix4fv(s, 1, GL_FALSE, glm::value_ptr(ViewMatrix));
glUseProgram(0);
///main while loop
while (!glfwWindowShouldClose(window))
{
//clear
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
///draw
glfwPollEvents();
glUseProgram(programID);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, noOfIndices, GL_UNSIGNED_INT, 0);
///flush
glfwSwapBuffers(window);
glFlush();
///unuse
glBindVertexArray(0);
glUseProgram(0);
}
return 0;
}
Both the near plane and the far plane have to be positive values for glm::perspective and static_cast<float>(framebuffer_width / framebuffer_height) would be an integral division:
float fov = 90.f;
float nearPlane = 0.1f; // 0.1 instead of -1.0
float farPlane = 1000.f;
glm::mat4 ProjectionMatrix(1.f);
ProjectionMatrix = glm::perspective(glm::radians(fov),
static_cast<float>(framebuffer_width) / static_cast<float>(framebuffer_height),
nearPlane, farPlane);
See glm::perspective:
GLM_FUNC_DECL mat<4, 4, T, defaultp> glm::perspective(
T fovy,
T aspect,
T near,
T far
)
[...]
near Specifies the distance from the viewer to the near clipping plane (always positive).
far Specifies the distance from the viewer to the far clipping plane (always positive).
The glm library provides matrix operations related to OpenGL and GLSL. The glm API documentation refers to The OpenGL Shading Language specification 4.20.
See The OpenGL Shading Language 4.6, 5.4.2 Vector and Matrix Constructors, page 101:
To initialize a matrix by specifying vectors or scalars, the components are assigned to the matrix elements in column-major order.
mat4(float, float, float, float, // first column
float, float, float, float, // second column
float, float, float, float, // third column
float, float, float, float); // fourth column
This means the transformation of the vertex coordinate in the vertex shader has to be:
gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * vec4(vertex_position,1.0);
See also GLSL Programming/Vector and Matrix Operations:
Likely the matrix can be transposed when set to the uniform, by setting the 3rd paramter of glUniformMatrix4fv to GL_TRUE:
GLuint s = glGetUniformLocation(programID, "ModelMatrix");
glUniformMatrix4fv(s, 1, GL_TRUE, glm::value_ptr(ModelMatrix));
s = glGetUniformLocation(programID, "ProjectionMatrix");
glUniformMatrix4fv(s, 1, GL_TRUE, glm::value_ptr(ProjectionMatrix));
s = glGetUniformLocation(programID, "ViewMatrix");
glUniformMatrix4fv(s, 1, GL_TRUE, glm::value_ptr(ViewMatrix));
And compute the vertex coordinate transformation in the reverse order:
gl_Position = vec4(vertex_position,1.0) * ModelMatrix * ViewMatrix * ProjectionMatrix;
Further, the winding order of the faces of the cube a is clockwise, so it has to be:
glFrontFace(GL_CCW);
glFrontFace(GL_CW);
Change the camera position to
glm::vec3 cameraPos(0.f, 0.f, 2.f);
and you'll get the following result:
To me, it would seem that your program is working correctly. If I'm not mistaken, then your camera is located inside the cube, looking straight from the position of one of the faces at the face on the other side. What you're seeing is exactly what one would expect to see in this case. In the center of the image you have the two triangles that make the backside of the face you're looking out of. The "weird lines" you get are simply the edges of the triangles that make the other faces. Since your camera is inside the cube, these faces necessarily reach all the way behind your camera and everything gets cut off at the near plane, which is where you get the outer rectangle from that "encloses" everything.
Everything is a bit squashed because this
static_cast<float>(framebuffer_width / framebuffer_height)
will not have the effect you most likely intend it to have. You are still performing an integer division here.
Also, I'm not sure what exactly you expect the effect of using a negative value for the near plane to be. Most likely, it's also not what you actually want, I suggest you use some positive value, e.g., 0.1f there… 😉
I have been attempting to transition my game's prototype renderer from it's immediate mode testing implementation to an actual VAO/VBO implementation. The VBO is rendering on screen, but is refusing to texture. Below is the simplest test class that shows the problem:
public static void main(String[] args) throws Exception {
// VertX,VertY TexX, TexY
float[] data = new float[] {0.0f, 0.0f, 0.25f, 0.75f,
0.0f, 64.0f, 0.25f, 1.0f,
64.0f, 64.0f, 0.5f, 1.0f,
0.0f, 0.0f, 0.25f, 0.75f,
64.0f, 64.0f, 0.5f, 1.0f,
64.0f, 0.0f, 0.5f, 0.75f};
glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.err));
if (!glfwInit())
throw new IllegalStateException("Unable to initialize GLFW");
long window = GLFW.glfwCreateWindow(1600, 900, "TEST", 0, 0);
GLFW.glfwMakeContextCurrent(window);
GL.createCapabilities();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1600, 900, 0, 0.000001, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
int vboId = glGenBuffers();
int vaoId = glGenVertexArrays();
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindVertexArray(vaoId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, data, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 4*Float.BYTES, 0);
glTexCoordPointer(2, GL_FLOAT, 4*Float.BYTES, 4*Float.BYTES);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glTranslatef(50, 50, 0);
Texture t = new Texture(TEST.class.getClassLoader().getResourceAsStream("test/WallFloor.png"));
while (!GLFW.glfwWindowShouldClose(window)) {
GLFW.glfwPollEvents();
GLFW.glfwSwapBuffers(window);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindVertexArray(vaoId);
glEnableVertexAttribArray(0);
t.bind();
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glBindVertexArray(0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
/* Equivelent immediate mode code - that works
t.bind();
glBegin(GL_TRIANGLES);
glTexCoord2f(0.25f, 0.75f);
glVertex2f(0, 0);
glTexCoord2f(0.25f, 1f);
glVertex2f(0, 64);
glTexCoord2f(0.5f, 0.75f);
glVertex2f(64, 0);
glTexCoord2f(0.5f, 1f);
glVertex2f(64, 64);
glTexCoord2f(0.25f, 1f);
glVertex2f(0, 64);
glTexCoord2f(0.5f, 0.75f);
glVertex2f(64, 0);
glEnd();
*/
}
}
The texture bind call is the following (where wrap = GL_REPEAT and filter = GL_NEAREST):
public void bind()
{
glActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(target, id);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap);
}
Having spent the weekend googling it an not finding an answer, am I doing something horribly wrong? I have also tested using immediate mode, which does still render with a texture.
In addition, you are mixing core profile code (glVertexAttribPointer) with non-core profile (glTexCoordPointer)
But the real problem comes from the wrong stride and offset used. Stride defines how large the data of one vertex is, while the offset specifies how far from the beginning of each vertex the actual data starts. In your case, every vertex consists of 4 floats thus the stride has to be 4 * Float.BYTES. The positions are the first two floats in each vertex (offset 0) while the texture coordinates are the 3rd and 4th floats which means offset = 2 * Float.BYTES. The correct code could look somehow like this (note the usage of glVertexPointer instead of glVertexAttribPointer):
glVertexPointer(2, GL_FLOAT, false, 4*Float.BYTES, 0);
glTexCoordPointer(2, GL_FLOAT, 4*Float.BYTES, 2*Float.BYTES);
Edit
The usage of your VAOs is also wrong. In the initialization you store the glVertexPointer/glTexCoordPointer to the VAO vaoId. But in the rendering code you bind VAO 0 instead. Most probably the attribute settings are not present when drawing. In addition, I'm not absolutely sure whether VAOs work together with fixed function calls. In this case you can remove all of the VAO calls.