0
\$\begingroup\$

I've asked this question on regular StackOverflow but without much success yet. The below program produces a segfault on the call to glDrawElements. I've looked at my max and min index values and they do not go over the length of GLushort and match up to the size of my vertex array. I don't get the segfault if I use a smaller number of rings and sectors for my sphere; but I don't think this has much to do with it.

As far as I can tell I've loaded by buffers correctly; however I'm new to OpenGL and this is such a simple program that I must be doing something simple wrong.

I've tried using GLIntercept but it doesn't give me anything additional

#include <exception>
#include <iostream>
#include <fstream>
#include <sstream>
#include <list>
#include <string>
#include <algorithm>
#include <functional>

#include <utilities.hpp>

#include <GL/glew.h>
#include <SDL2/sdl.h>
#define GLM_FORCE_RADIANS
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>

struct VertexData
{
    GLdouble position[4];
    GLfloat color[3];
    GLfloat normal[3];
    GLfloat tcoords[2];
};

int main(int argc, char* argv[])
{
    try
    {
        SDL_Window* window;
        SDL_GLContext context;
        if(SDL_Init(SDL_INIT_VIDEO) < 0)
            throw std::runtime_error("unable to initialise video");

        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4);

        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);

        window = SDL_CreateWindow("SpaceEngine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        800, 800, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
        if(!window)
            throw std::runtime_error("unable to create window");

        context = SDL_GL_CreateContext(window);

        SDL_GL_SetSwapInterval(1);

        GLenum glewErr = glewInit();
        if(glewErr != GLEW_OK)
        {
            SDL_GL_DeleteContext(context);
            SDL_DestroyWindow(window);
            SDL_Quit();
            throw std::runtime_error(reinterpret_cast<const char*>(glewGetErrorString(glewErr)));
        }

        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LESS);

        std::vector<VertexData> vertices;
        std::vector<GLushort> indices;
        int rings = 200;
        int sectors = 200;
        float radius = 1.0;

        if(rings < 2)
            rings = 2;
        if(sectors < 2)
            sectors = 2;
        while(rings * sectors >= std::numeric_limits<GLushort>::max())
        {
            rings /= 2;
            sectors /= 2;
        }

        const GLuint polyCountXPitch = rings+1;

        GLuint level = 0;

        for(GLuint p1 = 0; p1 < sectors-1; ++p1)
        {
            for(GLuint p2 = 0; p2 < rings-1; ++p2)
            {
                GLuint curr = level + p2;
                indices.push_back(curr + polyCountXPitch);
                indices.push_back(curr);
                indices.push_back(curr + 1);
                indices.push_back(curr + polyCountXPitch);
                indices.push_back(curr + 1);
                indices.push_back(curr + 1 + polyCountXPitch);
            }

            indices.push_back(level + rings - 1 + polyCountXPitch);
            indices.push_back(level + rings - 1);
            indices.push_back(level + rings);

            indices.push_back(level + rings - 1 + polyCountXPitch);
            indices.push_back(level + rings);
            indices.push_back(level + rings + polyCountXPitch);

            level += polyCountXPitch;
        }

        const GLuint polyCountSq = polyCountXPitch * sectors;           //top point
        const GLuint polyCountSq1 = polyCountSq + 1;                    //bottom point
        const GLuint polyCountSqM1 = (sectors - 1) * polyCountXPitch;   //last rows first index

        for(GLuint p2 = 0; p2 < rings - 1; ++p2)
        {
            indices.push_back(polyCountSq);
            indices.push_back(p2 + 1);
            indices.push_back(p2);

            indices.push_back(polyCountSqM1 + p2);
            indices.push_back(polyCountSqM1 + p2 + 1);
            indices.push_back(polyCountSq1);
        }

        indices.push_back(polyCountSq);
        indices.push_back(rings);
        indices.push_back(rings - 1);

        indices.push_back(polyCountSqM1 + rings - 1);
        indices.push_back(polyCountSqM1);
        indices.push_back(polyCountSq1);

        const GLdouble angleX = 2 * pi() / rings;
        const GLdouble angleY = pi() / sectors;

        GLuint i = 0;
        GLdouble axz;
        GLdouble ay = 0;

        vertices.resize(polyCountXPitch * sectors + 2);
        for(GLuint y = 0; y < sectors; ++y)
        {
            ay += angleY;
            const GLdouble sinay = std::sin(ay);
            axz = 0;

            for(GLuint xz = 0; xz < rings; ++xz)
            {
                const glm::vec3 pos((radius * std::cos(axz) * sinay),radius * std::cos(ay), radius * std::sin(axz) * sinay);
                glm::vec3 normal = pos;
                normal = glm::normalize(normal);

                GLuint tu = 0.5f;
                if(y == 0)
                {
                    if(normal.y != -1.0f && normal.y != 1.0f)
                        tu = std::acos(glm::clamp<GLdouble>(normal.x/sinay, -1.0f, 1.0f)) * 0.5 * (1.0f/pi());
                    if(normal.z < 0.0f)
                        tu = 1 - tu;
                }
                else
                    tu = vertices[i-polyCountXPitch].tcoords[0];

                VertexData v;
                v.color[0] = 1;
                v.color[1] = 1;
                v.color[2] = 1;
                v.position[0] = pos.x;
                v.position[1] = pos.y;
                v.position[2] = pos.z;
                v.position[3] = 1.0f;
                v.normal[0] = normal.x;
                v.normal[1] = normal.y;
                v.normal[2] = normal.z;
                v.tcoords[0] = tu;
                v.tcoords[1] = ay * (1.0f/pi());
                vertices.at(i) = v;

                ++i;
                axz += angleX;
            }

            vertices.at(i) = vertices.at(i - rings);
            vertices.at(i).tcoords[0] = 1.0f;
            ++i;
        }

        VertexData v;
        v.color[0] = 1;
        v.color[1] = 1;
        v.color[2] = 1;
        v.position[0] = 0;
        v.position[1] = radius;
        v.position[2] = 0;
        v.position[3] = 1.0f;
        v.normal[0] = 0;
        v.normal[1] = 1;
        v.normal[2] = 0;
        v.tcoords[0] = 0.5f;
        v.tcoords[1] = 0.0f;
        vertices.at(i) = v;
        ++i;
        v.position[1] = -radius;
        v.normal[1] = -1.0f;
        v.tcoords[1] = 1.0f;
        vertices.at(i) = v;

        GLuint vao;
        glGenVertexArrays(1,&vao);
        glBindVertexArray(vao);

        GLuint vbo;
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(struct VertexData) * vertices.size(), vertices.data(), GL_STATIC_DRAW);

        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, position));
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, color));
        glEnableVertexAttribArray(2);
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, normal));
        glEnableVertexAttribArray(3);
        glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, tcoords));

        GLuint ibo;
        glGenBuffers(1, &ibo);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), indices.data(), GL_STATIC_DRAW);

        glBindVertexArray(0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

        GLuint shader1,shader2;
        std::ifstream file("tutorial2.vert");
        if(!file)
            throw std::runtime_error("The file tutorial2.vert was not opened");
        else
        {
            std::string fileContents((std::istreambuf_iterator<char>(file)),std::istreambuf_iterator<char>());

            shader1 = glCreateShader(GL_VERTEX_SHADER);
            std::string fail = "glCreateShader failed using " + GL_VERTEX_SHADER;

            if(!shader1)
                throw std::runtime_error(fail.c_str());

            const GLchar* contents[1];
            contents[0] = fileContents.c_str();
            glShaderSource(shader1, 1, contents, NULL);

            glCompileShader(shader1);
            int compiled;
            glGetShaderiv(shader1, GL_COMPILE_STATUS, &compiled);
            if(compiled == 0)
            {
                int maxLength;
                glGetShaderiv(shader1, GL_INFO_LOG_LENGTH, &maxLength);
                char* vertexInfoLog = new char[maxLength];
                glGetShaderInfoLog(shader1, maxLength, &maxLength, vertexInfoLog);
                throw std::runtime_error("Shader failed to compile:\n>\t" + std::string(vertexInfoLog));
            }
        }
        std::ifstream file2("tutorial2.frag");
        if(!file2)
            throw std::runtime_error("The file tutorial2.frag was not opened");
        else
        {
            std::string fileContents((std::istreambuf_iterator<char>(file2)),std::istreambuf_iterator<char>());

            shader2 = glCreateShader(GL_FRAGMENT_SHADER);
            std::string fail = "glCreateShader failed using " + GL_FRAGMENT_SHADER;
            if(!shader2)
                throw std::runtime_error(fail.c_str());

            const GLchar* contents[1];
            contents[0] = fileContents.c_str();
            glShaderSource(shader2, 1, contents, NULL);

            glCompileShader(shader2);
            int compiled;
            glGetShaderiv(shader2, GL_COMPILE_STATUS, &compiled);
            if(compiled == 0)
            {
                int maxLength;
                glGetShaderiv(shader2, GL_INFO_LOG_LENGTH, &maxLength);
                char* vertexInfoLog = new char[maxLength];
                glGetShaderInfoLog(shader2, maxLength, &maxLength, vertexInfoLog);
                throw std::runtime_error("Shader failed to compile:\n>\t" + std::string(vertexInfoLog));
            }
        }

        GLuint program = glCreateProgram();
        if(!program)
            throw std::runtime_error("glCreateProgram failed");

        glAttachShader(program, shader1);
        glAttachShader(program, shader2);

        glBindAttribLocation(program, 0, "in_Position");
        glBindAttribLocation(program, 1, "in_Color");
        glBindAttribLocation(program, 2, "in_Normal");
        glBindAttribLocation(program, 3, "in_UV");

        glLinkProgram(program);
        int IsLinked;
        glGetProgramiv(program, GL_LINK_STATUS, (int *)&IsLinked);
        if(IsLinked == 0)
        {
           int maxLength;
           glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
           char* shaderProgramInfoLog = new char[maxLength];
           glGetProgramInfoLog(program, maxLength, &maxLength, shaderProgramInfoLog);
           throw std::runtime_error("Program failed to link:\n>\t" + std::string(shaderProgramInfoLog) + "");
        }

        glDetachShader(program, shader1);
        glDetachShader(program, shader2);

        bool done = false;

        while(!done)
        {
            SDL_Event event;
            while(SDL_PollEvent(&event))
            {
                switch(event.type)
                {
                case SDL_WINDOWEVENT:
                    switch(event.window.event)
                    {
                    case SDL_WINDOWEVENT_CLOSE:
                        done = true;
                        break;
                    }
                    break;
                }
            }

            glClearColor(0.0, 0.0, 0.0, 1.0);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            glUseProgram(program);

            glBindVertexArray(vao);

            glDrawElements(GL_TRIANGLES,indices.size(),GL_UNSIGNED_SHORT,0);

            glBindVertexArray(0);

            glUseProgram(0);

            SDL_GL_SwapWindow(window);
            }

        glUseProgram(0);
        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);

        glDeleteProgram(program);
        glDeleteBuffers(1, &vbo);
        glDeleteVertexArrays(1, &vao);

        SDL_GL_DeleteContext(context);
        SDL_DestroyWindow(window);
        SDL_Quit();

        std::cout << "all good in the hood" << std::endl;
    }
    catch(const std::exception& e)
    {
        std::cout << "ERROR:\t" << e.what() << std::endl;
    }
    catch(...)
    {
        std::cout << "ERROR" << std::endl;
    }
    exit(EXIT_SUCCESS);
}

My Vertex shader:

#version 150

precision highp float;

in vec4 in_Position;
in vec3 in_Color;
in vec3 in_Normal;
in vec2 in_UV;

uniform mat4 mvpmatrix;

out vec3 ex_Color;
void main(void) 
{
    gl_Position = in_Position;

    ex_Color = in_Color;
}

And my Frag shader:

#version 150

precision highp float;

in  vec3 ex_Color;
out vec4 gl_FragColor;

void main(void) 
{
    gl_FragColor = vec4(ex_Color,1.0);
}

EDIT

I believe the problem is in the way the element array is being setup for the indices.

GLuint vao;
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);

GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(struct VertexData) * vertices.size(), vertices.data(), GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, color));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, normal));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, tcoords));

GLuint ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), indices.data(), GL_STATIC_DRAW);

glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

EDIT2

I've even tried outputing a line of text to a file and iterate through each triangle in my indices 1 by 1. If I run it a few times I find the segfault happens at different points in the indices array. The vertex that the index is looking up is within bounds of my vertices array.

for(int i = 0; i < tt; i+=3)
{
    file << "attempting " << i/3 << std::endl;
    glDrawElements(GL_TRIANGLES,i,GL_UNSIGNED_SHORT,0);
    SDL_GL_SwapWindow(sdlglHandler);
}

So this tells me that I'm trying to access a index that is outside of the bounds from what I sent to the GL_ELEMENT_ARRAY_BUFFER but again, I cannot see the problem.

\$\endgroup\$
  • \$\begingroup\$ Please only show the code that you suspect has the problem. \$\endgroup\$ – concept3d Sep 21 '14 at 6:22
  • \$\begingroup\$ @concept3d, thank you for your reply, please see my edit. I've found that I can stop the error by reducing the number of indices used in the glDrawElements call, but the number is variable, which tells me I'm not loading them into the buffer correctly. But reviewing the documentation for OpenGL again and again and every tutorial I can find, I do not see the issue in the way it's being populated. \$\endgroup\$ – NeomerArcana Sep 21 '14 at 6:34
1
\$\begingroup\$

The issue was in using GL_DOUBLE for the vertices. Changing to GL_FLOAT seems to have done the trick.

You need to use glVertexAttribLPointer when using double.

EDIT That is not completely accurate. glVertexAttribLPointer (...) is for double and dvecN vertex attributes, which your shader is not using. To use glVertexAttribLPointer meaningfully would require you to re-write a line in your shader (in dvec4 in_Position)

\$\endgroup\$
  • \$\begingroup\$ That is not completely accurate. glVertexAttribLPointer (...) is for double and dvecN vertex attributes, which your shader is not using. To use glVertexAttribLPointer meaningfully would require you to re-write a line in your shader (in dvec4 in_Position). \$\endgroup\$ – Andon M. Coleman Sep 21 '14 at 15:02
  • \$\begingroup\$ @AndonM.Coleman Ah, yes. Thanks for clearing that up \$\endgroup\$ – NeomerArcana Sep 22 '14 at 1:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.