From a4fa46a4fda967348ea18961c177330491bdb953 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 15 Dec 2009 02:25:40 +0100 Subject: Added nice lighting shaders --- CMakeLists.txt | 6 ++-- FindGLEW.cmake | 16 +++++++++ Game.cpp | 54 +++++++++++++++++++++++------- Game.h | 1 + Shader.cpp | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++ Shader.h | 41 +++++++++++++++++++++++ gl.h | 1 + shader/default.frag | 44 +++++++++++++++++++++++++ shader/default.vert | 25 ++++++++++++++ zoom.cpp | 34 ++++++++----------- 10 files changed, 283 insertions(+), 34 deletions(-) create mode 100644 FindGLEW.cmake create mode 100644 Shader.cpp create mode 100644 Shader.h create mode 100644 shader/default.frag create mode 100644 shader/default.vert diff --git a/CMakeLists.txt b/CMakeLists.txt index 6135c41..305c938 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,11 @@ set(CMAKE_MODULE_PATH ${ZOOM_SOURCE_DIR}) find_package(Boost REQUIRED) find_package(OpenGL REQUIRED) +find_package(GLEW REQUIRED) find_package(GLPng REQUIRED) find_package(LibXml2 REQUIRED) -include_directories(${Boost_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} ${GLPNG_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) +include_directories(${Boost_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} ${GLEW_INCLUDE_DIR} ${GLPNG_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) add_executable(zoom BSPTree.cpp BSPTree.h @@ -17,9 +18,10 @@ add_executable(zoom gl.h Level.cpp Level.h Renderer.cpp Renderer.h + Shader.cpp Shader.h Texture.cpp Texture.h Triangle.h zoom.cpp ) -target_link_libraries(zoom ${Boost_LIBRARIES} ${OPENGL_LIBRARIES} ${GLPNG_LIBRARY} ${LIBXML2_LIBRARIES}) +target_link_libraries(zoom ${Boost_LIBRARIES} ${OPENGL_LIBRARIES} ${GLEW_LIBRARY} ${GLPNG_LIBRARY} ${LIBXML2_LIBRARIES}) diff --git a/FindGLEW.cmake b/FindGLEW.cmake new file mode 100644 index 0000000..cf743e0 --- /dev/null +++ b/FindGLEW.cmake @@ -0,0 +1,16 @@ +FIND_PATH(GLEW_INCLUDE_DIR GL/glew.h) +FIND_LIBRARY(GLEW_LIBRARY NAMES GLEW) + +IF (GLEW_INCLUDE_DIR AND GLEW_LIBRARY) + SET(GLEW_FOUND TRUE) +ENDIF (GLEW_INCLUDE_DIR AND GLEW_LIBRARY) + +IF (GLEW_FOUND) + IF (NOT GLEW_FIND_QUIETLY) + MESSAGE(STATUS "Found GLEW: ${GLEW_LIBRARY}") + ENDIF (NOT GLEW_FIND_QUIETLY) +ELSE (GLEW_FOUND) + IF (GLEW_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find GLEW") + ENDIF (GLEW_FIND_REQUIRED) +ENDIF (GLEW_FOUND) diff --git a/Game.cpp b/Game.cpp index 46f942f..d948b2f 100644 --- a/Game.cpp +++ b/Game.cpp @@ -20,12 +20,13 @@ #include "Game.h" #include "BSPTree.h" #include "Level.h" +#include "Shader.h" #include "Triangle.h" #include "gl.h" namespace Zoom { -Game::Game(bool multisample) : angle(0) { +Game::Game(bool multisample) : angle(0), lightPos(0) { glClearColor(0.0, 0.0, 0.0, 1.0); glClearDepth(1.0); glEnable(GL_DEPTH_TEST); @@ -42,19 +43,23 @@ Game::Game(bool multisample) : angle(0) { glShadeModel(GL_SMOOTH); glEnable(GL_LIGHTING); - static const float light[] = {0, 0, 0, 1}; - static const float lightColor[] = {1, 1, 1, 1}; - glLightfv(GL_LIGHT0, GL_POSITION, light); - glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor); + glLightfv(GL_LIGHT0, GL_AMBIENT, vmml::vec4f::ZERO.array); + glLightfv(GL_LIGHT0, GL_DIFFUSE, vmml::vec4f::ONE.array); + glLightfv(GL_LIGHT0, GL_SPECULAR, vmml::vec4f::ONE.array); + glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0); + glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.3); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, vmml::vec4f::ONE.array); + glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 128); + glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); - glLoadIdentity(); + Shader::loadProgram("default.vert", "default.frag"); loadLevel("level.xml"); } @@ -70,21 +75,46 @@ void Game::run(int delta) { if(angle >= 360) angle -= 360; + + lightPos += delta; + lightPos %= 24000; } void Game::render() { - std::list triangles; + int i; + float light[] = {0, 0, 0, 1}; + + if(lightPos < 12000) i = lightPos; + else i = 24000 - lightPos; + + if(i < 4000) { + light[0] = 0.0; + light[2] = -i * 0.001; + } + else if(i < 8000) { + light[0] = (i-4000) * 0.001; + light[2] = -4.0; + } + else if(i < 12000) { + light[0] = 4.0; + light[2] = -4.0 - (i-8000) * 0.001; + } + else { + light[0] = 4.0; + light[2] = -8.0; + } - triangles.insert(triangles.end(), level->getRooms().front().walls.begin(), level->getRooms().front().walls.end()); + glLightfv(GL_LIGHT0, GL_POSITION, light); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); - glRotatef(angle, 1, 2, 1); - //glRotatef(3*angle, 0, -1, 2); - //glRotatef(5*angle, 2, -1, 0); + //glRotatef(10, 1, 2, 1); + /*glRotatef(5*angle, 0, -1, 2); + glRotatef(7*angle, 2, -1, 0); + glRotatef(11*angle, 2, -1, 2);*/ - renderer.render(triangles); + renderer.render(level->getRooms().front().walls); glPopMatrix(); } diff --git a/Game.h b/Game.h index 7960497..f651125 100644 --- a/Game.h +++ b/Game.h @@ -43,6 +43,7 @@ class Game { boost::shared_ptr level; float angle; + int lightPos; }; } diff --git a/Shader.cpp b/Shader.cpp new file mode 100644 index 0000000..420b6c6 --- /dev/null +++ b/Shader.cpp @@ -0,0 +1,95 @@ +/* + * Shader.cpp + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#include "Shader.h" +#include +#include +#include +#include + +namespace Zoom { + +bool Shader::loadProgram(const std::string &vertexShader, const std::string &fragmentShader) { + GLhandleARB program, vs = 0, fs = 0; + + if(!vertexShader.empty()) + vs = loadShader(vertexShader, GL_VERTEX_SHADER_ARB); + + if(!fragmentShader.empty()) + fs = loadShader(fragmentShader, GL_FRAGMENT_SHADER_ARB); + + program = glCreateProgramObjectARB(); + + if(vs) + glAttachObjectARB(program, vs); + + if(fs) + glAttachObjectARB(program, fs); + + glLinkProgramARB(program); + printInfoLog(program); + + glUseProgramObjectARB(program); + + return true; +} + +GLhandleARB Shader::loadShader(const std::string &name, GLenum type) { + std::vector lines; + std::ifstream file(("shader/" + name).c_str(), std::ios_base::in); + if(!file.good()) + throw std::ios::failure("Can't read file '" + name + "'"); + + while(file.good() && !file.eof()) { + std::string line; + std::getline(file, line); + + if(!line.empty()) + lines.push_back(line); + } + + boost::scoped_array strings(new const char*[lines.size()]); + for(std::size_t i = 0; i < lines.size(); ++i) { + strings[i] = lines[i].c_str(); + } + + GLhandleARB shader = glCreateShaderObjectARB(type); + glShaderSourceARB(shader, lines.size(), strings.get(), 0); + glCompileShaderARB(shader); + printInfoLog(shader); + + return shader; +} + +void Shader::printInfoLog(GLhandleARB obj) { + int length = 0; + + glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + + if(length > 0) { + boost::scoped_array log(new char[length]); + + int foo; + glGetInfoLogARB(obj, length, &foo, log.get()); + std::cerr << log.get() << std::endl; + } +} + + +} diff --git a/Shader.h b/Shader.h new file mode 100644 index 0000000..8111f0c --- /dev/null +++ b/Shader.h @@ -0,0 +1,41 @@ +/* + * Shader.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#ifndef ZOOM_SHADER_H_ +#define ZOOM_SHADER_H_ + +#include "gl.h" +#include + +namespace Zoom { + +class Shader { + public: + static bool loadProgram(const std::string &vertexShader, const std::string &fragmentShader); + + private: + Shader(); + + static GLhandleARB loadShader(const std::string &name, GLenum type); + static void printInfoLog(GLhandleARB obj); +}; + +} + +#endif /* ZOOM_SHADER_H_ */ diff --git a/gl.h b/gl.h index 22e0523..3272b25 100644 --- a/gl.h +++ b/gl.h @@ -25,6 +25,7 @@ #include #endif +#include #include #include diff --git a/shader/default.frag b/shader/default.frag new file mode 100644 index 0000000..b39b46d --- /dev/null +++ b/shader/default.frag @@ -0,0 +1,44 @@ +uniform sampler2D tex; + +varying vec4 diffuse, ambientGlobal, ambient; +varying vec3 normal, pos; +/*varying vec3 normal, lightVector, reflectVector, eyeVector;*/ + + +void main() { + vec3 n, l, refl, eye; + float NdotL, RdotE; + vec4 color, specularColor; + float dist, att, specularFactor; + + color = ambientGlobal; + + n = normalize(normal); + + l = gl_LightSource[0].position.xyz - pos; + + dist = length(l); + l /= dist; + + /* compute the dot product between normal and normalized lightdir */ + NdotL = max(dot(n, l), 0.0); + + if (NdotL > 0.0) { + att = 1.0 / (gl_LightSource[0].constantAttenuation + + gl_LightSource[0].linearAttenuation * dist + + gl_LightSource[0].quadraticAttenuation * dist * dist); + color += att * (diffuse * NdotL + ambient); + + refl = normalize(reflect(-l, n)); + eye = normalize(-pos); + + RdotE = max(dot(refl, eye), 0.0); + specularFactor = att * pow(RdotE, gl_FrontMaterial.shininess); + specularColor = specularFactor * gl_FrontMaterial.specular * gl_LightSource[0].specular; + } + else { + specularColor = vec4(0, 0, 0, 1); + } + + gl_FragColor = color * texture2D(tex, gl_TexCoord[0].st) + specularColor; +} diff --git a/shader/default.vert b/shader/default.vert new file mode 100644 index 0000000..133c871 --- /dev/null +++ b/shader/default.vert @@ -0,0 +1,25 @@ +varying vec4 diffuse, ambientGlobal, ambient; +varying vec3 normal, pos; +/*varying vec3 normal, lightVector, reflectVector, eyeVector;*/ + + +void main() { + normal = normalize(gl_NormalMatrix * gl_Normal); + + pos = vec3(gl_ModelViewMatrix * gl_Vertex); + /*lightVector = vec3(gl_LightSource[0].position - ecPos); + + reflectVector = normalize(reflect(-lightVector, normal)); + eyeVector = vec3(-ecPos);*/ + + /* Compute the diffuse, ambient and globalAmbient terms */ + diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse; + + /* The ambient terms have been separated since one of them */ + /* suffers attenuation */ + ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient; + ambientGlobal = gl_LightModel.ambient * gl_FrontMaterial.ambient; + + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = ftransform(); +} diff --git a/zoom.cpp b/zoom.cpp index 8f01c1b..6fab527 100644 --- a/zoom.cpp +++ b/zoom.cpp @@ -66,8 +66,7 @@ bool WGLInit(HINSTANCE hInstance, HWND *hWnd, HDC *hDC, HGLRC *hRC) { wc.lpszMenuName = 0; wc.lpszClassName = "3D"; - if (!RegisterClass(&wc)) - { + if (!RegisterClass(&wc)) { MessageBox(0, "Failed To Register The Window Class.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; // Exit And Return FALSE } @@ -85,14 +84,12 @@ bool WGLInit(HINSTANCE hInstance, HWND *hWnd, HDC *hDC, HGLRC *hRC) { *hWnd = CreateWindowEx(dwExStyle, "3D" /* Class Name */, "3D" /* Title*/, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle, 0, 0, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, 0, 0, hInstance, 0); - if(!*hWnd) - { + if(!*hWnd) { MessageBox(0, "Window Creation Error.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; } - static PIXELFORMATDESCRIPTOR pfd = - { + static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 1, // Version Number PFD_DRAW_TO_WINDOW | // Format Must Support Window @@ -114,38 +111,33 @@ bool WGLInit(HINSTANCE hInstance, HWND *hWnd, HDC *hDC, HGLRC *hRC) { }; *hDC=GetDC(*hWnd); - if (!*hDC) - { + if (!*hDC) { WGLUninit(*hWnd, 0, 0); MessageBox(0, "Can't Create A GL Device Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; } GLuint pixelFormat = ChoosePixelFormat(*hDC, &pfd); - if(!pixelFormat) - { + if(!pixelFormat) { WGLUninit(*hWnd, *hDC, 0); MessageBox(0, "Can't Find A Suitable PixelFormat.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; } - if(!SetPixelFormat(*hDC, pixelFormat, &pfd)) - { + if(!SetPixelFormat(*hDC, pixelFormat, &pfd)) { WGLUninit(*hWnd, *hDC, 0); MessageBox(0, "Can't Set The PixelFormat.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; } *hRC=wglCreateContext(*hDC); - if(!*hRC) - { + if(!*hRC) { WGLUninit(*hWnd, *hDC, 0); MessageBox(0, "Can't Create A GL Rendering Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; } - if(!wglMakeCurrent(*hDC, *hRC)) - { + if(!wglMakeCurrent(*hDC, *hRC)) { WGLUninit(*hWnd, *hDC, *hRC); MessageBox(0, "Can't Activate The GL Rendering Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; @@ -171,17 +163,17 @@ void WGLUninit(HWND hWnd, HDC hDC, HGLRC hRC) { DestroyWindow(hWnd); } -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -{ +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hWnd = 0; HDC hDC = 0; HGLRC hRC = 0; - if(!WGLInit(hInstance, &hWnd, &hDC, &hRC)) - { + if(!WGLInit(hInstance, &hWnd, &hDC, &hRC)) { return 0; } + glewInit(); + resize(DEFAULT_WIDTH, DEFAULT_HEIGHT); bool running = true; @@ -330,6 +322,8 @@ int main() { if(!GLXinit(disp, windele, &wnd, &gc, &multisample)) return 1; + glewInit(); + resize(DEFAULT_WIDTH, DEFAULT_HEIGHT); Zoom::Game game(multisample); -- cgit v1.2.3