/*
* 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;
}