I'm sorry for asking such a common question, yet all of the other answers have not been very applicable to my problem. In short, I have begun learning OpenGL, and have started trying to draw the mandelbrot set as a small exercise. All of the pixel data is stored in a vector (I checked with GDB), yet for some reason when I transfer it into a texture and then draw it it does not work. To draw the texture I created a class called DrawBuffer, which handles all the OpenGL.
Any insight onto why this may be happening would be appreciated.
Fragment Shader
#version 150
in vec2 Tex_coord;
out vec4 outColor;
uniform sampler2D tex;
void main() {
outColor = texture(tex, Tex_coord);
}
Vertex Shader
#version 150
in vec2 position;
in vec2 tex_coord;
out vec2 Tex_coord;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
Tex_coord = tex_coord;
}
DrawBuffer.cpp
#include "Draw_Buffer.h"
#include <memory>
#include <algorithm>
#include <stdexcept>
#include <vector>
#include <sstream>
#include <fstream>
#include <string>
// Util function to compile a shader from source
void compile_shader(GLuint &shader, const std::string &src) {
std::ifstream is(src);
std::string code;
std::string temp_str;
while (std::getline(is, temp_str)) {
code += temp_str + '\n';
}
const char *c_code = code.c_str();
glShaderSource(shader, 1, &c_code, NULL);
glCompileShader(shader);
}
Draw_Buffer::Draw_Buffer(Window<int> *win, const std::string &vertex_shader_src, const std::string &frag_shader_src) :
window(win), buffer(std::vector<RGB>(window->size())), pos_iter(buffer.begin()) {
// Initialise GLFW
if (!glfwInit()) {
throw std::runtime_error("error: GLFW unable to initialise");
}
// Set up the window
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
screen.reset(glfwCreateWindow(win->width(), win->height(), "Mandelbrot Fractal", nullptr, nullptr));
make_current();
// Initialise glew
glewExperimental = GL_TRUE;
GLenum glewinit = glewInit();
if (glewinit != GLEW_OK) {
std::ostringstream ss;
ss << "error: Glew unable to initialise" << glewinit;
throw std::runtime_error(ss.str());
}
// Clear
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
// Generate shaders
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
GLuint frag_shader = glCreateShader(GL_VERTEX_SHADER);
GLint compile_status;
compile_shader(vertex_shader, vertex_shader_src);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &compile_status);
if (compile_status != GL_TRUE) {
char buffer[512];
glGetShaderInfoLog(vertex_shader, 512, NULL, buffer);
throw std::runtime_error(buffer);
}
compile_shader(frag_shader, frag_shader_src);
glGetShaderiv(frag_shader, GL_COMPILE_STATUS, &compile_status);
if (compile_status != GL_TRUE) {
char buffer[512];
glGetShaderInfoLog(frag_shader, 512, NULL, buffer);
throw std::runtime_error(buffer);
}
// Put shaders into shader program
shader_prog = glCreateProgram();
glAttachShader(shader_prog, vertex_shader);
glAttachShader(shader_prog, frag_shader);
glBindFragDataLocation(shader_prog, 0, "outColor");
glLinkProgram(shader_prog);
glUseProgram(shader_prog);
// Set shader attributes
GLint pos_attrib = glGetAttribLocation(shader_prog, "position");
glVertexAttribPointer(pos_attrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glEnableVertexAttribArray(pos_attrib);
GLint tex_coord_attrib = glGetAttribLocation(shader_prog, "tex_coord");
glEnableVertexAttribArray(tex_coord_attrib);
glVertexAttribPointer(tex_coord_attrib, 2, GL_FLOAT, GL_FALSE,
4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
// Generate texture
glGenTextures(1, &mandelbrot_tex);
}
Draw_Buffer::~Draw_Buffer() {
// Terminate GLFW
glfwTerminate();
}
void Draw_Buffer::flush() {
// Render pixels to image
glBindTexture(GL_TEXTURE_2D, mandelbrot_tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window->width(), window->height(), 0, GL_RGB, GL_FLOAT, &buffer[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Draw a rectangle
const static GLfloat vertices[] = {
// Position Tex-coords
-1.0f, 1.0f, 0.0f, 0.0f, // Top-left
1.0f, 1.0f, 1.0f, 0.0f, // Top-right
1.0f, -1.0f, 1.0f, 1.0f, // Bottom-right
-1.0f, -1.0f, 0.0f, 1.0f // Bottom-left
};
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STREAM_DRAW);
const static GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
GLuint ebo;
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STREAM_DRAW);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(screen.get());
}
void Draw_Buffer::keep_window_open() {
while(!glfwWindowShouldClose(screen.get())) {
glfwPollEvents();
}
}
Draw_Buffer &operator<<(Draw_Buffer &db, const RGB &pixel) {
if (db.pos_iter != db.buffer.end()) {
*(db.pos_iter) = pixel;
++db.pos_iter;
return db;
}
else {
throw std::runtime_error("error: Cannot append past end of buffer : Remember to flush the buffer");
return db;
}
}
DrawBuffer.h
#include "Window.h"
#include "Cleanup.h"
struct RGB {
float r;
float g;
float b;
};
class Draw_Buffer {
friend Draw_Buffer &operator<<(Draw_Buffer &db, const RGB &pixel);
std::unique_ptr<Window<int>> window;
std::unique_ptr<GLFWwindow, Cleaner> screen;
std::vector<RGB> buffer;
// Tracks position of appending in buffer
std::vector<RGB>::iterator pos_iter;
// Texture where pixels are written to
GLuint mandelbrot_tex;
// GLSL Shader program
GLuint shader_prog;
public:
Draw_Buffer(Window<int> *, const std::string &, const std::string &);
~Draw_Buffer();
void make_current() {
glfwMakeContextCurrent(screen.get());
}
void flush();
void keep_window_open();
};
Draw_Buffer &operator<<(Draw_Buffer &db, const RGB &pixel);
#endif //MANDELBROT_FRACTAL_DRAWER_DRAW_BUFFER_H
glUniform1i()
at some point, no? \$\endgroup\$