Click here to Skip to main content
15,885,366 members
Articles / Multimedia / OpenGL

Domain Coloring Method on GPU

Rate me:
Please Sign up or sign in to vote.
4.86/5 (19 votes)
27 Jan 2013MIT8 min read 52.5K   1.5K   31  
This article describes how to visualize complex-valued functions of a single complex variable using the domain coloring method on GPU.
/*
 *  Copyright (C) 2012 Khaldoon Ghanem
 *  See the file license.txt for copying permission.
 */

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


#if defined(WIN32)
	#define GLEW_STATIC
	#include <GL/glew.h>
	#include <windows.h>
#else
	#include <GL/glew.h>
#endif


#if defined(__APPLE__) || defined(MACOSX)
	#include <OpenGL/gl.h>
	#include <OpenGL/glu.h>
	#include <GLUT/glut.h>
#else
	#include <GL/glut.h>
	#include <GL/gl.h>
	#include <GL/glu.h>
#endif

#include <string.h>

GLuint v, painter, p;

#define CMAP_NUM 2
#define FUNC_MAX 64

#define SHADER_DIR "./shader/"
#define RES_DIR "./res/"

int func_num = 0;
GLuint cmap[CMAP_NUM];
GLuint func[FUNC_MAX];

char* cmap_name[CMAP_NUM] =
{ SHADER_DIR"cmap1.frag", SHADER_DIR"cmap2.frag" };
char* func_input[FUNC_MAX];
char* funcs[FUNC_MAX];

int cmap_curr = 0;
int func_curr = 0;

float w = 400, h = 400;
GLint loc;

float x0 = 0;
float y0 = 0;
float side = 4;
float scale = 2.0 / 400.0;
float m[9];

void updateView()
{
    float ratio = h / w;

    if (ratio > 1)
        scale = side / w;
    else
        scale = side / h;

    m[0] = scale;
    m[1] = 0;
    m[2] = scale * (-w / 2) + x0;
    m[3] = 0;
    m[4] = scale;
    m[5] = scale * (-h / 2) + y0;
    m[6] = 0;
    m[7] = 0;
    m[8] = 1;

    glUniformMatrix3fv(loc, GL_TRUE, 1, m);
}

void makeRect()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(-1, 1, -1, 1);
    glColor3f(1.0, 1.0, 1.0);
    glBegin (GL_POLYGON);
    glVertex2f(-1, -1);
    glVertex2f(1, -1);
    glVertex2f(1, 1);
    glVertex2f(-1, 1);
    glEnd();
}

void renderScene(void)
{
    makeRect();
    updateView();
    glutSwapBuffers();
}

int gw, gh;
void changeSize(int ww, int hh)
{

    glViewport(0, 0, ww, hh);
    //cx = cx * ww/w;
    //cy = cy * hh/h;
    if (ww != 0)
        w = ww;
    else
        w = 1;
    if (hh != 0)
        h = hh;
    else
        h = 1;
    gh = h;
    gw = w;        
}

void setProgram();

int fullscreen = 0;
int screen_pos_x;
int screen_pos_y;
int screen_w;
int screen_h;
void processNormalKeys(unsigned char key, int x, int y)
{

    //Navigation
    if (key == 'a' || key == 'A')
    {
        float delta = side / 20;
        x0 -= delta;
    }
    if (key == 'd' || key == 'D')
    {
        float delta = side / 20;
        x0 += delta;
    }
    if (key == 's' || key == 'S')
    {
        float delta = side / 20;
        y0 -= delta;
    }
    if (key == 'w' || key == 'W')
    {
        float delta = side / 20;
        y0 += delta;
    }

    if (key == 'c' || key == 'C')
    {
        x0 = 0;
        y0 = 0;
    }

    if (key == 'r' || key == 'R')
    {
        side = 4;
    }

    //Zooming
    if (key == 'e' || key == 'E')
    {
        side *= 0.9;
    }
    if (key == 'q' || key == 'Q')
    {
        side *= 1.1;
    }

    //Switch Color Map
    if (key == 32)
    {
        cmap_curr = (cmap_curr + 1) % CMAP_NUM;
        printf("Switching to color map: %s\n", cmap_name[cmap_curr]);
        setProgram();
    }

    //Switch Function
    if (key == 'x' || key == 'X')
    {
        func_curr = (func_curr + 1) % func_num;
        printf("Switching to function: f_%d(z)\n", func_curr);
        setProgram();
    }

    if (key == 'z' || key == 'Z')
    {
        func_curr = (func_curr + func_num - 1) % func_num;
        printf("Switching to function: f_%d(z)\n", func_curr);
        setProgram();
    }

    if (key >= '0' && key <= '9')
    {
        int temp = key - '0';
        if (temp != func_curr && temp < func_num)
        {
            func_curr = temp;
            printf("Switching to function: f_%d(z)\n", func_curr);
            setProgram();
        }
    }
    if (key == 'p' || key == 'P')
    {
        printf("x0: %f, y0:%lg, side:%f \n", x0, y0, side);
    }

    if (key == 'f' || key == 'F')
    {
        fullscreen = !fullscreen;
        if (fullscreen)
        {
            screen_pos_x = glutGet((GLenum) GLUT_WINDOW_X);
            screen_pos_y = glutGet((GLenum) GLUT_WINDOW_Y);
            screen_w = gw;
            screen_h = gh;
            glutFullScreen();
        }
        else
        {
            glutReshapeWindow(screen_w, screen_h);
            glutPositionWindow(screen_pos_x, screen_pos_y);
        }
    }  
    if (key == 27)
        exit(0);

}
float old_x0;
float old_y0;
int pressed = 0;

void mult(float* m, float* x, float* y)
{
    float tx = m[0] * *x + m[1] * *y + m[2];
    float ty = m[3] * *x + m[4] * *y + m[5];
    *x = tx;
    *y = ty;
}

float mouse_x;
float mouse_y;
void mouseButton(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON)
    {

        // when the button is released
        if (state == GLUT_UP)
        {
            pressed = 0;
        }
        else
        { // state = GLUT_DOWN
            mouse_x = x;
            mouse_y = y;
            old_x0 = x0;
            old_y0 = y0;
            pressed = 1;
        }
    }
    // Wheel reports as button 3(scroll up) and button 4(scroll down)
    if ((button == 3 && state == GLUT_DOWN)
            || (button == 4 && state == GLUT_DOWN))
    {
        float zoom;
        if (button == 3)
            zoom = 1.1;
        else
            zoom = 0.9;
        float xx = x;
        float yy = h - y;

        mult(m, &xx, &yy);
        float m2[9];
        m2[0] = zoom;
        m2[1] = 0;
        m2[2] = zoom * (-xx) + xx;
        m2[3] = 0;
        m2[4] = zoom;
        m2[5] = zoom * (-yy) + yy;
        m2[6] = 0;
        m2[7] = 0;
        m2[8] = 1;
        mult(m2, &x0, &y0);
        side = side * zoom;
    }
}

void mouseMove(int x, int y)
{
    if (pressed)
    {
        x0 = old_x0 + (mouse_x - x) * scale;
        y0 = old_y0 - (mouse_y - y) * scale;
    }
}

char *textFileRead(char *fn) {


	FILE *fp;
	char *content = NULL;

	int count=0;

	if (fn != NULL) {
		fp = fopen(fn,"rt");

		if (fp != NULL) {
      
      fseek(fp, 0, SEEK_END);
      count = ftell(fp);
      rewind(fp);

			if (count > 0) {
				content = (char *)malloc(sizeof(char) * (count+1));
				count = fread(content,sizeof(char),count,fp);
				content[count] = '\0';
			}
			fclose(fp);
		}
	}
	return content;
}


#define printOpenGLError() printOglError(__FILE__, __LINE__)

int printOglError(char *file, int line)
{
    //
    // Returns 1 if an OpenGL error occurred, 0 otherwise.
    //
    GLenum glErr;
    int retCode = 0;

    glErr = glGetError();
    while (glErr != GL_NO_ERROR)
    {
        printf("glError in file %s @ line %d: %s\n", file, line,
                gluErrorString(glErr));
        retCode = 1;
        glErr = glGetError();
    }
    return retCode;
}

void printShaderInfoLog(GLuint obj)
{
    int infologLength = 0;
    int charsWritten = 0;
    char *infoLog;

    glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &infologLength);

    if (infologLength > 0)
    {
        infoLog = (char *) malloc(infologLength);
        glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
        if (strlen(infoLog) > 0)
            printf("%s\n", infoLog);
        free(infoLog);
    }
}

void printProgramInfoLog(GLuint obj)
{
    int infologLength = 0;
    int charsWritten = 0;
    char *infoLog;

    glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &infologLength);

    if (infologLength > 0)
    {
        infoLog = (char *) malloc(infologLength);
        glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
        if (strlen(infoLog) > 0)
            printf("%s\n", infoLog);
        free(infoLog);
    }
}

void setShaders()
{
    char *vs = NULL;
    char *painters = NULL;
    char *cmaps[CMAP_NUM];

    v = glCreateShader(GL_VERTEX_SHADER);
    painter = glCreateShader(GL_FRAGMENT_SHADER);
    for (int i = 0; i < func_num; i++)
        func[i] = glCreateShader(GL_FRAGMENT_SHADER);
    for (int i = 0; i < CMAP_NUM; i++)
        cmap[i] = glCreateShader(GL_FRAGMENT_SHADER);

    vs = textFileRead(SHADER_DIR"fixed.vert");
    painters = textFileRead(SHADER_DIR"painter.frag");
    for (int i = 0; i < CMAP_NUM; i++)
        cmaps[i] = textFileRead(cmap_name[i]);

    const char * _v = vs;
    const char * _painter = painters;
    const char * _func[FUNC_MAX];
    for (int i = 0; i < func_num; i++)
        _func[i] = funcs[i];

    const char * _cmap[CMAP_NUM];
    for (int i = 0; i < CMAP_NUM; i++)
        _cmap[i] = cmaps[i];

    glShaderSource(v, 1, &_v, NULL);
    glShaderSource(painter, 1, &_painter, NULL);
    for (int i = 0; i < func_num; i++)
        glShaderSource(func[i], 1, &_func[i], NULL);
    for (int i = 0; i < CMAP_NUM; i++)
        glShaderSource(cmap[i], 1, &_cmap[i], NULL);

    free(vs);
    free(painters);
    for (int i = 0; i < CMAP_NUM; i++)
        free(cmaps[i]);

    glCompileShader(v);
    int isCompiled;
    glGetShaderiv(v, GL_COMPILE_STATUS, &isCompiled);
    if(isCompiled == 0)
    {
        printf("Vertex Shader - Compilation Error!\n");
        printShaderInfoLog(v);
        exit(1);
    }
        
    glCompileShader(painter);
    glGetShaderiv(painter, GL_COMPILE_STATUS, &isCompiled);
    if(isCompiled == 0)
    {
        printf("Painter Fragment Shader - Compilation Error!\n");
        printShaderInfoLog(painter);
        exit(1);
    }
    
    for (int i = 0; i < func_num; i++)
    {
        glCompileShader(func[i]);
        glGetShaderiv(func[i], GL_COMPILE_STATUS, &isCompiled);
        if(isCompiled == 0)
        {
            printf("Function '%d' Fragment Shader - Compilation Error!\n", i);
            printShaderInfoLog(func[i]);
            exit(1);
        }        
    }
    for (int i = 0; i < CMAP_NUM; i++)
    {
        glCompileShader(cmap[i]);
        glGetShaderiv(cmap[i], GL_COMPILE_STATUS, &isCompiled);
        if(isCompiled == 0)
        {
            printf("'ColorMap %s' Fragment Shader - Compilation Error!\n", cmap_name[i]);
            printShaderInfoLog(cmap[i]);
            exit(1);
        }          
    }
    
    p = -1;        
}

void setProgram()
{
    if(p!=-1)
        glDeleteProgram(p);
    p = glCreateProgram();
    glAttachShader(p, v);
    glAttachShader(p, painter);
    glAttachShader(p, func[func_curr]);
    glAttachShader(p, cmap[cmap_curr]);

    glLinkProgram(p);
    int IsLinked;
    glGetProgramiv(p, GL_LINK_STATUS, (int *)&IsLinked);
    if(IsLinked == 0)
    {
        printf("Shading Program - Linking Error!\n");
        printProgramInfoLog(p);
        exit(1);
    }

    glUseProgram(p);

    loc = glGetUniformLocation(p, "windowToComplex");
}

void yyparse();
void myprintf(char** s, const char * format, int num, ...);

int main(int argc, char **argv)
{
    myprintf(&funcs[0], "%s\nvec2 f(vec2 z){ return z; }", 1,
            textFileRead(SHADER_DIR"complex.frag"));

    func_input[0] = (char*) malloc(sizeof(char) * 2);
    func_input[0][0] = 'z';
    func_input[0][1] = '\0';
    func_num++;

    yyparse();

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(w, h);
    glutCreateWindow("Domain Coloring Method on GPU");

    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);
    glutReshapeFunc(changeSize);
    glutKeyboardFunc(processNormalKeys);
    glutMouseFunc(mouseButton);
    glutMotionFunc(mouseMove);

    glClearColor(1.0, 1.0, 1.0, 1.0);

    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        /* Problem: glewInit failed, something is seriously wrong. */
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
        return 1;
    }

    if (!glewIsSupported("GL_VERSION_2_0"))
    {
        printf("OpenGL 2.0 not supported\n");
        exit(1);
    }

    setShaders();

    setProgram();

    char* control = textFileRead(RES_DIR"control.txt");
    printf("%s", control);
    free(control);

    printf("Functions as written in shader:\n");
    printf("-------------------------------\n");
    for (int i = 0; i < func_num; i++)
        printf("f_%d(z) = %s\n", i, func_input[i]);
    printf("_________________________________________________\n");
    glutMainLoop();

    return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Student RWTH Aachen
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions