diff --git a/doc/GPGPU-GameOfLife-VisualStudioSolution.zip b/doc/GPGPU-GameOfLife-VisualStudioSolution.zip new file mode 100644 index 0000000..7bd6835 Binary files /dev/null and b/doc/GPGPU-GameOfLife-VisualStudioSolution.zip differ diff --git a/doc/GameOfLife-Version1.0.zip b/doc/GameOfLife-Version1.0.zip new file mode 100644 index 0000000..3eba280 Binary files /dev/null and b/doc/GameOfLife-Version1.0.zip differ diff --git a/src/PutLifeShader.frag b/src/PutLifeShader.frag new file mode 100644 index 0000000..ff3f59f --- /dev/null +++ b/src/PutLifeShader.frag @@ -0,0 +1,34 @@ +#version 130 + +uniform sampler2D inputMap; +uniform ivec2 Coord; +uniform int button; + +out vec4 outColor; + +in vec2 fTexCoord; + +void main(void){ + ivec2 pos = ivec2(gl_FragCoord[0],gl_FragCoord[1]); + vec4 data = texelFetch(inputMap, pos, 0); + ivec2 MCoord = ivec2(Coord.x, Coord.y); + + if(pos == MCoord && button == 0) + { + data[0] = 1; + data[1] = 1; + data[2] = 1; + data[3] = 1; + } + if(pos == MCoord && button == 2) + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + } + else + + outColor = data; +} + diff --git a/src/framebuffer.cpp b/src/framebuffer.cpp new file mode 100644 index 0000000..4225ab1 --- /dev/null +++ b/src/framebuffer.cpp @@ -0,0 +1,83 @@ +#include "framebuffer.hpp" + +#include +#include + +Framebuffer::Framebuffer(GLuint width, GLuint height, GLuint planes){ + this->width = width; + this->height = height; + this->planes = planes; + + buffers = new GLenum[planes]; + + glGenFramebuffers(1, &handle); + colorBuffer = new GLuint[planes]; + glGenTextures(planes, colorBuffer); + glBindFramebuffer(GL_FRAMEBUFFER, handle); + + for(unsigned int i = 0; i < planes; ++i){ + glBindTexture(GL_TEXTURE_2D, colorBuffer[i]); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, NULL); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, colorBuffer[i], 0); + buffers[i] = GL_COLOR_ATTACHMENT0 + i; + if(glGetError() != GL_NO_ERROR){ + std::cout << "Framebuffer: Error creating color attachment" << std::endl; + } + } + + glGenRenderbuffers(1, &depthBuffer); + glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer); + if(glGetError() != GL_NO_ERROR){ + std::cout << "Framebuffer: Error creating depth attachment" << std::endl; + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if(status != GL_FRAMEBUFFER_COMPLETE){ + std::cout << "Framebuffer: Incomplete framebuffer ("; + switch(status){ + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + std::cout << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + std::cout << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + std::cout << "GL_FRAMEBUFFER_UNSUPPORTED"; + break; + } + std::cout << ")" << std::endl; + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +Framebuffer::~Framebuffer(){ + glDeleteFramebuffers(1, &handle); + glDeleteRenderbuffers(1, &depthBuffer); +} + +void Framebuffer::setRenderTarget(){ + glBindFramebuffer(GL_FRAMEBUFFER, handle); + glDrawBuffers(planes, buffers); + glViewport(0,0, width, height); +} + +void Framebuffer::disableRenderTarget(){ + GLenum tmpBuff[] = { GL_COLOR_ATTACHMENT0 }; + glDrawBuffers(1, tmpBuff); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void Framebuffer::clear(){ + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0f); + setRenderTarget(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + disableRenderTarget(); +} diff --git a/src/framebuffer.hpp b/src/framebuffer.hpp new file mode 100644 index 0000000..4ca4a27 --- /dev/null +++ b/src/framebuffer.hpp @@ -0,0 +1,40 @@ +#ifndef _FRAMEBUFFER_ +#define _FRAMEBUFFER_ + +#include + +class Framebuffer{ +private: + GLuint handle; + GLuint* colorBuffer; + GLuint depthBuffer; + + GLuint width, height; + GLuint planes; + + GLenum* buffers; + +public: + Framebuffer(GLuint width, GLuint height, GLuint planes); + ~Framebuffer(); + + void setRenderTarget(); + void disableRenderTarget(); + + GLuint getColorBuffer(unsigned int plane){ + return colorBuffer[plane]; + } + + void clear(); + + int getWidth(){ + return width; + } + + int getHeight(){ + return height; + } +}; + +#endif + diff --git a/src/init.frag b/src/init.frag new file mode 100644 index 0000000..ed7b627 --- /dev/null +++ b/src/init.frag @@ -0,0 +1,19 @@ +#version 130 + + +uniform int type; + +in vec2 fTexCoord; + +out vec4 outColor; + +void main(void){ + if(type == 0) + { + outColor = vec4((tan(fTexCoord.x*25) * sin(fTexCoord.y*3) + sin(fTexCoord.y*12)),0, 0 ,1 ); + } + else + { + outColor = vec4(0,0, 0 ,1 ); + } + } \ No newline at end of file diff --git a/src/life.frag b/src/life.frag new file mode 100644 index 0000000..7caf597 --- /dev/null +++ b/src/life.frag @@ -0,0 +1,72 @@ +#version 130 + +uniform sampler2D inputMap; + +out vec4 outColor; + +in vec2 fTexCoord; + +void main(void){ + // Is current cell alive? + vec4 data = texelFetch(inputMap, ivec2(gl_FragCoord), 0); + float IsAlive = data[0]; + + // Count Neighbours + + float NumberOfNeighbours = round(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2(-1, 0), 0).x) + + round(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2( 1, 0), 0).x) + + round(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2( 0, -1), 0).x) + + round(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2( 0, 1), 0).x) + + round(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2(-1, 1), 0).x) + + round(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2( 1, 1), 0).x) + + round(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2( 1, -1), 0).x) + + round(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2(-1, -1), 0).x); + +/* + float NumberOfNeighbours = floor(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2(-1, 0), 0).x) + + floor(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2( 1, 0), 0).x) + + floor(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2( 0, -1), 0).x) + + floor(texelFetch(inputMap, ivec2(gl_FragCoord) + ivec2( 0, 1), 0).x); + */ +if(IsAlive > 0.1) +{ + //Any live cell with fewer than two live neighbours dies, as if caused by under-population. + if(NumberOfNeighbours<1.5) + { + data[0] = 0; + data[1] = 0.7; + data[2] = 0.2; + } + else + //Any live cell with two or three live neighbours lives on to the next generation. + if(NumberOfNeighbours>1.9 && NumberOfNeighbours<3.1) + { + data[0] = 1; + data[1] = 0.3; + data[2] = 0.3; + } + else + //Any live cell with more than three live neighbours dies, as if by overcrowding. + if(NumberOfNeighbours>3.1) + { + data[0] = 0; + data[1] = 0; + data[2] = 1; + } +} +else +{ + //Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. + if(NumberOfNeighbours<3.1 && NumberOfNeighbours > 2.9) + { + data[0] = 1; + data[1] = 1; + data[2] = 1; + } + else + { + data = data * 0.95; + } +} + outColor = vec4(data[0], data[1], data[2], data[3]); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..57ff39b --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,291 @@ +#include +#include + +#include + +#include "framebuffer.hpp" +#include "shader.hpp" +#include "texture.hpp" +#include "quad.hpp" +#include + +#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) +#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) + +int windowWidth = 600; +int windowHeight = 600; + +Quad* fullscreenQuad; +Texture2D* texture; +Shader* initShader; +Shader* lifeShader; +Shader* PutLifeShader; +Shader* visualize; + +int example = 1; +bool paused = false; +int zoom = 1; +int left = 0; +int top = 0; +int sleepMs = 0; + +long time = 0; +long frames; + +Framebuffer* computeBuffer[2]; +int inputBuffer = 0; +int npasses = 15; + +void init(){ + + glewExperimental = GL_TRUE; + GLenum err = glewInit(); + if (GLEW_OK != err) { + std::cerr << "Error: "<< glewGetErrorString(err) << std::endl; + } + else + { + if (GLEW_VERSION_3_3) + { + std::cout << "Driver supports OpenGL 3.3\nDetails:"<< std::endl; + std::cout << "Using GLEW: " << glewGetString(GLEW_VERSION)<< std::endl; + std::cout << "Vendor: " << glGetString (GL_VENDOR)<< std::endl; + std::cout << "Renderer: " << glGetString (GL_RENDERER)<< std::endl; + std::cout << "Version: " << glGetString (GL_VERSION)<< std::endl; + std::cout << "GLSL: " << glGetString (GL_SHADING_LANGUAGE_VERSION)<< std::endl; + } + } + + fullscreenQuad = new Quad(); + + computeBuffer[0] = new Framebuffer(600, 600, 1); + computeBuffer[1] = new Framebuffer(600, 600, 1); + + computeBuffer[0]->clear(); + computeBuffer[1]->clear(); + + initShader = new Shader("passthrough.vert", "init.frag"); + lifeShader = new Shader("passthrough.vert", "life.frag"); + visualize = new Shader("passthrough.vert", "visualize.frag"); + PutLifeShader = new Shader("passthrough.vert", "PutLifeShader.frag"); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); +} + +void Reset(int type = 0) +{ + + computeBuffer[(inputBuffer) % 2]->setRenderTarget(); + initShader->enable(); + initShader->bindUniformTexture("inputMap", computeBuffer[(inputBuffer ) % 2]->getColorBuffer(0), 0); + initShader->bindUniformInt("type", type); + fullscreenQuad->render(initShader); + initShader->disable(); + computeBuffer[(inputBuffer) % 2]->disableRenderTarget(); +} + +int i = 0; +void Render() +{ + if(i == 0) + { + inputBuffer = 0; + Reset(); + } + + frames++; + long currentTime = glutGet(GLUT_ELAPSED_TIME); + if(currentTime-time>1000) + { + std::ostringstream oss; + char str[100]; + sprintf(str, "GP GPU - Homework - Attila Bujaki - Game of Life (FPS: %f)", 1000*frames/((float)currentTime-time)); + + glutSetWindowTitle(str); + frames = 0; + time = currentTime; + } + + i++; + + if(!paused) + { + computeBuffer[(inputBuffer + 1) % 2]->setRenderTarget(); + lifeShader->enable(); + lifeShader->bindUniformTexture("inputMap", computeBuffer[inputBuffer]->getColorBuffer(0), 0); + fullscreenQuad->render(lifeShader); + lifeShader->disable(); + computeBuffer[(inputBuffer + 1) % 2]->disableRenderTarget(); + inputBuffer = (inputBuffer + 1) % 2; + Sleep(sleepMs); + } + + visualize->enable(); + visualize->bindUniformTexture("inputMap", computeBuffer[inputBuffer]->getColorBuffer(0), 0); + visualize->bindUniformInt("zoom", zoom); + visualize->bindUniformInt("top", top/zoom); + visualize->bindUniformInt("left", left/zoom); + fullscreenQuad->render(visualize); + visualize->disable(); +} + +int lastRender = -1; +void display(){ + glClearColor(0.17f, 0.4f, 0.6f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glutReshapeWindow(600, 600); + Render(); + + glutSwapBuffers(); + + glutPostRedisplay(); +} + +void PrintHelp() +{ + std::cout << "\nClick anywhere to add a living cell.\n\n Keys:\n z - zoom in\n t - zoom out\n w - move up\n s - move - down\n a - move left\n d - move right\n u - speed up\n j - speed down\n h - print this help\n space - pause/resume\n\n\t HAVE FUN! :-) "; +} + +void keyboard(unsigned char key, int x, int y){ + switch(key){ + case 27: + exit(0); + break; + case 'h': + PrintHelp(); + break; + case 'u': + if (sleepMs>5) + { + sleepMs = sleepMs - 5; + } + else + { + sleepMs = 0; + } + std::cout << "Wait each loop:" << sleepMs << "ms.\n"; + break; + case 'j': + if (sleepMs > 0) + { + sleepMs = sleepMs + 5; + } + else + { + sleepMs = 1; + } + std::cout << "Wait each loop:" << sleepMs << "ms.\n"; + break; + case 'r': + Reset(); + break; + case 'c': + Reset(1); + break; + case 'w': + top += 3 * zoom; + std::cout << "Top:" << top << "\n"; + break; + case 's': + top -= 3 * zoom; + std::cout << "Top:" << top << "\n"; + break; + case 'a': + left -= 3 * zoom; + std::cout << "Left:" << left << "\n"; + break; + case 'd': + left += 3 * zoom; + std::cout << "Left:" << left << "\n"; + break; + case 'z': + zoom++; + top += 600/zoom; + left += left/zoom; + std::cout << "Zoom:" << zoom << "\n"; + std::cout << "Top:" << top << "\n"; + std::cout << "Left:" << left << "\n"; + break; + case 't': + if(zoom>1) + { + top -= top/zoom; + left -= left/zoom; + zoom--; + std::cout << "Zoom:" << zoom << "\n"; + std::cout << "Top:" << top << "\n"; + std::cout << "Left:" << left << "\n"; + } + break; + + case ' ': + paused = !paused; + + if(paused) + { + std::cout << "Paused " << std::endl; + } + else + { + std::cout << "Started " << std::endl; + } + break; + default: + std::cout << "Unbinded key: " << (unsigned int)key << std::endl; + + PrintHelp(); + } + +} + +void PutLife(int x, int y, int button) +{ + int XCoord = left/zoom + x/zoom; + int YCoord = (top/zoom + (590-y)/zoom ); + std::cout << "Life put x: " << XCoord << " y:" << YCoord << "button:" << button << "\n"; + computeBuffer[(inputBuffer + 1) % 2]->setRenderTarget(); + PutLifeShader->enable(); + PutLifeShader->bindUniformTexture("inputMap", computeBuffer[inputBuffer]->getColorBuffer(0), 0); + PutLifeShader->bindUniformInt2("Coord", XCoord, YCoord); + PutLifeShader->bindUniformInt("button", button); + fullscreenQuad->render(PutLifeShader); + PutLifeShader->disable(); + computeBuffer[(inputBuffer + 1) % 2]->disableRenderTarget(); + inputBuffer = (inputBuffer + 1) % 2; +} + +void mouse(int button, int state, int x, int y) +{ + PutLife(x,y,button); +} + +void reshape(int width, int height){ + windowWidth = width; + windowHeight = height; + glViewport(0, 0, width, height); +} + +int main(int argc, char* argv[]){ + glutInit(&argc, argv); + glutInitContextVersion (3, 3); + glutInitContextFlags (GLUT_CORE_PROFILE | GLUT_DEBUG); + glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); + glutInitWindowSize(windowWidth, windowHeight); + glutCreateWindow("GP GPU - Homework - Attila Bujaki - Game of Life"); + init(); + + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyboard); + glutMouseFunc(mouse); + + PrintHelp(); + + glutMainLoop(); + + return(0); +} diff --git a/src/passthrough.vert b/src/passthrough.vert new file mode 100644 index 0000000..a6eae71 --- /dev/null +++ b/src/passthrough.vert @@ -0,0 +1,12 @@ +#version 130 + +in vec4 position; +in vec2 texCoord; + +out vec2 fTexCoord; + +void main(void) { + gl_Position = position; + fTexCoord = texCoord; +} + diff --git a/src/quad.cpp b/src/quad.cpp new file mode 100644 index 0000000..501e8a3 --- /dev/null +++ b/src/quad.cpp @@ -0,0 +1,43 @@ +#include "quad.hpp" + +GLfloat Quad::vertices[18] = {-1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 0.0f}; + +GLfloat Quad::texCoords[12] = {0.0f, 0.0f, + 1.0f, 0.0f, + 0.0f, 1.0f, + 0.0f, 1.0f, + 1.0f, 0.0f, + 1.0f, 1.0f}; + +Quad::Quad(){ + glGenVertexArrays(1, &vertexArray); + glBindVertexArray(vertexArray); + + glGenBuffers(1, &vertexBuffer); + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 18, vertices, GL_STATIC_DRAW); + glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); + + glGenBuffers(1, &texCoordBuffer); + glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, texCoords, GL_STATIC_DRAW); + glVertexAttribPointer((GLuint)1, 2, GL_FLOAT, GL_FALSE, 0, 0); + + glBindVertexArray(0); +} + +void Quad::render(Shader* shader){ + glBindVertexArray(vertexArray); + + shader->bindAttribLocation(0, "position"); + shader->bindAttribLocation(1, "texCoord"); + + glDrawArrays(GL_TRIANGLES, 0, 6); + + glBindVertexArray(0); +} diff --git a/src/quad.hpp b/src/quad.hpp new file mode 100644 index 0000000..1d1d2ae --- /dev/null +++ b/src/quad.hpp @@ -0,0 +1,25 @@ +#ifndef _QUAD_ +#define _QUAD_ + +#include + +#include "shader.hpp" + +class Quad{ +private: + GLuint vertexArray; + + static GLfloat vertices[18]; + GLuint vertexBuffer; + + static GLfloat texCoords[12]; + GLuint texCoordBuffer; + +public: + Quad(); + ~Quad(); + + void render(Shader* shader); +}; + +#endif diff --git a/src/shader.cpp b/src/shader.cpp new file mode 100644 index 0000000..eef65b1 --- /dev/null +++ b/src/shader.cpp @@ -0,0 +1,153 @@ +#include +#include + +#include "shader.hpp" + +Shader::Shader(){ +} + +Shader::Shader(const char* vertexShaderPath, const char* fragmentShaderPath){ + GLuint vertexProgram, fragmentProgram; + + shaderFromFile(vertexShaderPath, GL_VERTEX_SHADER, vertexProgram); + shaderFromFile(fragmentShaderPath, GL_FRAGMENT_SHADER, fragmentProgram); + linkShaders(vertexProgram, fragmentProgram, shaderProgram); + glDeleteShader(vertexProgram); + glDeleteShader(fragmentProgram); +} + +Shader::~Shader(){ +} + +void Shader::shaderFromFile(const char* shaderPath, GLenum shaderType, GLuint& handle){ + char* shaderSource = NULL; + int len = 0; + int errorFlag = -1; + + if(!fileToString(shaderPath, shaderSource, len)){ + std::cout << "Error loading shader: " << shaderPath << std::endl; + std::cout << shaderPath << std::endl; + return; + } + + handle = glCreateShader(shaderType); + + glShaderSource(handle, 1, (const char**)&shaderSource, &len); + glCompileShader(handle); + delete[] shaderSource; + + glGetShaderiv(handle, GL_COMPILE_STATUS, &errorFlag); + if(!errorFlag){ + std::cout << "Shader compile error: " << shaderPath << std::endl; + std::cout << getShaderInfoLog(handle) << std::endl; + return; + } +} + +void Shader::linkShaders(GLuint& vertexShader, GLuint& fragmentShader, GLuint& handle){ + int errorFlag = -1; + + handle = glCreateProgram(); + glAttachShader(handle, vertexShader); + glAttachShader(handle, fragmentShader); + glLinkProgram(handle); + glGetProgramiv(handle, GL_LINK_STATUS, &errorFlag); + if(!errorFlag){ + std::cout << "Shader link error: " << std::endl; + std::cout << getProgramInfoLog(handle) << std::endl; + return; + } +} + +std::string Shader::getShaderInfoLog(GLuint& object){ + int logLength = 0; + int charsWritten = 0; + char* tmpLog; + std::string log; + + glGetShaderiv(object, GL_INFO_LOG_LENGTH, &logLength); + if(logLength > 0){ + tmpLog = new char[logLength]; + glGetShaderInfoLog(object, logLength, &charsWritten, tmpLog); + log = tmpLog; + delete[] tmpLog; + } + + return log; +} + +std::string Shader::getProgramInfoLog(GLuint& object){ + int logLength = 0; + int charsWritten = 0; + char *tmpLog; + std::string log; + + glGetProgramiv(object, GL_INFO_LOG_LENGTH, &logLength); + + if (logLength > 0) { + tmpLog = new char[logLength]; + glGetProgramInfoLog(object, logLength, &charsWritten, tmpLog); + log = tmpLog; + delete[] tmpLog; + } + return log; +} + +bool Shader::fileToString(const char* path, char*& out, int& len) { + std::ifstream file(path, std::ios::ate | std::ios::binary); + if(!file.is_open()) { + return false; + } + len = file.tellg(); + out = new char[ len+1 ]; + file.seekg (0, std::ios::beg); + file.read(out, len); + file.close(); + out[len] = 0; + return true; +} + +void Shader::enable(){ + glUseProgram(shaderProgram); +} + +void Shader::disable(){ + glUseProgram(NULL); +} + +void Shader::bindUniformInt(const char* name, int i){ + GLuint vectorLocation = glGetUniformLocation(shaderProgram, name); + glUniform1i(vectorLocation, i); +} + +void Shader::bindUniformInt2(const char* name, int i1, int i2){ + GLuint vectorLocation = glGetUniformLocation(shaderProgram, name); + glUniform2i(vectorLocation, i1, i2); +} + +void Shader::bindUniformFloat(const char* name, float f){ + GLuint location = glGetUniformLocation(shaderProgram, name); + glUniform1f(location, f); +} + +void Shader::bindUniformFloat2(const char* name, float f1, float f2){ + GLuint location = glGetUniformLocation(shaderProgram, name); + glUniform2f(location, f1, f2); +} + +void Shader::bindUniformFloat3(const char* name, float f1, float f2, float f3){ + GLuint location = glGetUniformLocation(shaderProgram, name); + glUniform3f(location, f1, f2, f3); +} + +void Shader::bindUniformTexture(const char* name, GLuint texture, GLuint unit){ + GLuint location = glGetUniformLocation(shaderProgram, name); + glActiveTexture(GL_TEXTURE0 + unit); + glBindTexture(GL_TEXTURE_2D, texture); + glUniform1i(location, unit); +} + +void Shader::bindAttribLocation(GLuint id, const char* name){ + glEnableVertexAttribArray(id); + glBindAttribLocation(shaderProgram, id, name); +} diff --git a/src/shader.hpp b/src/shader.hpp new file mode 100644 index 0000000..c19d925 --- /dev/null +++ b/src/shader.hpp @@ -0,0 +1,42 @@ +#ifndef _SHADER_ +#define _SHADER_ + +#include + +#include + +class Shader{ +private: + GLuint shaderProgram; + + Shader(); + bool fileToString(const char* path, char* &out, int& len); + +public: + Shader(const char* vertexShaderPath, const char* fragmentShaderPath); + virtual ~Shader(); + + void shaderFromFile(const char* shaderPath, GLenum shaderType, GLuint& handle); + void linkShaders(GLuint& vertexShader, GLuint& fragmentShader, GLuint& handle); + + std::string getShaderInfoLog(GLuint& object); + std::string getProgramInfoLog(GLuint& object); + + void enable(); + void disable(); + + GLuint getHandle(){ + return shaderProgram; + } + + void bindUniformInt(const char* name, int i); + void bindUniformInt2(const char* name, int i1, int i2); + void bindUniformFloat(const char* name, float f); + void bindUniformFloat2(const char* name, float f1, float f2); + void bindUniformFloat3(const char* name, float f1, float f2, float f3); + void bindUniformTexture(const char* name, GLuint texture, GLuint unit); + + void bindAttribLocation(GLuint id, const char* name); +}; + +#endif diff --git a/src/texture.cpp b/src/texture.cpp new file mode 100644 index 0000000..9a9b0aa --- /dev/null +++ b/src/texture.cpp @@ -0,0 +1,65 @@ +#include + +#include "texture.hpp" + +Texture2D::Texture2D(){ +} + +Texture2D::~Texture2D(){ +} + +void Texture2D::initialize(GLuint width, GLuint height, GLuint bpp){ + this->width = width; + this->height = height; + this->bpp = bpp; + + glGenTextures(1, &handle); + glBindTexture(GL_TEXTURE_2D, handle); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, 0); + + glBindTexture(GL_TEXTURE_2D, NULL); +} + +void Texture2D::setData(float* data){ + glBindTexture(GL_TEXTURE_2D, handle); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, data); +} + +void Texture2D::loadFromFile(std::string fileName){ + ilInit(); + ILuint devilError = ilGetError(); + if(IL_NO_ERROR != devilError){ + std::cout << iluErrorString(devilError)<< std::endl; + } + + ILuint imageHandle; + ilGenImages(1, &imageHandle); + ilBindImage(imageHandle); + ilLoadImage(fileName.c_str()); + if(IL_NO_ERROR != devilError){ + std::cout << iluErrorString(devilError)<< std::endl; + } + + width = (unsigned int)ilGetInteger(IL_IMAGE_WIDTH); + height = (unsigned int)ilGetInteger(IL_IMAGE_HEIGHT); + bpp = (unsigned int)ilGetInteger(IL_IMAGE_BITS_PER_PIXEL); + + ILuint dataSize = ilGetInteger(IL_IMAGE_SIZE_OF_DATA); + + float* buffer = new float[width*height*4]; + ilCopyPixels(0,0,0, width, height, 1, IL_RGBA, IL_FLOAT, buffer); + + initialize(width, height, bpp); + setData(buffer); + + ilDeleteImages(1, &imageHandle); +} + +GLuint Texture2D::getTextureHandle(){ + return handle; +} + diff --git a/src/texture.hpp b/src/texture.hpp new file mode 100644 index 0000000..ccfb615 --- /dev/null +++ b/src/texture.hpp @@ -0,0 +1,32 @@ +#ifndef _TEXTURE_ +#define _TEXTURE_ + +#include + +#include + +// DevIL +#include +#include +#include + +class Texture2D{ +private: + GLuint handle; + GLuint width, height; + GLuint bpp; + +public: + Texture2D(); + ~Texture2D(); + + int getWidth(){ return width; } + int getHeight(){ return height; } + + void initialize(GLuint width, GLuint height, GLuint bpp); + void setData(float* data); + void loadFromFile(std::string fileName); + GLuint getTextureHandle(); +}; + +#endif diff --git a/src/visualize.frag b/src/visualize.frag new file mode 100644 index 0000000..31d301f --- /dev/null +++ b/src/visualize.frag @@ -0,0 +1,24 @@ +#version 130 + +uniform sampler2D inputMap; + +out vec4 outColor; + +in vec2 fTexCoord; +uniform int zoom; +uniform int left; +uniform int top; + +void main(void){ + ivec2 pos = ivec2(gl_FragCoord[0]/zoom + left,gl_FragCoord[1]/zoom + top); + //ivec2 pos = ivec2((gl_FragCoord[0] + left)/zoom,(gl_FragCoord[1] + top)/zoom); + + vec4 data = vec4(0.3, 0.3, 0.3, 1); + if(pos[0] < 600 && pos[1]<600 && pos[0]>=0 && pos[1]>=0) + { + data = texelFetch(inputMap, pos, 0); + } + + outColor = data; +} +