OpenGL 4.x textures not working - c

I'm new here.
I'm having trouble with textures in OpenGL 4.4, I just get a black screen.
Here's my code (I suspect everything before glGenBuffers() is unimportant but you never know):
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "eternity.h"
#include "error.h"
#define STB_IMAGE_IMPLEMENTATION
#define STBI_FAILURE_USERMSG
#include "stb_image.h"
int main(int argc, char *argv[])
{
if (argc < 2)
DIE("%s\n", "not enough arguments");
GLuint width = 0, height = 0, bpp = 0;
unsigned char *image_raw;
if ((image_raw = stbi_load("image.jpg", &width, &height, &bpp, 0)) == NULL)
DIE("stbi error: %s\n", stbi_failure_reason());
uint8_t rv;
if (rv = initialize_glfw())
DIE("%s%" PRIu8 "\n", "initialize_glfw() failed with code ", rv);
glfwSetErrorCallback(glfw_error_callback);
glfw *glfw = malloc(sizeof(glfw));
if (!(glfw->window = glfwCreateWindow(
width,
height,
"Eternity",
NULL,
NULL)))
{
glfwTerminate();
DIE("%s\n", "glfwCreateWindow failed");
}
glfwMakeContextCurrent(glfw->window);
glfwSetKeyCallback(glfw->window, glfw_key_callback);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
eternity_cleanup(glfw);
DIE("%s\n", "glewInit() failed");
}
printf("OpenGL %s\n", glGetString(GL_VERSION));
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
GLshort vertices[] = {
-1, 1, 0,
1, 1, 0,
-1, -1, 0,
1, -1, 0
};
GLushort texcoords[] = {
0, 0,
1, 0,
0, 1,
1, 1
};
gl gl = {0}; // This is just a struct
glGenBuffers(1, &(gl.points_vbo));
glBindBuffer(GL_ARRAY_BUFFER, gl.points_vbo);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLshort), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &(gl.texcoords_vbo));
glBindBuffer(GL_ARRAY_BUFFER, gl.texcoords_vbo);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLushort), texcoords, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, gl.points_vbo); // EDIT: I added this line
glGenVertexArrays(1, &(gl.vao));
glBindVertexArray(gl.vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_SHORT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_UNSIGNED_SHORT, GL_FALSE, 0, NULL);
setup_shaders(&gl);
GLenum format;
switch (bpp * 8)
{
case 24:
format = GL_RGB;
break;
case 32:
format = GL_RGBA;
break;
}
GLuint texture_id = 0;
glGenTextures(1, &texture_id);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, (GLint)format, width, height, 0, format, GL_UNSIGNED_BYTE, image_raw);
stbi_image_free(image_raw);
glBindTexture(GL_TEXTURE_2D, texture_id);
check_error();
while (!glfwWindowShouldClose(glfw->window))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(gl.shader_program);
glBindVertexArray(gl.vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glfwSwapBuffers(glfw->window);
glfwPollEvents();
}
glDeleteTextures(1, &texture_id);
eternity_cleanup(glfw);
}
void setup_shaders(gl *gl)
{
const GLchar *vs_source =
"#version 440\n"
"layout(location = 0) in vec3 vp;"
"layout(location = 1) in vec2 vt;"
"out vec2 texcoord;"
"void main() { gl_Position = vec4(vp, 1.0);"
"texcoord = vt; }",
*fs_source =
"#version 440\n"
"out vec4 frag_color;"
"in vec2 texcoord;"
"uniform sampler2D texture;"
"void main() { frag_color = texture2D(texture, texcoord); }";
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vs_source, NULL);
glCompileShader(vs);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fs_source, NULL);
glCompileShader(fs);
gl->shader_program = glCreateProgram();
glAttachShader(gl->shader_program, fs);
glAttachShader(gl->shader_program, vs);
glLinkProgram(gl->shader_program);
glDeleteShader(vs);
glDeleteShader(fs);
}
uint8_t initialize_glfw(void)
{
int major = 0, minor = 0, rev = 0;
glfwGetVersion(&major, &minor, &rev);
printf("GLFW %d.%d rev %d\n", major, minor, rev);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, minor);
glfwWindowHint(GLFW_CONTEXT_REVISION, rev);
glfwWindowHint(GLFW_SAMPLES, 8);
if (!glfwInit())
return 1;
return 0;
}
void glfw_error_callback(int error, const char *description)
{
printf("glfw error callback triggered\n");
fprintf(stderr, "%d: %s\n", error, description);
}
void glfw_key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
void eternity_cleanup(glfw* glfw)
{
glfwDestroyWindow(glfw->window);
free(glfw);
glfwTerminate();
}
I'm not sure if I've forgotten to do something here or if I'm doing something incorrectly, I have tried very hard to fix this but the black screen persists.
I feel like the problem is in my shaders (hardcoded in setup_shaders()), or maybe around glTexImage2D()?
edit:
I found that if I call glBindBuffer again right before glGenVertexArrays, then I get a light blue screen, and the specific image that I am loading is predominantly this exact shade of blue, so I believe I am sampling a single pixel.
I have updated the source code with a comment where I added a line.
My problem is now that I am sampling only one pixel.

Related

GL_INVALID_OPERATION after calling glBindVertexArray(VAO)

Everything works up until this step where I get a GL_INVALID_OPERATION error (code 1282). I've confirmed that every opengl function before glBindVertexArray(VAO) return no error codes. I'm also sure that my context is okay because I'm able to draw a simple clearcolor to the screen just fine.
#include <windows.h>
#include <GL/glcorearb.h>
#include <GL/wglext.h>
#include <stdbool.h>
#include <stdio.h>
LRESULT CALLBACK window_procedure(HWND, UINT, WPARAM, LPARAM);
void *get_proc(const char *);
HMODULE gl_module;
bool quit = false;
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
PFNGLGETSTRINGPROC glGetString;
PFNGLCLEARCOLORPROC glClearColor;
PFNGLCLEARPROC glClear;
PFNGLVIEWPORTPROC glViewport;
PFNGLGENBUFFERSPROC glGenBuffers;
PFNGLBINDBUFFERPROC glBindBuffer;
PFNGLBUFFERDATAPROC glBufferData;
PFNGLCREATESHADERPROC glCreateShader;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLGETSHADERIVPROC glGetShaderiv;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
PFNGLDRAWARRAYSPROC glDrawArrays;
PFNGLGETSHADERIVPROC glGetProgramiv;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLGETERRORPROC glGetError;
int WINAPI WinMain(HINSTANCE instance_handle, HINSTANCE prev_instance_handle, PSTR cmd_line, int cmd_show)
{
// Create Window and register it
WNDCLASS window_class;
ZeroMemory(&window_class, sizeof(window_class));
window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
window_class.lpfnWndProc = window_procedure;
window_class.hInstance = instance_handle;
window_class.lpszClassName = TEXT("OPENGL_WINDOW");
RegisterClass(&window_class);
///////////////////////////////////
/* CREATE DUMMY WINDOW TO MAKE DC */
HWND window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TEXT("OPENGL_WINDOW"),
TEXT("OPENGL_WINDOW"),
WS_OVERLAPPEDWINDOW,
0, 0,
0, 0,
NULL,
NULL,
instance_handle,
NULL);
HDC dc = GetDC(window_handle);
PIXELFORMATDESCRIPTOR descriptor;
ZeroMemory(&descriptor, sizeof(descriptor));
descriptor.nSize = sizeof(descriptor);
descriptor.nVersion = 1;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER | PFD_SWAP_LAYER_BUFFERS;
descriptor.iPixelType = PFD_TYPE_RGBA;
descriptor.cColorBits = 32;
descriptor.cRedBits = 8;
descriptor.cGreenBits = 8;
descriptor.cBlueBits = 8;
descriptor.cAlphaBits = 8;
descriptor.cDepthBits = 32;
descriptor.cStencilBits = 8;
int pixel_format = ChoosePixelFormat(dc, &descriptor);
SetPixelFormat(dc, pixel_format, &descriptor);
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
gl_module = LoadLibrary(TEXT("opengl32.dll"));
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)get_proc("wglGetExtensionsStringARB");
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)get_proc("wglChoosePixelFormatARB");
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)get_proc("wglCreateContextAttribsARB");
glGetString = (PFNGLGETSTRINGPROC)get_proc("glGetString"); //
glClearColor = (PFNGLCLEARCOLORPROC)get_proc("glClearColor"); //
glClear = (PFNGLCLEARPROC)get_proc("glClear"); //
glViewport = (PFNGLVIEWPORTPROC)get_proc("glViewport"); //
glGenBuffers = (PFNGLGENBUFFERSPROC)get_proc("glGenBuffers");
glBindBuffer = (PFNGLBINDBUFFERPROC)get_proc("glBindBuffer");
glBufferData = (PFNGLBUFFERDATAPROC)get_proc("glBufferData");
glCreateShader = (PFNGLCREATESHADERPROC)get_proc("glCreateShader");
glShaderSource = (PFNGLSHADERSOURCEPROC)get_proc("glShaderSource");
glCompileShader = (PFNGLCOMPILESHADERPROC)get_proc("glCompileShader");
glGetShaderiv = (PFNGLGETSHADERIVPROC)get_proc("glGetShaderiv");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)get_proc("glGetShaderInfoLog");
glCreateProgram = (PFNGLCREATEPROGRAMPROC)get_proc("glCreateProgram");
glAttachShader = (PFNGLATTACHSHADERPROC)get_proc("glAttachShader");
glLinkProgram = (PFNGLLINKPROGRAMPROC)get_proc("glLinkProgram");
glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)get_proc("glVertexAttribPointer");
glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)get_proc("glEnableVertexAttribArray");
glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)get_proc("glEnableVertexAttribArray");
glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)get_proc("glBindVertexArray");
glDrawArrays = (PFNGLDRAWARRAYSPROC)get_proc("glDrawArrays");
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)get_proc("glGetProgramiv");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)get_proc("glGetShaderInfoLog");
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)get_proc(("glGetProgramInfoLog"));
glUseProgram = (PFNGLUSEPROGRAMPROC)get_proc("glUseProgram");
glDeleteShader = (PFNGLDELETESHADERPROC)get_proc(("glDeleteShader"));
glGetError = (PFNGLGETERRORPROC)get_proc("glGetError");
FreeLibrary(gl_module);
int pixel_format_arb = 0;
UINT pixel_formats_found = 0;
int pixel_attributes[] = {
WGL_SUPPORT_OPENGL_ARB, 1,
WGL_DRAW_TO_WINDOW_ARB, 1,
WGL_DRAW_TO_BITMAP_ARB, 1,
WGL_DOUBLE_BUFFER_ARB, 1,
WGL_SWAP_LAYER_BUFFERS_ARB, 1,
WGL_COLOR_BITS_ARB, 32,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 32,
WGL_STENCIL_BITS_ARB, 8,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
0};
BOOL result = wglChoosePixelFormatARB(dc, pixel_attributes, NULL, 1, &pixel_format_arb, &pixel_formats_found);
/* RECREATE WINDOW */
wglMakeCurrent(dc, NULL);
wglDeleteContext(rc);
ReleaseDC(window_handle, dc);
DestroyWindow(window_handle);
window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TEXT("OPENGL_WINDOW"),
TEXT("OPENGL_WINDOW"),
WS_OVERLAPPEDWINDOW,
((GetSystemMetrics(SM_CXSCREEN) - 800) / 2), ((GetSystemMetrics(SM_CYSCREEN) - 600) / 2),
800, 600,
NULL,
NULL,
instance_handle,
NULL);
dc = GetDC(window_handle);
SetPixelFormat(dc, pixel_format, &descriptor);
ShowWindow(window_handle, SW_SHOW);
/* NEW CONTEXT */
GLint context_attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0};
rc = wglCreateContextAttribsARB(dc, 0, context_attributes);
wglMakeCurrent(dc, rc);
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// fragment shader
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// link shaders
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
printf("%d\n", VAO);
glGenBuffers(1, &VBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(VAO);
GLenum error = glGetError();
printf("%d", error);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray(0);
/* EVENT PUMP */
MSG msg;
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
glDrawArrays(GL_TRIANGLES, 0, 3);
SwapBuffers(dc);
}
return 0;
}
// Procedure that processes window events
LRESULT CALLBACK window_procedure(HWND window_handle, UINT message, WPARAM param_w, LPARAM param_l)
{
return DefWindowProc(window_handle, message, param_w, param_l);
}
/* A procedure for getting OpenGL functions and OpenGL or WGL extensions.
When looking for OpenGL 1.2 and above, or extensions, it uses wglGetProcAddress,
otherwise it falls back to GetProcAddress. */
void *get_proc(const char *proc_name)
{
void *proc = (void *)wglGetProcAddress(proc_name);
if (!proc)
{
proc = (void *)GetProcAddress(gl_module, proc_name);
}
return proc;
}

Opengl is not using the correct texture

I have recently started learning opengl on learnopengl.com. I am the chapter about textures. I have managed to load 2 textures however when I tell opengl to render the texture currently bound to GL_TEXTURE0 it instead draws the texture currently bound to GL_TEXTURE1.
My main.c file looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "glad/glad.h"
#include "GLFW/glfw3.h"
#include "stb/stb_image_init.h"
#define WIDTH 1080
#define HEIGHT 720
typedef unsigned int uint;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void process_input(GLFWwindow* window);
void check_shader_compilation(GLuint shader_object, GLenum shader_type);
void check_shader_linking(GLuint shader_program);
char* get_shader_code(const char* path);
int main(void) {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Triangle", NULL, NULL);
if (window == NULL) {
printf("Unable to create glfw window!\n");
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
printf("Couldn't initialize glad!\n");
return -1;
}
glViewport(0, 0, WIDTH, HEIGHT);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
char* vertex_shader_code = get_shader_code("shaders/vertex.glsl");
GLuint vertex_shader_object = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader_object, 1, &vertex_shader_code, NULL);
glCompileShader(vertex_shader_object);
check_shader_compilation(vertex_shader_object, GL_VERTEX_SHADER);
free(vertex_shader_code);
char* fragment_shader_code = get_shader_code("shaders/fragment.glsl");
GLuint fragment_shader_object = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader_object, 1, &fragment_shader_code, NULL);
glCompileShader(fragment_shader_object);
check_shader_compilation(fragment_shader_object, GL_FRAGMENT_SHADER);
free(fragment_shader_code);
uint shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader_object);
glAttachShader(shader_program, fragment_shader_object);
glLinkProgram(shader_program);
glUseProgram(shader_program);
check_shader_linking(shader_program);
float rectangle_data[] = {
// Coords Colors Texture coords
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Bottom Left
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Bottom Right
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // Top Left
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // Top Right
};
unsigned int indicies[] = {
0, 2, 3,
0, 1, 3,
};
uint vao, vbo, ebo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ARRAY_BUFFER, sizeof(rectangle_data), rectangle_data, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indicies), indicies, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float)*8, (void*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float)*8, (void*)(sizeof(float)*3));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float)*8, (void*)(sizeof(float)*6));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
float border_color[] = { 1.0f, 0.0f, 0.0f, 1.0f };
uint texture_buffer, texture2_buffer;
glGenBuffers(1, &texture_buffer);
glBindTexture(GL_TEXTURE_2D, texture_buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
stbi_set_flip_vertically_on_load(true);
int width = 0, height = 0, n_channels = 0;
unsigned char* texture_image = stbi_load("assets/textures/luffy.jpg", &width, &height, &n_channels, 0);
if (texture_image) {
printf("Loaded texture0!\n");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_image);
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
printf("Couldn't find the image for the texture\n");
exit(-1);
}
stbi_image_free(texture_image);
glGenBuffers(1, &texture2_buffer);
glBindTexture(GL_TEXTURE_2D, texture2_buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
int t2_width = 0, t2_height = 0, t2_n_channels = 0;
unsigned char* texture2_image = stbi_load("assets/textures/face.png", &t2_width, &t2_height, &t2_n_channels, 0);
if (texture2_image) {
printf("Loaded texture1!\n");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, t2_width, t2_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture2_image);
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
printf("Couldn't find the image for texture2\n");
exit(-1);
}
stbi_image_free(texture2_image);
glUseProgram(shader_program);
glUniform1i(glGetUniformLocation(shader_program, "luffy"), 0);
glUniform1i(glGetUniformLocation(shader_program, "face"), 1);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
while (!glfwWindowShouldClose(window)) {
process_input(window);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_buffer);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2_buffer);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwPollEvents();
glfwSwapBuffers(window);
}
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ebo);
glDeleteShader(vertex_shader_object);
glDeleteShader(fragment_shader_object);
glDeleteProgram(shader_program);
glfwTerminate();
return 0;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
void process_input(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_Q) == true) {
glfwSetWindowShouldClose(window, true);
}
}
void check_shader_compilation(GLuint shader_object, GLenum shader_type) {
char* print_shader_type;
switch (shader_type) {
case GL_VERTEX_SHADER:
print_shader_type = "vertex";
break;
case GL_FRAGMENT_SHADER:
print_shader_type = "fragment";
break;
default:
printf("Cannot check for shader compilation, the shader_type is not GL_VERTEX_SHADER or GL_FRAGMENT_SHADER!\n");
exit(-1);
}
int shader_status;
glGetShaderiv(shader_object, GL_COMPILE_STATUS, &shader_status);
if (!shader_status) {
int message_length;
GLchar error[1024];
glGetShaderInfoLog(shader_object, 1024, &message_length, error);
printf("Could not compile the %s shader: \n %s\n", print_shader_type, error);
exit(-1);
}
else {
printf("Compiled the %s shader!\n", print_shader_type);
}
}
void check_shader_linking(GLuint shader_program) {
int linking_status;
glGetProgramiv(shader_program, GL_LINK_STATUS, &linking_status);
if (!linking_status) {
int message_length;
GLchar error[1024];
glGetProgramInfoLog(shader_program, 1024, &message_length, error);
printf("Could not link the shader program:\n %s\n", error);
exit(-1);
}
else {
printf("Linked the shader program!\n");
}
}
char* get_shader_code(const char* path) {
FILE* shader_file = fopen(path, "rb");
if (!shader_file) {
printf("Incorrect file path for shader: %s\n", path);
exit(-1);
}
fseek(shader_file, 0, SEEK_END);
int file_size = ftell(shader_file);
rewind(shader_file);
char* shader_code = malloc(file_size + 1);
shader_code[file_size] = '\0';
fread(shader_code, sizeof(char), file_size, shader_file);
return shader_code;
}
My Vertex shader is:
#version 330
layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 colors;
layout (location = 2) in vec2 texCoords;
out vec3 vertex_colors;
out vec2 tex_coords;
void main() {
gl_Position = vec4(pos.x, pos.y, pos.z, 1.0);
vertex_colors = colors;
tex_coords = texCoords;
}
And my fragment shader is:
#version 330 core
out vec4 fragColor;
in vec3 vertex_colors;
in vec2 tex_coords;
uniform sampler2D luffy;
uniform sampler2D face;
void main() {
fragColor = texture(luffy, tex_coords);
}
Whenever I run the program, it texture it uses is the image in face.png, whereas I told it to use the image in luffy.jpg.
You never create any texture objects:
glGenBuffers(1, &texture_buffer);
glBindTexture(GL_TEXTURE_2D, texture_buffer);
glGenBuffers is for buffer objects, not for texture objects. You have to use glGenTextures. (Also calling your variable texture_buffer here is very confusing. There are buffer textures in the GL, but you're not using those here).
And since you use a core profile, the glBindTexture() call will just generate a GL error and have no other effect, becuase the object name you try to bind never was generated by glGenTextures. So in effect, you are working with texture object 0 here, and load both images to that texture object, with the latter overwriting the former. In a core profiler, using texture object 0 actually shouldn't work, but many drivers still allow it (as it was allowed in legacy GL), so that you actually see any texture at all is not guaranteed either.

Why my openGL program shows a blank screen?

I created this simple hello triangle program from internet samples, but no matter how I try, I always get a blank screen. I would appreciate any help.
The development environment is Visual Studio on Windows 10 with CUDA 10.
The glGetError at the display callback return 0.
Here is the full source code:
#pragma comment(lib, "C:\\GL\\GLUT\\lib\\x64\\freeglut.lib")
#define GLEW_STATIC
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
const char* vertexShaderSource = "#version 460 core\n"
"layout(location = 0) in vec3 aPos;\n"
"layout(location = 1) in vec3 aColor;\n"
"out vec4 vertexColor;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos, 1.0);\n"
" vertexColor = vec4(aColor, 1.0);\n"
"}\0";
unsigned int vertexShader;
const char* fragmentShaderSource = "#version 460 core\n"
"in vec4 vertexColor;\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vertexColor;\n"
"}\0";
unsigned int shaderProgram;
unsigned int VAO;
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
/* Exit on escape key press */
case '\x1B':
{
exit(EXIT_SUCCESS);
break;
}
}
}
void display()
{
glUseProgram(shaderProgram);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
printf("GL error=%d\n", glGetError()); fflush(stdout);
}
/* Main method */
int main(int argc, char** argv)
{
glutInitContextVersion(4, 6);
glutInit(&argc, argv);
glutInitWindowSize(800, 600);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Automaton");
printf("%s\n", glGetString(GL_VERSION));
glViewport(0, 0, 800, 600);
GLenum err = glewInit();
if (GLEW_OK != err)
{
printf("glew init %s\n", glewGetErrorString(err)); fflush(stdout);
return -1;
}
//
// Create shaders
//
int success;
char infoLog[512];
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
perror("Vertex shader failed.\n");
return -1;
}
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
perror("Vertex shader failed.\n");
return -1;
}
//
// Link shaders
//
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
perror("Linking error.\n");
return -1;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
//
float vertices[] =
{
-1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f
};
GLuint attribPos = 0;
GLuint attribCol = 1;
//
unsigned int VBO;
glCreateBuffers(1, &VBO);
glCreateVertexArrays(1, &VAO);
glNamedBufferStorage(VBO, sizeof(vertices), vertices, GL_DYNAMIC_STORAGE_BIT);
GLuint vaoBindingPoint = 0;
glVertexArrayVertexBuffer(VAO, vaoBindingPoint, VBO, 0, 6 * sizeof(float));
glEnableVertexArrayAttrib(VAO, attribPos);
glEnableVertexArrayAttrib(VAO, attribCol);
glVertexArrayAttribFormat(VAO, attribPos, 3, GL_FLOAT, 0/*false*/, 0);
glVertexArrayAttribFormat(VAO, attribCol, 3, GL_FLOAT, 0/*false*/, 3 * sizeof(float));
glVertexArrayAttribBinding(VAO, attribPos, vaoBindingPoint);
glVertexArrayAttribBinding(VAO, attribCol, vaoBindingPoint);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glutKeyboardFunc(&keyboard);
glutDisplayFunc(&display);
glutMainLoop();
return EXIT_SUCCESS;
}
The program is running in a DELL PC with NVIDIA GPU 1050.
You have to call glutSwapBuffers to flush the display respectively perform a buffer swap:
void display()
{
glUseProgram(shaderProgram);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
printf("GL error=%d\n", glGetError()); fflush(stdout);
glutSwapBuffers();
}

Why am I getting a black screen with this opengl application?

I must be missing something really simple here, I've been staring at my code for the last hour and just can't see it. The code should just create a texture with random pure color or pure black pixels, then draw it to the screen. Right now though it's just producing a black screen...
My guess is it has something to with my vertex or uv positions.
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
const char TITLE[] = "GL TEST";
const int WIDTH = 800;
const int HEIGHT = 600;
const char BASIC_VERT_SHADER[] =
"#version 330\n"
"in vec2 vs_position;"
"in vec2 vs_uvCoord;"
"out vec2 fs_uvCoord;"
"void main()"
"{"
"fs_uvCoord = vs_uvCoord;"
"gl_Position = vec4(vs_position, 1.f, 1.f);"
"}";
const char BASIC_FRAG_SHADER[] =
"#version 330\n"
"uniform sampler2D texture;"
"in vec2 fs_uvCoord;"
"out vec4 frag_color;"
"void main()"
"{"
"frag_color = texture2D(texture, fs_uvCoord);"
"}";
const float TEXTURE_UV[] =
{
0.f, 0.f,
1.f, 0.f,
1.f, 1.f,
0.f, 1.f
};
const float VERT_POS[] =
{
-1.f, -1.f,
1.f, -1.f,
1.f, 1.f,
-1.f, 1.f
};
GLFWwindow* setupGraphics()
{
GLFWwindow* window;
if ( !glfwInit() )
{
fputs("failed to initialize glfw!\n", stderr);
exit(1);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // opengl 3.x
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // opengl 3.3
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // needed for osx
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(WIDTH, HEIGHT, TITLE, NULL, NULL);
if (!window)
{
fputs("failed to create window!\n", stderr);
exit(1);
}
glfwMakeContextCurrent(window);
glewExperimental = true;
if ( glewInit() != GLEW_OK )
{
fputs("failed to initialize glew!\n", stderr);
exit(1);
}
if ( !GLEW_VERSION_3_3 )
{
fputs("opengl 3.3 support is required!\n", stderr);
exit(1);
}
return window;
};
unsigned int compileShader(const char* shaderSource, GLenum type)
{
unsigned int shaderID = glCreateShader(type);
glShaderSource(shaderID, 1, &shaderSource , NULL);
glCompileShader(shaderID);
int status;
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &status);
if ( status == GL_FALSE )
{
int errorLength;
glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &errorLength);
char errorString[errorLength+1];
glGetShaderInfoLog(shaderID, errorLength, NULL, errorString);
fprintf(stderr, "glsl compile error: %s", errorString);
exit(1);
}
return shaderID;
}
unsigned int compileShaderProgram(const char* vsSource, const char* fsSource)
{
unsigned int programID = glCreateProgram();
unsigned int vsID = compileShader(vsSource, GL_VERTEX_SHADER);
unsigned int fsID = compileShader(fsSource, GL_FRAGMENT_SHADER);
glAttachShader(programID, vsID);
glAttachShader(programID, fsID);
glLinkProgram(programID);
int status;
glGetProgramiv(programID, GL_LINK_STATUS, &status);
if ( status == GL_FALSE )
{
int errorLength;
glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &errorLength);
char errorString[errorLength+1];
glGetProgramInfoLog(programID, errorLength, NULL, errorString);
fprintf(stderr, "glsl linking error: %s", errorString);
exit(1);
}
glDetachShader(programID, vsID);
glDetachShader(programID, fsID);
glDeleteShader(vsID);
glDeleteShader(fsID);
return programID;
}
unsigned int randomTexture(int width, int height)
{
unsigned int textureID;
int size = width * height;
unsigned char* buffer = malloc( size * sizeof(unsigned char) );
for (int i = 0; i < size; i++)
{
if ( rand() & 1 )
{
buffer[i] = 0x00;
}
else
{
buffer[i] = 0xFF;
}
}
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_R8,
width, height, 0, GL_RED,
GL_UNSIGNED_BYTE, buffer
);
free(buffer);
return textureID;
}
int main()
{
GLenum glError;
GLFWwindow* window;
unsigned int shader;
unsigned int texture;
unsigned int vertPosBuffer;
unsigned int uvCoordBuffer;
unsigned int vertexArray;
int textureUniform;
int vertPosAttribute;
int uvCoordAttribute;
srand( time(NULL) );
window = setupGraphics();
shader = compileShaderProgram(BASIC_VERT_SHADER, BASIC_FRAG_SHADER);
textureUniform = glGetUniformLocation(shader, "texture");
vertPosAttribute = glGetAttribLocation(shader, "vs_position");
uvCoordAttribute = glGetAttribLocation(shader, "vs_uvCoord");
texture = randomTexture(WIDTH, HEIGHT);
glGenVertexArrays(1, &vertexArray);
glBindVertexArray(vertexArray);
glGenBuffers(1, &vertPosBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertPosBuffer);
glBufferData(GL_ARRAY_BUFFER, 8*sizeof(float), VERT_POS, GL_STATIC_DRAW);
glVertexAttribPointer(vertPosAttribute, 2, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, &uvCoordBuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvCoordBuffer);
glBufferData(GL_ARRAY_BUFFER, 8*sizeof(float), TEXTURE_UV, GL_STATIC_DRAW);
glVertexAttribPointer(uvCoordAttribute, 2, GL_FLOAT, GL_FALSE, 0, 0);
while ( !glfwWindowShouldClose(window) )
{
glClear( GL_COLOR_BUFFER_BIT );
glClearColor(0.f, 0.f, 0.f, 1.f);
glUseProgram(shader);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(textureUniform, 0);
glBindVertexArray(vertexArray);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glfwSwapBuffers(window);
glfwPollEvents();
while((glError = glGetError()) != GL_NO_ERROR)
{
fprintf(stderr, "gl error: %d\n", glError);
exit(1);
}
}
glDeleteVertexArrays(1, &vertexArray);
glDeleteBuffers(1, &vertPosBuffer);
glDeleteBuffers(1, &uvCoordBuffer);
glDeleteTextures(1, &texture);
glDeleteProgram(shader);
return 0;
}
The major issue is that you have forgotten to enable the generic vertex attribute arrays. See glEnableVertexAttribArray
glGenBuffers(1, &vertPosBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertPosBuffer);
glBufferData(GL_ARRAY_BUFFER, 8*sizeof(float), VERT_POS, GL_STATIC_DRAW);
glVertexAttribPointer(vertPosAttribute, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray( vertPosAttribute ); // <-----------------
glGenBuffers(1, &uvCoordBuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvCoordBuffer);
glBufferData(GL_ARRAY_BUFFER, 8*sizeof(float), TEXTURE_UV, GL_STATIC_DRAW);
glVertexAttribPointer(uvCoordAttribute, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray( uvCoordAttribute ); // <-----------------
As mentioned in the comments to your question you should set the textue minifying filter to GL_LINEAR or GL_NEAREST, since you do not use mipmaps:
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_R8,
width, height, 0, GL_RED,
GL_UNSIGNED_BYTE, buffer.data()
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
A triangle stripe which creates a quad is setup like this:
const float TEXTURE_UV[] =
{
0.f, 0.f,
1.f, 0.f,
0.f, 1.f,
1.f, 1.f
};
const float VERT_POS[] =
{
-1.f, -1.f,
1.f, -1.f,
-1.f, 1.f,
1.f, 1.f
};
But you can draw a trangle fan instead:
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

glTexImage2d and GL_R8UI fails on some GPUs

I'm trying to use GL_R8UI to pass unsigned, unnormalized data to a shader, but have found that on at least one GPU it doesn't work.
ie: this works:
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 32, 32, 0, GL_RED, GL_UNSIGNED_BYTE, pData);
but this doesn't:
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, 32, 32, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pData);
I'm also changing the shader to use sampler2D vs usampler2D and updating the math in the shader appropriately, but finding it works on AMD/Radeon cards but fails on Intel and NVidia cards - the usampler2D always seems to return zero.
I've put together a minimal sample program here. The #define NORMALIZED switches between the two approaches.
So... my main question is: is this simply a driver problem or is there something else wrong in my code that's causing this?
To ask this question another way... what else needs to be changed to switch from GL_R8 normalized data to GL_R8UI unnormalized data, besides:
changing the call to glTextImage2D
changing from sampler2D to usampler2D in the shader
changing the shader to work with uint's instead of floats
changing the math in the shader to deal with normalized vs unnormalized data.
I've now logged an bug report with Intel: https://software.intel.com/en-us/forums/graphics-driver-bug-reporting/topic/748843
Since it was asked for here's the full example program source:
// ShaderTest.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "ShaderTest.h"
#include <stdlib.h>
#include <stdint.h>
#include <GL/gl3w.h>
#pragma comment(lib, "opengl32.lib")
#define NORMALIZED
const char* pszVertexShader = R"***(
#version 150
uniform mat4 transform;
attribute vec3 position;
varying vec2 vPosition;
void main()
{
gl_Position = transform * vec4(position,1.);
vPosition = position.xy;
}
)***";
#ifdef NORMALIZED
const char* pszFragmentShader = R"***(
#version 150
uniform sampler2D TextureData;
varying vec2 vPosition;
void main()
{
float red = texelFetch(TextureData, ivec2(0, 0), 0).r;
gl_FragColor = vec4(red , 0, 0, 1);
}
)***";
#else
const char* pszFragmentShader = R"***(
#version 150
uniform usampler2D TextureData;
varying vec2 vPosition;
void main()
{
// Original post had this wrong
// float red = float(texelFetch(TextureData, ivec2(0, 0), 0)).r/255.0;
// Fixed version - still fails on Intel GPUs though
float red = float(texelFetch(TextureData, ivec2(0, 0), 0).r)/255.0;
gl_FragColor = vec4(red, 0, 0, 1);
}
)***";
#endif
int CompileShader(GLenum type, const char* pszSource)
{
int iShader = glCreateShader(type);
glShaderSource(iShader, 1, &pszSource, NULL);
glCompileShader(iShader);
// Dump log
int length;
glGetShaderiv(iShader, GL_INFO_LOG_LENGTH, &length);
if (length != 0)
{
char* pszLog = (char*)_alloca((sizeof(char) + 10) * length);
GLsizei len;
glGetShaderInfoLog(iShader, length, &len, pszLog);
OutputDebugStringA(pszLog);
}
// Check for error
int status;
glGetShaderiv(iShader, GL_COMPILE_STATUS, &status);
if (status == 0)
{
// Clean up after failuer
glDeleteShader(iShader);
return 0;
}
// Success
return iShader;
}
// Globals
HINSTANCE hInst;
HGLRC g_hRC;
GLint g_iVertexShader = 0;
GLint g_iFragmentShader = 0;
GLint g_iShaderProgram = 0;
GLuint g_iTexture = 0;
GLuint g_iVertexBuffer = 0;
#define glCheck() assert(glGetError() == 0)
struct VERTEX
{
float x;
float y;
float z;
};
bool Setup()
{
// Compile shaders
g_iVertexShader = CompileShader(GL_VERTEX_SHADER, pszVertexShader);
g_iFragmentShader = CompileShader(GL_FRAGMENT_SHADER, pszFragmentShader);
// Link program
g_iShaderProgram = glCreateProgram();
glAttachShader(g_iShaderProgram, g_iVertexShader);
glAttachShader(g_iShaderProgram, g_iFragmentShader);
glLinkProgram(g_iShaderProgram);
// Dump log
int length;
glGetProgramiv(g_iShaderProgram, GL_INFO_LOG_LENGTH, &length);
if (length != 0)
{
char* pszLog = (char*)_alloca((sizeof(char) + 10) * length);
GLsizei len;
glGetProgramInfoLog(g_iShaderProgram, length, &len, pszLog);
OutputDebugStringA(pszLog);
}
// Check for error
int status;
glGetProgramiv(g_iShaderProgram, GL_LINK_STATUS, &status);
if (status == 0)
return false;
// Create texture
glGenTextures(1, &g_iTexture);
glBindTexture(GL_TEXTURE_2D, g_iTexture);
uint8_t* pData = (uint8_t*)_alloca(32 * 32 * sizeof(uint8_t));
memset(pData, 128, 32 * 32 * sizeof(uint8_t));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#ifdef NORMALIZED
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 32, 32, 0, GL_RED, GL_UNSIGNED_BYTE, pData);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, 32, 32, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pData);
#endif
glBindTexture(GL_TEXTURE_2D, 0);
// Create vertex buffer
glGenBuffers(1, &g_iVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, g_iVertexBuffer);
VERTEX v[] = {
{ 10, 10, 0, },
{ 10, 230, 0, },
{ 310, 10, 0, },
{ 310, 230, 0, },
};
glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
// Done
return true;
}
void Cleanup()
{
if (g_iVertexBuffer)
glDeleteBuffers(1, &g_iVertexBuffer);
if (g_iTexture)
glDeleteTextures(1, &g_iTexture);
if (g_iShaderProgram)
glDeleteProgram(g_iShaderProgram);
if (g_iVertexShader)
glDeleteShader(g_iVertexShader);
if (g_iFragmentShader)
glDeleteShader(g_iFragmentShader);
}
void Display(RECT* prc)
{
// Setup viewport
glViewport(0, 0, prc->right, prc->bottom);
// Clear background
glClearColor(0, 0, 0.5f, 1);
glClear(GL_COLOR_BUFFER_BIT);
// Setup program
glUseProgram(g_iShaderProgram);
// Bind vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, g_iVertexBuffer);
// Setup vertex buffer
int aPosition = glGetAttribLocation(g_iShaderProgram, "position");
glEnableVertexAttribArray(aPosition);
glVertexAttribPointer(aPosition, 3, GL_FLOAT, false, sizeof(VERTEX), 0);
// Setup texture
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, g_iTexture);
int uTextureData = glGetUniformLocation(g_iShaderProgram, "TextureData");
glUniform1i(uTextureData, 0);
// Setup ortho projection
float left = 0;
float right = 320;
float top = 0;
float bottom = 240;
float fnear = -1;
float ffar = 1;
float proj[] = {
(float)(2.0 / (right - left)), 0.0f, 0.0f, 0.0f,
0.0f, (float)(2.0 / (top - bottom)), 0.0f, 0.0f,
0.0f, 0.0f, (float)(-2.0 / (ffar - fnear)), 0.0f,
(float)(-(right + left) / (right - left)), (float)(-(top + bottom) / (top - bottom)), (float)(-(ffar + fnear) / (ffar - fnear)), 1.0f
};
int uTransform = glGetUniformLocation(g_iShaderProgram, "transform");
glUniformMatrix4fv(uTransform, 1, false, proj);
// Draw
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glFlush();
}
bool InitOpenGLContext(HWND hWnd)
{
// Setup pixel format
HDC hDC = GetDC(hWnd);
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
int pf = ChoosePixelFormat(hDC, &pfd);
if (pf == 0 || !SetPixelFormat(hDC, pf, &pfd))
return false;
DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
g_hRC = wglCreateContext(hDC);
if (!g_hRC)
return false;
// Init gl3w
wglMakeCurrent(hDC, g_hRC);
int err = gl3wInit();
if (err)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(g_hRC);
g_hRC = NULL;
return false;
}
// Setup
if (!Setup())
{
assert(false);
Cleanup();
wglMakeCurrent(NULL, NULL);
wglDeleteContext(g_hRC);
g_hRC = NULL;
return false;
}
ReleaseDC(hWnd, hDC);
return true;
}
void CleanupOpenGLContext(HWND hWnd)
{
HDC hDC = GetDC(hWnd);
wglMakeCurrent(hDC, g_hRC);
Cleanup();
wglMakeCurrent(NULL, NULL);
ReleaseDC(hWnd, hDC);
wglDeleteContext(g_hRC);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rc;
GetClientRect(hWnd, &rc);
HDC hdc = BeginPaint(hWnd, &ps);
wglMakeCurrent(hdc, g_hRC);
Display(&rc);
wglMakeCurrent(NULL, NULL);
EndPaint(hWnd, &ps);
}
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_ERASEBKGND:
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
// Register Class
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SHADERTEST));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"ShaderTest";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassExW(&wcex);
// Create Window
HWND hWnd = CreateWindowW(L"ShaderTest", L"ShaderTest", WS_OVERLAPPEDWINDOW,
50, 50, 100, 100, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
return 7;
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = 320;
rc.bottom = 240;
AdjustWindowRect(&rc, GetWindowLong(hWnd, GWL_STYLE), FALSE);
SetWindowPos(hWnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
if (!InitOpenGLContext(hWnd))
{
DestroyWindow(hWnd);
return 7;
}
// Show window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Main message loop:
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CleanupOpenGLContext(hWnd);
DestroyWindow(hWnd);
return (int) msg.wParam;
}
Integer textures need to have nearest filtering (not linear or mipmap):
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

Resources