Reputation: 1330
I'm trying to create a sample program that can be used as a test harness for OpenGL. The one I have so far seems to work, but it seems that the MVP matrix passed via the uniform variable MVPMatrix is ignored. When I added code to read the uniform back and check that it was actually updating properly, I get an invalid operation error when doing so and I can't see why - what's going on?
#include "stdafx.h"
#include <iostream>
#include <memory>
#include <sdl/SDL.h>
#include <assimp/Importer.hpp>
#include <assimp/mesh.h>
#include <assimp/scene.h>
#include <sdl/SDL_image.h>
#include <glm/glm.hpp>
#include <Windows.h>
#include <GL/glew.h>
#include <GL/GL.h>
#include <gl/GLU.h>
#include <vector>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <assimp/Importer.hpp>
#include <assimp/mesh.h>
#include <assimp/postprocess.h>
#include <assimp/vector3.h>
using namespace std;
void checkGLShaderStatus(GLuint id, GLuint thingToCheck, bool shader) {
GLint ret;
if (shader) glGetShaderiv(id, thingToCheck, &ret); else glGetProgramiv(id, thingToCheck, &ret);
// If there was an error
if (ret == GL_FALSE) {
// Print it out, then halt
GLint maxLength = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &maxLength);
GLchar *shaderErrorLog = (GLchar*)malloc(sizeof(GLchar)*(maxLength + 1));
glGetShaderInfoLog(id, maxLength, &maxLength, shaderErrorLog);
shaderErrorLog[maxLength] = '\0';
cout << shaderErrorLog;
free(shaderErrorLog);
int junk;
cin >> junk;
exit(EXIT_FAILURE);
}
}
GLuint buildShader(const GLchar **source, GLuint length, GLenum type) {
// Create the shader
GLuint shaderId = glCreateShader(type);
// Upload source code
glShaderSource(shaderId, length, source, NULL);
// Compile the shader
glCompileShader(shaderId);
// See how the compilation went
checkGLShaderStatus(shaderId, GL_COMPILE_STATUS, true);
return shaderId;
}
void checkGL(string stage) {
GLuint error = glGetError();
if (error != GL_NO_ERROR) {
cout << "OpenGL broke..";
switch (error) {
case GL_INVALID_ENUM:
cout << "Invalid Enum";
break;
case GL_INVALID_VALUE:
cout << "Value out of range";
break;
case GL_INVALID_OPERATION:
cout << "Invalid operation";
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
cout << "Incomplete framebuffer";
break;
case GL_OUT_OF_MEMORY:
cout << "Out of memory";
break;
default:
cout << "Oh boy, did it break..";
}
cout << " (" << stage << ")" << endl;
int junk;
cin >> junk;
exit(EXIT_FAILURE);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
if (SDL_Init(SDL_INIT_EVERYTHING) == -1) exit(EXIT_FAILURE);
if (IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG) == -1) exit(EXIT_FAILURE);
Assimp::Importer importer;
const aiScene *importedScene = importer.ReadFile("Table.3ds",aiProcess_Triangulate);
if (importedScene == nullptr) exit(EXIT_FAILURE);
aiMesh *theMesh = importedScene->mMeshes[0];
if (theMesh == nullptr) exit(EXIT_FAILURE);
cout << "I imported a mesh with " << theMesh->mNumVertices << " vertices and " << theMesh->mNumFaces << " faces! " << endl;
SDL_Window *win = nullptr;
win = SDL_CreateWindow("My even more awesome SDL/OGL program", 100, 100, 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
if (win == nullptr) exit(EXIT_FAILURE);
SDL_Renderer *ren = nullptr;
ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (ren == nullptr) exit(EXIT_FAILURE);
SDL_GLContext context = SDL_GL_CreateContext(win);
if (context == nullptr) exit(EXIT_FAILURE);
glewInit();
int attrib_vPosition = 0;
const GLchar *vertexShaderSource = { "#version 430 core\n"
"layout (location=0) in vec4 vPosition;"
"uniform mat4 MVPMatrix;"
"void main() {"
" gl_Position = MVPMatrix * vPosition;"
"}"};
GLuint vertexShader = buildShader(&vertexShaderSource, 1, GL_VERTEX_SHADER);
checkGL("compiling vertex shader");
const GLchar *fragShaderSource = { "#version 430 core\n"
"out vec4 fColor;"
"void main() {"
" fColor = vec4(0.0, 0.0, 1.0, 1.0);"
"}"
};
GLuint fragmentShader = buildShader(&fragShaderSource, 1, GL_FRAGMENT_SHADER);
checkGL("compiling fragment shader");
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
checkGLShaderStatus(shaderProgram, GL_LINK_STATUS, false);
checkGL("Linking shader");
glUseProgram(shaderProgram);
//glDeleteShader(fragmentShader);
//glDeleteShader(vertexShader);
checkGL("Running shader");
GLint MVPlocation = glGetUniformLocation(shaderProgram, "MVPMatrix");
checkGL("Getting uniform location");
glm::mat4 mvpMatrix(0.1f);
glUniformMatrix4fv(MVPlocation, 1, GL_FALSE, glm::value_ptr(mvpMatrix));
checkGL("Setting uniform");
GLint testLocation = glGetUniformLocation(shaderProgram, "MVPMatrix[0][0]");
checkGL("Getting uninform test cell location");
GLfloat testfloat;
glGetUniformfv(shaderProgram, testLocation, &testfloat);
checkGL("Reading uniform");
if (testfloat != mvpMatrix[0][0]) {
cout << "Uniform setting did not sink in..";
}
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
checkGL("Creating VAO");
GLfloat vertices[3][3] = { { -0.9f, -0.9f, 0.f }, { 0.85f, -0.9f, 0.f }, { -0.9f, 0.85f, 0.f } };
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
int vertexDataSize = 9;
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, ((void *)(0)));
glEnableVertexAttribArray(0);
checkGL("creating VBO");
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, vertexDataSize);
glFlush();
SDL_GL_SwapWindow(win);
SDL_Event event;
bool quit = false;
while (!quit) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
quit = true;
}
}
}
glDeleteProgram(shaderProgram);
glDeleteBuffers(1, &buffer);
glDeleteVertexArrays(1, &VAO);
SDL_GL_DeleteContext(context);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
IMG_Quit();
SDL_Quit();
return 0;
}
Upvotes: 0
Views: 553
Reputation: 283684
You shouldn't use glGetUniformfv(... glGetUniformLocation(... "MVPMatrix[0][0]"))
. The documentation says
glGetUniformLocation
returns an integer that represents the location of a specific uniform variable within a program object. name must be a null terminated string that contains no white space. name must be an active uniform variable name in program that is not a structure, an array of structures, or a subcomponent of a vector or a matrix.
And
glGetUniform
returns in params the value(s) of the specified uniform variable. The type of the uniform variable specified by location determines the number of values returned. If the uniform variable is defined in the shader as a boolean, int, or float, a single value will be returned. If it is defined as a vec2, ivec2, or bvec2, two values will be returned. If it is defined as a vec3, ivec3, or bvec3, three values will be returned, and so on. To query values stored in uniform variables declared as arrays, callglGetUniform
for each element of the array. To query values stored in uniform variables declared as structures, callglGetUniform
for each field in the structure. The values for uniform variables declared as a matrix will be returned in column major order.
Your uniform variable uniform mat4 MVPMatrix;
is declared as a matrix type, not an array and you will retrieve the entire 4x4 matrix at once (just like you set it in a single operation). Try
GLfloat testfloat[16];
glGetUniformfv(shaderProgram, MVPLocation, testfloat);
Another problem is here:
GLfloat vertices[3][3] = { { -0.9f, -0.9f, 0.f }, { 0.85f, -0.9f, 0.f }, { -0.9f, 0.85f, 0.f } };
int vertexDataSize = 9;
glDrawArrays(GL_TRIANGLES, 0, vertexDataSize);
You don't have 9 vertices, only 3.
Upvotes: 1