0

I'm new to OpenGL and I am trying to get a mandelbrot set computed with OpenGL and GLFW.

I found the code here but freeglut is broken on my system and for some reason complains about no callback being set even though it clearly is being set. It does however flash one frame and then crash, in that frame I can see the mandelbrot set so I know the math is correct.

I figured this would be a good opportunity to learn more about OpenGL and GLFW, so I set to work making this happen.

After double checking everything, I can see that it definitely calculates the values then switches the buffers properly.

However, I think I'm missing two things:

  1. A vertex which the texture can actually be applied to

EDIT: (from learnopengl.com) "Once glTexImage2D is called, the currently bound texture object now has the texture image attached to it.", so it can't be #2

  1. not sure what's happening with the calculation but it looks like it's binding a texture named 'texture' but then calculating the values in a struct array which don't seem to be associated in any way. I bind the texture with tex (texture) and then send the struct array to glTexImage2D

If someone could just point me in the right direction or confirm my suspicions that would be awesome.

My code is here:

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>

    #define  GLEW_STATIC
    #include <GL/glew.h>
    #include <pthread.h>

    #include <GLFW/glfw3.h>

    #include <GL/gl.h>

    #define VAL 255

    typedef struct {
      uint8_t r; 
      uint8_t g;
      uint8_t b;
    }rgb_t;

    rgb_t **tex_array = 0;
    rgb_t *image;
    int gwin;
    int width = 640;
    int height = 480;
    int tex_w, tex_h;
    double scale = 1./256;
    double cx = -.6, cy = 0;
    int color_rotate = 0;
    int saturation = 1;
    int invert = 0;
    int max_iter = 256;
    int dump = 1;
    GLFWwindow* window;
    int global_iterator = 0;
    int conversion_iterator_x = 0;
    int conversion_iterator_y = 0;

    GLFWwindow* init_glfw();
    void set_texture(GLuint tex); 
    void framebuffer_size_callback(GLFWwindow* window, int width, int height);
    void render(GLuint tex);
    void screen_dump();
    void keypress(unsigned char key, int x, int y);
    void hsv_to_rgb(int hue, int min, int max, rgb_t *p);
    void calc_mandel(rgb_t* px);
    void alloc_texture();
    void set_texture();
    void mouseclick(int button, int state, int x, int y);
    void resize(int w, int h);
    void framebuffer_size_callback(GLFWwindow* window, int width, int height);


    int main(int c, char **v)
    {

      GLFWwindow* win = init_glfw();
      glfwSetWindowPos(win, 1000, 500);

      GLuint texture;
      glGenTextures(1, &texture);
      set_texture(texture);

      /* Loop until the user closes the window */
           while (!glfwWindowShouldClose(win))
        {

            render(texture);  

            /* Swap front and back buffers */
            glfwSwapBuffers(win);

            /* Poll for and process events */
            glfwPollEvents();

            if(glfwGetKey(win, GLFW_KEY_ESCAPE) == GLFW_PRESS){
               glfwSetWindowShouldClose(win, GL_TRUE);
            }
        }

        return 0;
    }


    void set_texture(GLuint tex)
    {
      printf("Allocating space\n");
        alloc_texture();
      printf("Calculating mandel... %d\n", global_iterator);
      ++global_iterator;
        calc_mandel(image);
      printf("mandel calculation complete\n");

        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, tex);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_w, tex_h,
            0, GL_RGB, GL_UNSIGNED_BYTE, tex_array[0]);

      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

      printf("Rendering to screen...\n");
        render(tex);
    }

    void alloc_texture()
    {
        int i;
      int ow = tex_w;
      int oh = tex_h;

        for (tex_w = 1; tex_w < width;  tex_w <<= 1);
        for (tex_h = 1; tex_h < height; tex_h <<= 1);

        if (tex_h != oh || tex_w != ow){
            tex_array = realloc(tex_array, tex_h * tex_w * 3 + tex_h * sizeof(rgb_t*));
      }

        for (tex_array[0] = (rgb_t *)(tex_array + tex_h), i = 1; i < tex_h; i++){
            tex_array[i] = tex_array[i - 1] + tex_w;
      }
    }


    void render(GLuint tex)
    {
        double  x = (double)width /tex_w,
            y = (double)height/tex_h;

        glClear(GL_COLOR_BUFFER_BIT);
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

        glBindTexture(GL_TEXTURE_2D, tex);

        glBegin(GL_QUADS);

        glTexCoord2f(0, 0); glVertex2i(0, 0);
        glTexCoord2f(x, 0); glVertex2i(width, 0);
        glTexCoord2f(x, y); glVertex2i(width, height);
        glTexCoord2f(0, y); glVertex2i(0, height);

        glEnd();

        glFlush();
        glFinish();
    }

    GLFWwindow* init_glfw()
    {

        /* Initialize the library */
        if (!glfwInit()){
            return NULL;
        }

        /*
         * Configure window options here if you so desire
         *
         * i.e.
         */
         glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
         glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
         glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
         //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

         //glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);


        //the fourth parameter of glfwCreateWindow should be NULL for windowed mode and 
        //glfGetPrimaryMonitor() for full screen mode
        /* Create a windowed mode window and its OpenGL context */
        window = glfwCreateWindow(width, height, "Mandelbrot", NULL, NULL);
        if (!window)
        {
            glfwTerminate();
            return NULL;
        }

        /* Make the window's context current */
        glfwMakeContextCurrent(window);
        glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

        /*
         * Initialize glew here
         */

        glewExperimental = GL_TRUE;
        glewInit();


      return window;

    }


    void calc_mandel(rgb_t* px)
    {
        int i, j, iter, min, max;
        double x, y, zx, zy, zx2, zy2;

      min = max_iter; 
      max = 0;

      for (i = 0; i < height; i++) {
            px = tex_array[i];
            y = (i - height/2) * scale + cy;
            for (j = 0; j  < width; j++, px++) {
                x = (j - width/2) * scale + cx;
                iter = 0;
                zx = hypot(x - .25, y);

                if (x < zx - 2 * zx * zx + .25){
            iter = max_iter;
          }
                if ((x + 1)*(x + 1) + y * y < 1/16){
            iter = max_iter;
          }

                zx = zy = zx2 = zy2 = 0;
                for (; iter < max_iter && zx2 + zy2 < 4; iter++) {
                    zy = 2 * zx * zy + y;
                    zx = zx2 - zy2 + x;
                    zx2 = zx * zx;
                    zy2 = zy * zy;
                }

                if (iter < min){
            min = iter;
          }
                if (iter > max){ 
            max = iter;
          }
                *(unsigned short *)px = iter;
            }
        }

        for (i = 0; i < height; i++){
            for (j = 0, px = tex_array[i]; j  < width; j++, px++){
                hsv_to_rgb(*(unsigned short*)px, min, max, px);
        }
      }

    }

    void hsv_to_rgb(int hue, int min, int max, rgb_t *p)
    {

      printf("Converting hsv to rbg... \n");
        if (min == max){
        max = min + 1;
      }
        if (invert){
        hue = max - (hue - min);
      }
        if (!saturation) {
            p->r = p->g = p->b = 255 * (max - hue) / (max - min);
            printf("done! (!saturation)\n");
        return;
        }
        double h = fmod(color_rotate + 1e-4 + 4.0 * (hue - min) / (max - min), 6);
        double c = VAL * saturation;
        double X = c * (1 - fabs(fmod(h, 2) - 1));

        p->r = p->g = p->b = 0;

        switch((int)h) {
        case 0: p->r = c; p->g = X; break;
        case 1: p->r = X; p->g = c; break;
        case 2: p->g = c; p->b = X; break;
        case 3: p->g = X; p->b = c; break;
        case 4: p->r = X; p->b = c; break;
        default:p->r = c; p->b = X; break;
        }
        printf("done! (sauration)\n");
    }

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
    glOrtho(0, width, 0, height, -1, 1);
    //set_texture();
}




  [1]: https://rosettacode.org/wiki/Mandelbrot_set#PPM_non_interactive
BitShift
  • 977
  • 2
  • 9
  • 28
  • You're using [Legacy OpenGL](https://www.khronos.org/opengl/wiki/Legacy_OpenGL) so you've to use a compatibility profile [OpenGL Context](https://www.khronos.org/opengl/wiki/OpenGL_Context) . `glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE)` – Rabbid76 Jun 26 '19 at 06:48
  • Do `glViewport(0, 0, width, height);` `glLoadIdentity();` `glOrtho(0, width, 0, height, -1, 1);` once at the end of `init_glfw()`. Note, `glLoadIdentity();` should be done in `framebuffer_size_callback`, too. – Rabbid76 Jun 26 '19 at 06:51
  • Brilliant, thank you so much!!! Ok so that code is written in an older version of OpenGL, EXCELLENT!!! I'll have to get working on updating it to modern GL. Just out of curiosity: what was the smoking gun when you looked at the code? i.e. how did you know it was legacy? – BitShift Jun 26 '19 at 06:56
  • Drawing by [`glBegin`/`glEnd`](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glBegin.xml) and fixed function matrix stack. Read about [Vertex Specification](https://www.khronos.org/opengl/wiki/Vertex_Specification) and [Shader](https://www.khronos.org/opengl/wiki/Shader) for a state of the art way of rendering. – Rabbid76 Jun 26 '19 at 06:59
  • Awesome, yeh I thought it was odd that there weren't any vertices or shaders in the code. Good to know. Thanks again! – BitShift Jun 26 '19 at 07:30
  • see my [Can't find a way to color the Mandelbrot-set the way i'm aiming for](https://stackoverflow.com/a/56197067/2521214) ... In case you are a rookie see: [complete GL+GLSL+VAO/VBO C++ example](https://stackoverflow.com/a/31913542/2521214) to get started – Spektre Jun 27 '19 at 18:01

0 Answers0