Here is the error message I am recieving from VS2010:
Unhandled exception at 0x77358dc9 in AzimuthalEqui.exe:
0xC0000005: Access violation writing location 0x00000014.
The line of code generating this error is:
texture[1] = SOIL_load_OGL_texture
(
texture_filename,
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID, // create ID automatically
SOIL_flags
);
before entering this function:
texture_filename = "Data/texture.jpg"
SOIL_LOAD_AUTO (= 0)
SOIL_CREATE_NEW_ID (=0)
SOIL_flags = 16 (=SOIL_FLAG_INVERT_Y)
The problem is that when I include a file I have written to parse some information in a text file an error is generated, otherwise the texture loads and is displayed. The prob is most likely caused by one function as when this particular function is removed the code loads and displays the texture.
Here is the function that when added to my project makes the error occur:
[CODE]
void get_user_points(double *lats, double *longs){
char buffer[BUFFSIZE_PARSE];
char *p_buff = buffer;
FILE *fp;
const char *filename = "Points.txt";
double temp;
double *tmp_p = &temp;
fp = fopen(filename,"r+");
if (fp == NULL)
{
sprintf(buffer, "Can't Find File: %s", filename);
MessageBoxA(NULL, buffer, "ERROR", MB_OK|MB_ICONEXCLAMATION);
exit(0);
}
fgets(buffer, BUFFSIZE_PARSE, fp);
while (*(p_buff+1) != '\0'){
p_buff = get_next_letter(p_buff);
switch (tolower(*p_buff)){
case 'n':
putchar(*p_buff);
p_buff++;
p_buff=get_next_double(lats, p_buff);
printf(" = %f\n", *lats);
break;
case 's':
...
...
}
}
putchar('\n');
fclose(fp);
}
It has something to do with opening the file for reading... if I comment out these lines the texture loads correctly:
//fpr = fopen(filename2,"rb");
...
...
...
//fclose(fpr);
Here is my reduced code (i don't think this is the issue but just in case). [There may be some remanants of my full code]:
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
{
printf("Initialising...\n");
glutInitWindowSize(700, 700);
glutInitWindowPosition(0, 0);
glutCreateWindow ("SOIL Texture Test");
}
InitGL();
glutDisplayFunc(DrawGLScene);
glutReshapeFunc(ReSizeGLScene);
glutMainLoop();
return 0;
}
int InitGL(GLvoid) // Setup OpenGL
{
//Load textures
if (!LoadGLTextures()) // Jump To Texture Loading Routine ( NEW )
{
MessageBox(NULL,TEXT("Cannot Load Image for Texture Map"),TEXT("Error!"),MB_OK | MB_ICONINFORMATION);
//return false; // If Texture Didn't Load Return FALSE ( NEW )
}
else
glEnable(GL_TEXTURE_2D); // Enable texture mapping
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Set the background colour (to black)
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // Select testing type
//get_user_points(&user_lat[0], &user_long[0]);
return true; // Initialization went OK
}
void DrawGLScene(GLvoid) // OpenGL drawing function
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the Screen and the Depth Buffer
glLoadIdentity();
glTranslatef(0.0f,0.0f,z);
glBindTexture (GL_TEXTURE_2D, texture[filter]);
glBegin (GL_QUADS);
glNormal3f(0, 0, 1);
glTexCoord2f (0,0);
glVertex3f (-3,-3 ,0);
glTexCoord2f (1,0 );
glVertex3f (3,-3 , 0);
glTexCoord2f (1, 1);
glVertex3f (3,3 , 0);
glTexCoord2f (0,1 );
glVertex3f (-3,3 ,0 );
glEnd();
glFlush();
}
void ReSizeGLScene(int w, int h) // Code to resize (and initialise) the OpenGL scene (run once when in fullscreen mode)
{
// Set up perspective view matrix
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)w/(GLfloat)h, 0.1f, 100.0f);
//glOrtho(-50.0, 50.0, -50.0, 50.0, -50.0, 50.0);
// Set up modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int LoadGLTextures(void) // Load Bitmaps And Convert To Textures
{
unsigned int SOIL_flags;
GLint mag_param;
GLint min_param;
printf("Loading Textures... ");
SOIL_flags = SOIL_FLAG_INVERT_Y;
mag_param = GL_NEAREST;
min_param = GL_NEAREST;
texture[1] = SOIL_load_OGL_texture
(
texture_filename,
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID, // create ID automatically
SOIL_flags
);
if(texture[1] == 0)
return false;
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,mag_param);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,min_param);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
printf("Textures Loaded\n");
return true;
}
Including the .c files in my project instead of the .lib file fixed the problem.
Related
I want to display a texture but the compiler (Visual Studio 2017) gives me this error:
Exception thrown at 0x69F1454A (nvoglv32.dll) in Playground.exe: 0xC0000005: Access violation reading location 0x0A08D000.
The loadBMP_custom function has been taken from this website:
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/
Any help is going to be appreciated.
This is my code:
#include <GL\freeglut.h>
#include <stdio.h>
GLuint loadBMP_custom(const char * imagepath) {
unsigned char header[54];
unsigned int width, height;
unsigned int imageSize;
GLuint textureID;
unsigned char * data;
FILE * file;
file = fopen(imagepath, "rb");
printf("%s\n", imagepath);
if (!file) {
printf("Image could not be opened\n");
return 0;
}
if (fread(header, 1, 54, file) != 54) {
printf("Not a correct BMP file\n");
}
if (header[0] != 'B' || header[1] != 'M') {
printf("Not a correct BMP file\n");
}
imageSize = *(int*)&(header[0x22]); //34
width = *(int*)&(header[0x12]); //18
height = *(int*)&(header[0x16]); //22
if (imageSize == 0) imageSize = width*height * 3;
data = (unsigned char* )malloc(imageSize);
fread(data, 1, imageSize, file);
fclose(file);
for (int i = 0; i < width * height; ++i)
{
int index = i * 3;
unsigned char B, R;
B = data[index];
R = data[index + 2];
data[index] = R;
data[index + 2] = B;
}
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureID;
}
void displayMe(void) {
GLuint bmp;
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glPushMatrix();
bmp = loadBMP_custom("C:\\Dev\\Playground\\Release\\template.bmp");
glBindTexture(GL_TEXTURE_2D, bmp);
glBegin(GL_POLYGON);
glTexCoord2f(0.0, 0.0);
glVertex2f(0.0, 0.0);
glTexCoord2f(0.1, 0.0);
glVertex2f(0.1, 0.0);
glTexCoord2f(0.1, 0.1);
glVertex2f(0.1, 0.1);
glTexCoord2f(0.0, 0.1);
glVertex2f(0.0, 0.1);
glEnd();
glPopMatrix();
glutSwapBuffers();
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 30.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -3.6);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(800, 800);
glutCreateWindow("hi");
glutDisplayFunc(displayMe);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
if (imageSize == 0) imageSize = width*height * 3;
[...]
data = (unsigned char* )malloc(imageSize);
[...]
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
You are telling OpenGL that it should interpret the data pointer as describing an image with RGBA components at each pixel, each as bytes, but you provide only RGB data, which means that the GL will access beyond the end of your buffer.
The last three parameters of glTexImage describe the image data in client memory: the numer and order of the channels, the data format for each channel, and the pointer to the first pixel. The GL_RGB you use as internalFormat just describes the format the GL shall internally store the texture at.
The correct code should be
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // use tightly-packed data buffer with no padding between image rows
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
I have two buffers with .rgb images loaded. Original image is stored in frame_buffer and second one is stored in temp_buffer. I want to switch between those two images in GLUT window, when user press a button, how can I extend my code to do this?
typedef struct pixel{
GLbyte r;
GLbyte g;
GLbyte b;
}Pixel;
Pixel frame_buffer[WIDTH][HEIGHT]; //original image
Pixel temp_buffer[WIDTH][HEIGHT]; //embossed image
GLuint texture;
int window_id;
void keyboardFunction(unsigned char button, int x, int y){
switch(button){
case 'S':
case 's':
// WHEN USER PRESS 'S', NEW IMAGE FROM temp_buffer IS
// LOADED, HOW CAN I DO THIS?
break;
default:
break;
}
glutPostRedisplay();
}
// Initialize OpenGL state
void init() {
// Texture setup
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
// Other
glClearColor(0, 0, 0, 0);
gluOrtho2D(-1, 1, -1, 1);
glLoadIdentity();
glColor3f(1, 1, 1);
loadInputFromUser();
emboss();
}
void display() {
// Copy frame_buffer to texture memory
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, frame_buffer);
// Clear screen buffer
glClear(GL_COLOR_BUFFER_BIT);
// Render a quad
glBegin(GL_QUADS);
glTexCoord2f(1, 0); glVertex2f(1, 1);
glTexCoord2f(1, 1); glVertex2f(1, -1);
glTexCoord2f(0, 1); glVertex2f(-1, -1);
glTexCoord2f(0, 0); glVertex2f(-1, 1);
glEnd();
// Display result
glFlush();
//glutPostRedisplay();
glutSwapBuffers();
}
// Main entry function
int main(int argc, char **argv) {
// Init GLUT
glutInit(&argc, argv);
glutInitWindowPosition(-1, -1);
glutInitWindowSize(WIDTH, HEIGHT);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutCreateWindow("Convolution Filter");
// Set up OpenGL state
init();
// Run the control loop
glutDisplayFunc(display);
glutKeyboardFunc(keyboardFunction);
glutReshapeFunc(changeViewPoint);
GLenum err = glewInit();
if (GLEW_OK != err){
fprintf(stderr, "GLEW error");
return 1;
}
glutMainLoop();
return EXIT_SUCCESS;
}
original image stored in frame_buffer
image filtered with emboss stored in temp_buffer (yeah I know its not perfect :D )
I want to switch between them with keybutton.
Edit the following snippets:
Pixel frame_buffer[WIDTH][HEIGHT]; //original image
Pixel temp_buffer[WIDTH][HEIGHT]; //embossed image
int which_image = 0;
...
case 'S':
case 's':
which_image ^= 1;
break;
...
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, which_image == 0 ? frame_buffer : temp_buffer);
...
glFlush();
glutPostRedisplay();
glutSwapBuffers();
That being said, you currently upload the texture (glTexImage2D) for each frame drawn. You should rather upload it only once during startup and each time it changes.
Ok. I'm getting into opengl 2.1(without the fixed function stuff) and I'm having troubles with shaders. I declare my uniform variable on my shader, and in my program I get the uniform location and assign it a value with gluniform but it doesn't seem to work.
These are my shaders
fragment shader:
#version 120
varying float color;
void
main ()
{
gl_FragColor = vec4(color, 0, 0, 1);
}
and my vertex shader:
#version 120
attribute vec2 position;
varying float color;
uniform float pr_color;
void
main ()
{
color = pr_color;
gl_Position = vec4(position, 0.0, 1.0);
}
This is how I'm passing the data to the shader:
void
display ()
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(g_program);
pos_loc = glGetAttribLocation(g_program, "position");
col_loc = glGetUniformLocation(g_program, "pr_color");
glUniform1f(col_loc, 1.0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(pos_loc);
glVertexAttribPointer(pos_loc, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glDrawArrays(GL_TRIANGLES, 0, 3);
glutPostRedisplay();
glutSwapBuffers();
}
and i don't think this is needed, but in any case, my initgl function
void
init ()
{
// Set clear color to black
glClearColor(0.0,0.0,0.0,0.0);
vshader = createShader(GL_VERTEX_SHADER, "vertex.glsl");
fshader = createShader(GL_FRAGMENT_SHADER, "fragment.glsl");
g_program = createProgram(vshader, fshader);
// Create vbo and send it the vertex data
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
}
the thing is, my shaders are working, if I hardcode the color into the fragment sahder, then the triangle is drawn, but if I pass the color to the vertex shader, it doesn't work, the triangle is drawn to black, which is strange, because my position attribute works, but my color uniform is set to 0. As you can see, I'm setting useprogram() before passing the uniform value.
EDIT: I changed the gluniform1i(col_loc, 1) to glUniformif(col_loc, 1.0). Still doesn't work
EDIT: I'll add my shader loading function to make sure the problem is not in the shader
GLuint
createShader (GLenum type, char* filename)
{
GLuint shader;
// Load file
FILE* file;
file = fopen(filename, "r");
if (file == NULL)
{
printf("Error reading file \n");
}
// Get Length
fseek(file, 0, SEEK_END);
long length = ftell(file);
fseek(file, 0, SEEK_SET);
// Get source
char* source;
source = malloc( (size_t) length + 1);
if (source == NULL)
{
printf("Error alocating space for shader\n");
}
// Read file
fread(source, 1, length, file);
// Close file
fclose(file);
source[length] = '\n';
// Create shader, attach it's source and compile it
shader = glCreateShader(type);
glShaderSource(shader, 1, (const GLchar*)&source, &length);
free(source); // Free shader source, once it's attached
glCompileShader(shader);
// Check for errors
GLint shader_status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_status);
if (!shader_status) {
fprintf(stderr, "Failed to compile %s:\n", filename);
GLint log_length;
char *log;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
log = malloc(log_length);
glGetShaderInfoLog(shader, log_length, NULL, log);
fprintf(stderr, "%s", log);
free(log);
glDeleteShader(shader);
return 0;
}
return shader;
}
When there's an error in the shader, the program actually prints the error log, so I don't think the error is in here, but anyway, here it is.
EDIT: program linker code
GLuint
createProgram (GLuint vertexs, GLuint fragments)
{
GLint program_ok;
// Create program and attach to shaders
GLuint program = glCreateProgram();
glAttachShader(program, vertexs);
glAttachShader(program, fragments);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &program_ok);
if (!program_ok) {
fprintf(stderr, "Failed to link shader program:\n");
GLint log_length;
char *log;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
log = malloc(log_length);
glGetProgramInfoLog(program, log_length, NULL, log);
fprintf(stderr, "%s", log);
free(log);
glDeleteProgram(program);
return 0;
}
return program;
}
Please tell me if there's anything wrong with my shaders/program, I was just starting to get the basics of programmable pipeline and now I can't even render a triangle
You are using
glUniform1i(col_loc, 1);
To set the value of
uniform float pr_color;
1i stands for 1 int. Use 1f for 1 float.
glUniform1f(col_loc, 1.0f);
OK, I got it working with glUnifrom4fv(). I am now passing a vec4 to the shader's color variable and it works!
I'm having issues loading a texture onto my triangle strips. I'm following Anton Gerdelan's tutorial, and after failing with my main program, I went back to the basics and just tried to make a plain square and put his texture on it (the skull and crossbones).
I completely copy and pasted code from his "Hello Triangle" page, which worked, but once trying to fit in code from his texture tutorial above (and changing the triangle to a square), all I'm getting is a big white square with no texture.
I've checked the status of my shaders with glGetShaderiv() and they returned positive, I checked the image I loaded to see if the pixel data was sensible, so I believe my error is in declaring my VBOs, or the order/parameters in which I'm using them.
Here's the complete code which I copied, which compiles fine in Visual Studio 2013, except the output isn't what is expected.
I am using the static libraries of GLEW and GLFW, along with the STBI Image header
#include <GL/glew.h> // include GLEW and new version of GL on Windows
#include <GL/glfw3.h> // GLFW helper library
#include <stdio.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
const char* vertex_shader =
"#version 400\n"
"in vec3 vp;"
"layout (location=1) in vec2 vt; // per-vertex texture co-ords"
"out vec2 texture_coordinates; "
"void main () {"
" gl_Position = vec4 (vp, 1.0);"
" texture_coordinates = vt; "
"}";
const char* fragment_shader =
"#version 400\n"
"in vec2 texture_coordinates;"
"uniform sampler2D basic_texture;"
"out vec4 frag_colour;"
"void main () {"
"vec4 texel = texture(basic_texture, texture_coordinates);"
"frag_colour = texel; "
"}";
float points[] = {
-0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f
};
float texcoords[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0
};
GLFWwindow* window;
unsigned int vt_vbo;
unsigned int tex = 0;
GLuint vao = 0;
GLuint vbo = 0;
GLuint shader_programme;
void initializeGL(){
// start GL context and O/S window using the GLFW helper library
if (!glfwInit()) {
printf("ERROR: could not start GLFW3\n");
return;
}
window = glfwCreateWindow(640, 480, "Texture Test", NULL, NULL);
if (!window) {
printf("ERROR: could not open window with GLFW3\n");
glfwTerminate();
return;
}
glfwMakeContextCurrent(window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit();
// get version info
const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
const GLubyte* version = glGetString(GL_VERSION); // version as a string
printf("Renderer: %s\n", renderer);
printf("OpenGL version supported %s\n", version);
// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
}
void startShaders(){
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vertex_shader, NULL);
glCompileShader(vs);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fragment_shader, NULL);
glCompileShader(fs);
shader_programme = glCreateProgram();
glAttachShader(shader_programme, fs);
glAttachShader(shader_programme, vs);
glLinkProgram(shader_programme);
GLint vsstat;
glGetShaderiv(vs, GL_COMPILE_STATUS, &vsstat);
GLint fsstat;
glGetShaderiv(fs, GL_COMPILE_STATUS, &fsstat);
printf("%i\n%i\n", vsstat, fsstat);
}
void loadImage(){
int x, y, n;
int force_channels = 4;
unsigned char* image_data = stbi_load("skulluvmap.png", &x, &y, &n, force_channels);
if (!image_data) {
printf("ERROR: could not load %s\n", "skulluvmap.png");
}
int width_in_bytes = x * 4;
unsigned char *top = NULL;
unsigned char *bottom = NULL;
unsigned char temp = 0;
int half_height = y / 2;
for (int row = 0; row < half_height; row++) {
top = image_data + row * width_in_bytes;
bottom = image_data + (y - row - 1) * width_in_bytes;
for (int col = 0; col < width_in_bytes; col++) {
temp = *top;
*top = *bottom;
*bottom = temp;
top++;
bottom++;
}
}
printf("first 4 bytes are: %i %i %i %i\n",
image_data[0], image_data[1], image_data[2], image_data[3]
);
glGenTextures(1, &tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void generateBuffers(){
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0); // don't forget this!
glGenBuffers(1, &vt_vbo);
glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), texcoords, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(1); // don't forget this!
}
void mainLoop(){
while (!glfwWindowShouldClose(window)) {
// wipe the drawing surface clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int tex_loc = glGetUniformLocation(shader_programme, "basic_texture");
glUseProgram(shader_programme);
glUniform1i(tex_loc, 0); // use active texture 0
// draw points 0-4 from the currently bound VAO with current in-use shader
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// update other events like input handling
glfwPollEvents();
// put the stuff we've been drawing onto the display
glfwSwapBuffers(window);
}
}
int main() {
initializeGL();
startShaders();
loadImage();
generateBuffers();
mainLoop();
// close GL context and any other GLFW resources
glfwTerminate();
return 0;
}
You're misusing your second buffer which is supposed to be the buffer with texcoords. So what you really want to achieve is having a pair of texture coordinates for every vertex. It means that you texcoords array should in fact store 4 pairs because you have 4 triples in the points array. So that's the first fix. You probably want it to look like:
float texcoords[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0, 0.0,
1.0, 1.0,
};
Then in the generateBuffers, your vt_vbo is wrong. The data should be passed this way:
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), texcoords, GL_STATIC_DRAW);
because you only want to pass 8 values there. 2 texcoords for each vertex.
Edit:
This however, doesn't fully explain why your texture doesn't appear at all. I primarily thought that there might be a problem with your texcoords pointer but it doesn't seem to be the case.
I am trying to write a basic volume renderer which uses opengl, and cg for writing shaders. I'm putting my transfer function in a one dimensional texture, and using that in a dependent texture lookup in the fragment shader. My problem is that I'm getting an openGL error when I try to enable the parameter corresponding to that 1D texture.
My code is pretty messy; right now it's basically a mashup of code taken from "Real-Time Volume Rendering" and "The CG User's Manual".
c file:
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <Cg/cg.h>
#include <Cg/cgGL.h>
static CGcontext myCgContext;
static CGprofile myCgVertexProfile,
myCgFragmentProfile;
static CGprogram myCgVertexProgram,
myCgFragmentProgram;
static const char *myProgramName = "first_volumetric_renderer",
*myVertexProgramFileName = "fvr_vertex.cg",
*myVertexProgramName = "fvr_vertex",
*myFragmentProgramFileName = "fvr_fragment.cg",
*myFragmentProgramName = "fvr_fragment";
static CGparameter first_texture, second_texture, transfer_function;
#define XDIM 256
#define YDIM 256
#define ZDIM 256
#define TRANSFER_RESOLUTION 256
static GLubyte raw_data[XDIM][YDIM][ZDIM];
static GLubyte transfer[TRANSFER_RESOLUTION][4];
static GLuint transfer_name;
static GLuint x_textures[XDIM], y_textures[YDIM], z_textures[ZDIM];
static void checkForCgError(const char *situation);
/* print any errors if we get them */
void check_gl_error(const char * where){
GLenum error = glGetError();
if(error != GL_NO_ERROR){
printf("openGL Error : %s : %s\n", where, gluErrorString(error));
exit(1);
}
}
long int file_length(FILE *f){
long int pos = ftell(f);
fseek(f, 0, SEEK_END);
long int result = ftell(f);
fseek(f, pos, SEEK_SET);
return result;
}
void get_volume_data(const char *filename){
FILE *in = fopen(filename, "r");
if(in == NULL) {
printf("opening '%s' to get volume data failed, exiting...\n", filename);
exit(1);
}
long int length = file_length(in);
if(length != XDIM*YDIM*ZDIM){
printf("the file does not contain a volume of the correct dimensions\n");
exit(1);
}
size_t res = fread((char *)raw_data, 1, length, in);
if(res < length) printf("error reading in file\n");
fclose(in);
}
void create_textures(){
glEnable(GL_TEXTURE_2D);
// reserve texture identifiers
glGenTextures(XDIM, x_textures);
glGenTextures(YDIM, y_textures);
glGenTextures(ZDIM, z_textures);
// set texture properties
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// generate slices in X
{
int x,y,z;
GLubyte x_slice[ZDIM][YDIM];
for(x=0;x < XDIM; x++){
for(y=0;y < YDIM; y++){
for(z=0;z < ZDIM; z++){
x_slice[z][y] = raw_data[x][y][z];
}
}
GLuint texname = x_textures[x];
glBindTexture(GL_TEXTURE_2D, texname);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, ZDIM, YDIM, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, x_slice);
}
}
// generate slices in Y
{
int x,y,z;
GLubyte y_slice[XDIM][ZDIM];
for(y=0;y < YDIM; y++){
for(x=0;x < XDIM; x++){
for(z=0;z < ZDIM; z++){
y_slice[x][z] = raw_data[x][y][z];
}
}
GLuint texname = y_textures[y];
glBindTexture(GL_TEXTURE_2D, texname);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, XDIM, ZDIM, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, y_slice);
}
}
// generate slices in Z
{
int x,y,z;
GLubyte z_slice[XDIM][YDIM];
for(z=0;z < ZDIM; z++){
for(y=0;y < YDIM; y++){
for(x=0;x < XDIM; x++){
z_slice[x][y] = raw_data[x][y][z];
}
}
GLuint texname = z_textures[z];
glBindTexture(GL_TEXTURE_2D, texname);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, XDIM, YDIM, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, z_slice);
}
}
}
void DrawSliceStack_NegativeZ(int numSlices){
double dZPos = -1.0;
double dZStep = 2.0/((double)numSlices);
int slice;
for(slice = 0;slice < numSlices;slice++){
double dZPosTex = (ZDIM * (dZPos + 1.0)/2.0);
int nTexIdx = (int)dZPosTex;
double dAlpha = dZPosTex - (double)nTexIdx;
check_gl_error("in slice-drawing function, before cg-stuff");
cgGLSetTextureParameter(first_texture, z_textures[nTexIdx]);
checkForCgError("setting first texture");
check_gl_error("1");
cgGLEnableTextureParameter(first_texture);
checkForCgError("enabling first texture");
check_gl_error("2");
cgGLSetTextureParameter(second_texture, z_textures[nTexIdx + 1]);
checkForCgError("setting second texture");
check_gl_error("3");
cgGLEnableTextureParameter(second_texture);
checkForCgError("enabling second texture");
check_gl_error("4");
cgGLSetTextureParameter(transfer_function, transfer_name);
checkForCgError("setting transfer function");
check_gl_error("5");
cgGLEnableTextureParameter(transfer_function);
checkForCgError("enabling transfer function");
check_gl_error("before updating parameters");
cgUpdateProgramParameters(myCgFragmentProgram);
checkForCgError("updating parameters");
check_gl_error("before drawing a slice");
glBegin(GL_QUADS);
glTexCoord3d(0.0, 0.0, dAlpha);
glVertex3d(-1.0, -1.0, dZPos);
glTexCoord3d(0.0, 1.0, dAlpha);
glVertex3d(-1.0, 1.0, dZPos);
glTexCoord3d(1.0, 1.0, dAlpha);
glVertex3d(1.0, 1.0, dZPos);
glTexCoord3d(1.0, 0.0, dAlpha);
glVertex3d(1.0, -1.0, dZPos);
glEnd();
check_gl_error("after drawing a slice");
dZPos += dZStep;
cgGLDisableTextureParameter(first_texture);
checkForCgError("disabling first texture");
cgGLDisableTextureParameter(second_texture);
checkForCgError("disabling second texture");
cgGLDisableTextureParameter(transfer_function);
checkForCgError("disabling transfer function");
}
}
void create_transfer_texture(){
glEnable(GL_TEXTURE_1D);
// create the raw data
int i;
for(i = 0; i < TRANSFER_RESOLUTION; i++){
if(i < 50) {
transfer[i][0] = (GLubyte)0;
transfer[i][1] = (GLubyte)0;
transfer[i][2] = (GLubyte)0;
transfer[i][3] = (GLubyte)0;
}
else {
transfer[i][0] = (GLubyte)255;
transfer[i][1] = (GLubyte)255;
transfer[i][2] = (GLubyte)255;
transfer[i][3] = (GLubyte)i;
}
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &transfer_name);
glBindTexture(GL_TEXTURE_3D, transfer_name);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, TRANSFER_RESOLUTION, 0, GL_RGBA, GL_UNSIGNED_BYTE, transfer);
check_gl_error("creating transfer texture");
}
static void checkForCgError(const char *situation)
{
CGerror error;
const char *string = cgGetLastErrorString(&error);
if (error != CG_NO_ERROR) {
printf("%s: %s: %s\n",
myProgramName, situation, string);
if (error == CG_COMPILER_ERROR) {
printf("%s\n", cgGetLastListing(myCgContext));
}
exit(1);
}
}
void init_CG(){
// copy-pasted straight from one of the CG examples
myCgContext = cgCreateContext();
checkForCgError("creating context");
cgGLSetDebugMode(CG_FALSE);
cgSetParameterSettingMode(myCgContext, CG_DEFERRED_PARAMETER_SETTING);
myCgFragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
cgGLSetOptimalOptions(myCgFragmentProfile);
checkForCgError("selecting fragment profile");
myCgFragmentProgram =
cgCreateProgramFromFile(
myCgContext, /* Cg runtime context */
CG_SOURCE, /* Program in human-readable form */
myFragmentProgramFileName, /* Name of file containing program */
myCgFragmentProfile, /* Profile: OpenGL ARB vertex program */
myFragmentProgramName, /* Entry function name */
NULL); /* No extra compiler options */
checkForCgError("creating fragment program from file");
cgGLLoadProgram(myCgFragmentProgram);
checkForCgError("loading fragment program");
first_texture = cgGetNamedParameter(myCgFragmentProgram, "text0");
checkForCgError("could not get 'texture0'");
second_texture = cgGetNamedParameter(myCgFragmentProgram, "text1");
checkForCgError("could not get 'texture1'");
transfer_function = cgGetNamedParameter(myCgFragmentProgram, "transfer_function");
checkForCgError("could not get 'transfer_function'");
check_gl_error("initializing CG");
}
void reshape(int w, int h)
{
if (h == 0) h = 1;
glViewport(0, 0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2, 2, -2, 2, -2, 2); // use orthographic projection
glMatrixMode(GL_MODELVIEW);
}
void display(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* cgGLBindProgram(myCgVertexProgram);
checkForCgError("binding vertex program");
cgGLEnableProfile(myCgVertexProfile);
checkForCgError("enabling vertex profile");*/
cgGLBindProgram(myCgFragmentProgram);
checkForCgError("binding fragment program");
cgGLEnableProfile(myCgFragmentProfile);
checkForCgError("enabling fragment profile");
check_gl_error("before entering slice-drawing function");
DrawSliceStack_NegativeZ(ZDIM * 2);
/*cgGLDisableProfile(myCgVertexProfile);
checkForCgError("disabling vertex profile");*/
cgGLDisableProfile(myCgFragmentProfile);
checkForCgError("disabling fragment profile");
glutSwapBuffers();
check_gl_error("Finishing 'display()'");
}
void keyboard(unsigned char c, int x, int y){
}
void init_glut(int argc, char** argv){
glutInitWindowSize(400, 400);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInit(&argc, argv);
glutCreateWindow(myProgramName);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutReshapeFunc(reshape);
glClearColor(1.0, 0.0, 0.0, 0.0); /* Black background */
}
int main(int argc, char **argv){
init_glut(argc, argv);
init_CG();
get_volume_data("aneurism.raw");
create_textures();
create_transfer_texture();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutMainLoop();
return 0;
}
fragment shader (fvr_fragment.cg):
float4 fvr_fragment(half3 texUV : TEXCOORD0,
uniform sampler2D text0,
uniform sampler2D text1,
uniform sampler1D transfer_function) : COLOR
{
half tex0 = tex2D(text0, texUV.xy);
half tex1 = tex2D(text1, texUV.xy);
half interp = lerp(tex0, tex1, texUV.z);
float4 result = tex1D(transfer_function, interp);
return result;
}
the volume data
When run, the program outputs:
openGL Error : before updating parameters : invalid operation
the line which causes the error, which I found thanks to my ad-hoc print debugging, is:
cgGLEnableTextureParameter(transfer_function);
Any ideas?
Your error is here
glBindTexture(GL_TEXTURE_3D, transfer_name);
It should read
glBindTexture(GL_TEXTURE_1D, transfer_name);