Initial commit for Labs 11-15

This commit is contained in:
Alex 2017-04-10 17:50:27 -05:00
parent d7c568f3e2
commit 4e5b557868
75 changed files with 28345 additions and 0 deletions

BIN
L11.zip Normal file

Binary file not shown.

127
L11/CMakeLists.txt Normal file
View file

@ -0,0 +1,127 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
# Name of the project
PROJECT(L11)
# FOR LAB MACHINES ONLY!
# DO NOT EDIT
SET(DEF_DIR_GLM "C:\\c++\\glm")
SET(DEF_DIR_GLFW "C:\\c++\\glfw-3.2.1")
SET(DEF_DIR_GLEW "C:\\c++\\glew-2.0.0")
# Is this the solution?
# Override with `cmake -DSOL=ON ..`
OPTION(SOL "Solution" OFF)
# Use glob to get the list of all source files.
# We don't really need to include header and resource files to build, but it's
# nice to have them also show up in IDEs.
IF(${SOL})
FILE(GLOB_RECURSE SOURCES "src0/*.cpp")
FILE(GLOB_RECURSE HEADERS "src0/*.h")
FILE(GLOB_RECURSE GLSL "resources0/*.glsl")
ELSE()
FILE(GLOB_RECURSE SOURCES "src/*.cpp")
FILE(GLOB_RECURSE HEADERS "src/*.h")
FILE(GLOB_RECURSE GLSL "resources/*.glsl")
ENDIF()
# Set the executable.
ADD_EXECUTABLE(${CMAKE_PROJECT_NAME} ${SOURCES} ${HEADERS} ${GLSL})
# Get the GLM environment variable. Since GLM is a header-only library, we
# just need to add it to the include directory.
SET(GLM_INCLUDE_DIR "$ENV{GLM_INCLUDE_DIR}")
IF(NOT GLM_INCLUDE_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLM_INCLUDE_DIR to the root directory of your GLM installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLM in ${DEF_DIR_GLM}")
IF(IS_DIRECTORY ${DEF_DIR_GLM})
MESSAGE(STATUS "Found!")
SET(GLM_INCLUDE_DIR ${DEF_DIR_GLM})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
INCLUDE_DIRECTORIES(${GLM_INCLUDE_DIR})
# Get the GLFW environment variable. There should be a CMakeLists.txt in the
# specified directory.
SET(GLFW_DIR "$ENV{GLFW_DIR}")
IF(NOT GLFW_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLFW_DIR to the root directory of your GLFW installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLFW in ${DEF_DIR_GLFW}")
IF(IS_DIRECTORY ${DEF_DIR_GLFW})
MESSAGE(STATUS "Found!")
SET(GLFW_DIR ${DEF_DIR_GLFW})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
OPTION(GLFW_BUILD_EXAMPLES "GLFW_BUILD_EXAMPLES" OFF)
OPTION(GLFW_BUILD_TESTS "GLFW_BUILD_TESTS" OFF)
OPTION(GLFW_BUILD_DOCS "GLFW_BUILD_DOCS" OFF)
IF(CMAKE_BUILD_TYPE MATCHES Release)
ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/release)
ELSE()
ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/debug)
ENDIF()
INCLUDE_DIRECTORIES(${GLFW_DIR}/include)
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} glfw ${GLFW_LIBRARIES})
# Get the GLEW environment variable.
SET(GLEW_DIR "$ENV{GLEW_DIR}")
IF(NOT GLEW_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLEW_DIR to the root directory of your GLEW installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLEW in ${DEF_DIR_GLEW}")
IF(IS_DIRECTORY ${DEF_DIR_GLEW})
MESSAGE(STATUS "Found!")
SET(GLEW_DIR ${DEF_DIR_GLEW})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
INCLUDE_DIRECTORIES(${GLEW_DIR}/include)
IF(WIN32)
# With prebuilt binaries
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/Release/Win32/glew32s.lib)
ELSE()
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/libGLEW.a)
ENDIF()
# OS specific options and libraries
IF(WIN32)
# c++11 is enabled by default.
# -Wall produces way too many warnings.
# -pedantic is not supported.
# Disable warning 4996.
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996")
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} opengl32.lib)
ELSE()
# Enable all pedantic warnings.
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pedantic")
IF(APPLE)
# Add required frameworks for GLFW.
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "-framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo")
ELSE()
#Link the Linux OpenGL library
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "GL")
ENDIF()
ENDIF()

View file

@ -0,0 +1,8 @@
#version 120
varying vec3 fragColor;
void main()
{
gl_FragColor = vec4(fragColor, 1.0);
}

View file

@ -0,0 +1,11 @@
#version 120
uniform mat4 P;
uniform mat4 MV;
varying vec3 fragColor;
void main()
{
gl_Position = P * MV * gl_Vertex;
fragColor = gl_Color.rgb;
}

152
L11/src/GLSL.cpp Normal file
View file

@ -0,0 +1,152 @@
//
// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book
// Created by zwood on 2/21/10.
// Modified by sueda 10/15/15.
//
#include "GLSL.h"
#include <stdio.h>
#include <stdlib.h>
#include <cassert>
#include <cstring>
using namespace std;
namespace GLSL {
const char * errorString(GLenum err)
{
switch(err) {
case GL_NO_ERROR:
return "No error";
case GL_INVALID_ENUM:
return "Invalid enum";
case GL_INVALID_VALUE:
return "Invalid value";
case GL_INVALID_OPERATION:
return "Invalid operation";
case GL_STACK_OVERFLOW:
return "Stack overflow";
case GL_STACK_UNDERFLOW:
return "Stack underflow";
case GL_OUT_OF_MEMORY:
return "Out of memory";
default:
return "No error";
}
}
void checkVersion()
{
int major, minor;
major = minor = 0;
const char *verstr = (const char *)glGetString(GL_VERSION);
if((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) != 2)) {
printf("Invalid GL_VERSION format %d.%d\n", major, minor);
}
if(major < 2) {
printf("This shader example will not work due to the installed Opengl version, which is %d.%d.\n", major, minor);
exit(0);
}
}
void checkError(const char *str)
{
GLenum glErr = glGetError();
if(glErr != GL_NO_ERROR) {
if(str) {
printf("%s: ", str);
}
printf("GL_ERROR = %s.\n", errorString(glErr));
assert(false);
}
}
void printShaderInfoLog(GLuint shader)
{
GLint infologLength = 0;
GLint charsWritten = 0;
GLchar *infoLog = 0;
checkError(GET_FILE_LINE);
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength);
checkError(GET_FILE_LINE);
if(infologLength > 0) {
infoLog = (GLchar *)malloc(infologLength);
if(infoLog == NULL) {
puts("ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog);
checkError(GET_FILE_LINE);
printf("Shader InfoLog:\n%s\n\n", infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint program)
{
GLint infologLength = 0;
GLint charsWritten = 0;
GLchar *infoLog = 0;
checkError(GET_FILE_LINE);
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength);
checkError(GET_FILE_LINE);
if(infologLength > 0) {
infoLog = (GLchar *)malloc(infologLength);
if(infoLog == NULL) {
puts("ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog);
checkError(GET_FILE_LINE);
printf("Program InfoLog:\n%s\n\n", infoLog);
free(infoLog);
}
}
char *textFileRead(const 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 = (int)ftell(fp);
rewind(fp);
if(count > 0) {
content = (char *)malloc(sizeof(char) * (count+1));
count = (int)fread(content,sizeof(char),count,fp);
content[count] = '\0';
}
fclose(fp);
} else {
printf("error loading %s\n", fn);
}
}
return content;
}
int textFileWrite(const char *fn, const char *s)
{
FILE *fp;
int status = 0;
if(fn != NULL) {
fp = fopen(fn,"w");
if(fp != NULL) {
if(fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) {
status = 1;
}
fclose(fp);
}
}
return(status);
}
}

40
L11/src/GLSL.h Normal file
View file

@ -0,0 +1,40 @@
//
// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book
// Created by zwood on 2/21/10.
// Modified by sueda 10/15/15.
//
#pragma once
#ifndef __GLSL__
#define __GLSL__
#define GLEW_STATIC
#include <GL/glew.h>
///////////////////////////////////////////////////////////////////////////////
// For printing out the current file and line number //
///////////////////////////////////////////////////////////////////////////////
#include <sstream>
template <typename T>
std::string NumberToString(T x)
{
std::ostringstream ss;
ss << x;
return ss.str();
}
#define GET_FILE_LINE (std::string(__FILE__) + ":" + NumberToString(__LINE__)).c_str()
///////////////////////////////////////////////////////////////////////////////
namespace GLSL {
void checkVersion();
void checkError(const char *str = 0);
void printProgramInfoLog(GLuint program);
void printShaderInfoLog(GLuint shader);
int textFileWrite(const char *filename, const char *s);
char *textFileRead(const char *filename);
}
#endif

114
L11/src/MatrixStack.cpp Normal file
View file

@ -0,0 +1,114 @@
#include "MatrixStack.h"
#include <stdio.h>
#include <cassert>
#include <vector>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
using namespace std;
MatrixStack::MatrixStack()
{
mstack = make_shared< stack<glm::mat4> >();
mstack->push(glm::mat4(1.0));
}
MatrixStack::~MatrixStack()
{
}
void MatrixStack::pushMatrix()
{
const glm::mat4 &top = mstack->top();
mstack->push(top);
assert(mstack->size() < 100);
}
void MatrixStack::popMatrix()
{
assert(!mstack->empty());
mstack->pop();
// There should always be one matrix left.
assert(!mstack->empty());
}
void MatrixStack::loadIdentity()
{
glm::mat4 &top = mstack->top();
top = glm::mat4(1.0);
}
void MatrixStack::translate(const glm::vec3 &t)
{
glm::mat4 &top = mstack->top();
top *= glm::translate(t);
}
void MatrixStack::translate(float x, float y, float z)
{
translate(glm::vec3(x, y, z));
}
void MatrixStack::scale(const glm::vec3 &s)
{
glm::mat4 &top = mstack->top();
top *= glm::scale(s);
}
void MatrixStack::scale(float x, float y, float z)
{
scale(glm::vec3(x, y, z));
}
void MatrixStack::scale(float s)
{
scale(glm::vec3(s, s, s));
}
void MatrixStack::rotate(float angle, const glm::vec3 &axis)
{
glm::mat4 &top = mstack->top();
top *= glm::rotate(angle, axis);
}
void MatrixStack::rotate(float angle, float x, float y, float z)
{
rotate(angle, glm::vec3(x, y, z));
}
void MatrixStack::multMatrix(const glm::mat4 &matrix)
{
glm::mat4 &top = mstack->top();
top *= matrix;
}
const glm::mat4 &MatrixStack::topMatrix() const
{
return mstack->top();
}
void MatrixStack::print(const glm::mat4 &mat, const char *name)
{
if(name) {
printf("%s = [\n", name);
}
for(int i = 0; i < 4; ++i) {
for(int j = 0; j < 4; ++j) {
// mat[j] returns the jth column
printf("%- 5.2f ", mat[j][i]);
}
printf("\n");
}
if(name) {
printf("];");
}
printf("\n");
}
void MatrixStack::print(const char *name) const
{
print(mstack->top(), name);
}

50
L11/src/MatrixStack.h Normal file
View file

@ -0,0 +1,50 @@
#pragma once
#ifndef _MatrixStack_H_
#define _MatrixStack_H_
#include <stack>
#include <memory>
#include <glm/fwd.hpp>
class MatrixStack
{
public:
MatrixStack();
virtual ~MatrixStack();
// glPushMatrix(): Copies the current matrix and adds it to the top of the stack
void pushMatrix();
// glPopMatrix(): Removes the top of the stack and sets the current matrix to be the matrix that is now on top
void popMatrix();
// glLoadIdentity(): Sets the top matrix to be the identity
void loadIdentity();
// glMultMatrix(): Right multiplies the top matrix
void multMatrix(const glm::mat4 &matrix);
// glTranslate(): Right multiplies the top matrix by a translation matrix
void translate(const glm::vec3 &trans);
void translate(float x, float y, float z);
// glScale(): Right multiplies the top matrix by a scaling matrix
void scale(const glm::vec3 &scale);
void scale(float x, float y, float z);
// glScale(): Right multiplies the top matrix by a scaling matrix
void scale(float size);
// glRotate(): Right multiplies the top matrix by a rotation matrix (angle in radians)
void rotate(float angle, const glm::vec3 &axis);
void rotate(float angle, float x, float y, float z);
// glGet(GL_MODELVIEW_MATRIX): Gets the top matrix
const glm::mat4 &topMatrix() const;
// Prints out the specified matrix
static void print(const glm::mat4 &mat, const char *name = 0);
// Prints out the top matrix
void print(const char *name = 0) const;
private:
std::shared_ptr< std::stack<glm::mat4> > mstack;
};
#endif

126
L11/src/Program.cpp Normal file
View file

@ -0,0 +1,126 @@
#include "Program.h"
#include <iostream>
#include <cassert>
#include "GLSL.h"
using namespace std;
Program::Program() :
vShaderName(""),
fShaderName(""),
pid(0),
verbose(true)
{
}
Program::~Program()
{
}
void Program::setShaderNames(const string &v, const string &f)
{
vShaderName = v;
fShaderName = f;
}
bool Program::init()
{
GLint rc;
// Create shader handles
GLuint VS = glCreateShader(GL_VERTEX_SHADER);
GLuint FS = glCreateShader(GL_FRAGMENT_SHADER);
// Read shader sources
const char *vshader = GLSL::textFileRead(vShaderName.c_str());
const char *fshader = GLSL::textFileRead(fShaderName.c_str());
glShaderSource(VS, 1, &vshader, NULL);
glShaderSource(FS, 1, &fshader, NULL);
// Compile vertex shader
glCompileShader(VS);
glGetShaderiv(VS, GL_COMPILE_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printShaderInfoLog(VS);
cout << "Error compiling vertex shader " << vShaderName << endl;
}
return false;
}
// Compile fragment shader
glCompileShader(FS);
glGetShaderiv(FS, GL_COMPILE_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printShaderInfoLog(FS);
cout << "Error compiling fragment shader " << fShaderName << endl;
}
return false;
}
// Create the program and link
pid = glCreateProgram();
glAttachShader(pid, VS);
glAttachShader(pid, FS);
glLinkProgram(pid);
glGetProgramiv(pid, GL_LINK_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printProgramInfoLog(pid);
cout << "Error linking shaders " << vShaderName << " and " << fShaderName << endl;
}
return false;
}
GLSL::checkError(GET_FILE_LINE);
return true;
}
void Program::bind()
{
glUseProgram(pid);
}
void Program::unbind()
{
glUseProgram(0);
}
void Program::addAttribute(const string &name)
{
attributes[name] = glGetAttribLocation(pid, name.c_str());
}
void Program::addUniform(const string &name)
{
uniforms[name] = glGetUniformLocation(pid, name.c_str());
}
GLint Program::getAttribute(const string &name) const
{
map<string,GLint>::const_iterator attribute = attributes.find(name.c_str());
if(attribute == attributes.end()) {
if(isVerbose()) {
cout << name << " is not an attribute variable" << endl;
}
return -1;
}
return attribute->second;
}
GLint Program::getUniform(const string &name) const
{
map<string,GLint>::const_iterator uniform = uniforms.find(name.c_str());
if(uniform == uniforms.end()) {
if(isVerbose()) {
cout << name << " is not a uniform variable" << endl;
}
return -1;
}
return uniform->second;
}

44
L11/src/Program.h Normal file
View file

@ -0,0 +1,44 @@
#pragma once
#ifndef __Program__
#define __Program__
#include <map>
#include <string>
#define GLEW_STATIC
#include <GL/glew.h>
/**
* An OpenGL Program (vertex and fragment shaders)
*/
class Program
{
public:
Program();
virtual ~Program();
void setVerbose(bool v) { verbose = v; }
bool isVerbose() const { return verbose; }
void setShaderNames(const std::string &v, const std::string &f);
virtual bool init();
virtual void bind();
virtual void unbind();
void addAttribute(const std::string &name);
void addUniform(const std::string &name);
GLint getAttribute(const std::string &name) const;
GLint getUniform(const std::string &name) const;
protected:
std::string vShaderName;
std::string fShaderName;
private:
GLuint pid;
std::map<std::string,GLint> attributes;
std::map<std::string,GLint> uniforms;
bool verbose;
};
#endif

270
L11/src/main.cpp Normal file
View file

@ -0,0 +1,270 @@
#include <iostream>
#include <vector>
#include <random>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "GLSL.h"
#include "Program.h"
#include "MatrixStack.h"
using namespace std;
GLFWwindow *window; // Main application window
string RESOURCE_DIR = ""; // Where the resources are loaded from
shared_ptr<Program> prog;
bool keyToggles[256] = {false}; // only for English keyboards!
glm::vec2 cameraRotations(0, 0);
glm::vec2 mousePrev(-1, -1);
// Control points
vector<glm::vec3> cps;
enum SplineType
{
BEZIER = 0,
CATMULL_ROM,
BASIS,
SPLINE_TYPE_COUNT
};
SplineType type = BEZIER;
static void error_callback(int error, const char *description)
{
cerr << description << endl;
}
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GL_TRUE);
}
if(action == GLFW_PRESS) {
switch(key) {
case GLFW_KEY_S:
type = (SplineType)((type + 1) % SPLINE_TYPE_COUNT);
break;
case GLFW_KEY_C:
cps.clear();
break;
case GLFW_KEY_R:
cps.clear();
default_random_engine generator;
uniform_real_distribution<float> distribution(-0.8, 0.8);
for(int i = 0; i < 10; ++i) {
float x = distribution(generator);
float y = distribution(generator);
float z = distribution(generator);
cps.push_back(glm::vec3(x, y, z));
}
break;
}
}
}
static void char_callback(GLFWwindow *window, unsigned int key)
{
keyToggles[key] = !keyToggles[key];
}
static void cursor_position_callback(GLFWwindow* window, double xmouse, double ymouse)
{
if(mousePrev.x >= 0) {
glm::vec2 mouseCurr(xmouse, ymouse);
cameraRotations += 0.01f * (mouseCurr - mousePrev);
mousePrev = mouseCurr;
}
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
// Get the current mouse position.
double xmouse, ymouse;
glfwGetCursorPos(window, &xmouse, &ymouse);
// Get current window size.
int width, height;
glfwGetWindowSize(window, &width, &height);
if(action == GLFW_PRESS) {
if(mods & GLFW_MOD_SHIFT) {
// Insert a new control point
// Convert from window coord to world coord assuming that we're
// using an orthgraphic projection from -1 to 1.
float aspect = (float)width/height;
glm::vec4 x;
x[0] = 2.0f * ((xmouse / width) - 0.5f)* aspect;
x[1] = 2.0f * (((height - ymouse) / height) - 0.5f);
x[2] = 0.0f;
x[3] = 1.0f;
// Build the current modelview matrix.
auto MV = make_shared<MatrixStack>();
MV->rotate(cameraRotations[1], glm::vec3(1, 0, 0));
MV->rotate(cameraRotations[0], glm::vec3(0, 1, 0));
// Since the modelview matrix transforms from world to eye coords,
// we want to invert to go from eye to world.
x = glm::inverse(MV->topMatrix()) * x;
cps.push_back(glm::vec3(x));
} else {
mousePrev.x = xmouse;
mousePrev.y = ymouse;
}
} else {
mousePrev[0] = -1;
mousePrev[1] = -1;
}
}
static void init()
{
GLSL::checkVersion();
// Set background color
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// Enable z-buffer test
glEnable(GL_DEPTH_TEST);
// Initialize the GLSL program.
prog = make_shared<Program>();
prog->setVerbose(true);
prog->setShaderNames(RESOURCE_DIR + "simple_vert.glsl", RESOURCE_DIR + "simple_frag.glsl");
prog->init();
prog->addUniform("P");
prog->addUniform("MV");
prog->setVerbose(false);
// Initialize time.
glfwSetTime(0.0);
keyToggles[(unsigned)'l'] = true;
// If there were any OpenGL errors, this will print something.
// You can intersperse this line in your code to find the exact location
// of your OpenGL error.
GLSL::checkError(GET_FILE_LINE);
}
void render()
{
// Update time.
double t = glfwGetTime();
// Get current frame buffer size.
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// Clear buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
auto P = make_shared<MatrixStack>();
auto MV = make_shared<MatrixStack>();
P->pushMatrix();
MV->pushMatrix();
double aspect = (double)width/height;
P->multMatrix(glm::ortho(-aspect, aspect, -1.0, 1.0, -2.0, 2.0));
MV->rotate(cameraRotations.y, glm::vec3(1, 0, 0));
MV->rotate(cameraRotations.x, glm::vec3(0, 1, 0));
// Bind the program
prog->bind();
glUniformMatrix4fv(prog->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix()));
glUniformMatrix4fv(prog->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix()));
// Draw control points
int ncps = (int)cps.size();
glPointSize(5.0f);
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_POINTS);
for(int i = 0; i < ncps; ++i) {
glVertex3f(cps[i].x, cps[i].y, cps[i].z);
}
glEnd();
glLineWidth(1.0f);
if(keyToggles[(unsigned)'l']) {
glColor3f(1.0f, 0.5f, 0.5f);
glBegin(GL_LINE_STRIP);
for(int i = 0; i < ncps; ++i) {
glVertex3f(cps[i].x, cps[i].y, cps[i].z);
}
glEnd();
}
// INSERT CODE HERE
// Unbind the program
prog->unbind();
// Pop matrix stacks.
MV->popMatrix();
P->popMatrix();
GLSL::checkError(GET_FILE_LINE);
}
int main(int argc, char **argv)
{
if(argc < 2) {
cout << "Please specify the resource directory." << endl;
return 0;
}
RESOURCE_DIR = argv[1] + string("/");
// Set error callback.
glfwSetErrorCallback(error_callback);
// Initialize the library.
if(!glfwInit()) {
return -1;
}
// Create a windowed mode window and its OpenGL context.
window = glfwCreateWindow(640, 480, "YOUR NAME", NULL, NULL);
if(!window) {
glfwTerminate();
return -1;
}
// Make the window's context current.
glfwMakeContextCurrent(window);
// Initialize GLEW.
glewExperimental = true;
if(glewInit() != GLEW_OK) {
cerr << "Failed to initialize GLEW" << endl;
return -1;
}
glGetError(); // A bug in glewInit() causes an error that we can safely ignore.
cout << "OpenGL version: " << glGetString(GL_VERSION) << endl;
cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;
// Set vsync.
glfwSwapInterval(1);
// Set keyboard callback.
glfwSetKeyCallback(window, key_callback);
// Set char callback.
glfwSetCharCallback(window, char_callback);
// Set cursor position callback.
glfwSetCursorPosCallback(window, cursor_position_callback);
// Set mouse button callback.
glfwSetMouseButtonCallback(window, mouse_button_callback);
// Initialize scene.
init();
// Loop until the user closes the window.
while(!glfwWindowShouldClose(window)) {
// Render scene.
render();
// Swap front and back buffers.
glfwSwapBuffers(window);
// Poll for and process events.
glfwPollEvents();
}
// Quit program.
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}

BIN
L12.zip Normal file

Binary file not shown.

126
L12/CMakeLists.txt Normal file
View file

@ -0,0 +1,126 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
# Name of the project
PROJECT(L12)
# FOR LAB MACHINES ONLY!
# DO NOT EDIT
SET(DEF_DIR_GLM "C:\\c++\\glm")
SET(DEF_DIR_GLFW "C:\\c++\\glfw-3.2.1")
SET(DEF_DIR_GLEW "C:\\c++\\glew-2.0.0")
# Is this the solution?
# Override with `cmake -DSOL=ON ..`
OPTION(SOL "Solution" OFF)
# Use glob to get the list of all source files.
# We don't really need to include header and resource files to build, but it's
# nice to have them also show up in IDEs.
IF(${SOL})
FILE(GLOB_RECURSE SOURCES "src0/*.cpp")
FILE(GLOB_RECURSE HEADERS "src0/*.h")
ELSE()
FILE(GLOB_RECURSE SOURCES "src/*.cpp")
FILE(GLOB_RECURSE HEADERS "src/*.h")
ENDIF()
FILE(GLOB_RECURSE GLSL "resources/*.glsl")
# Set the executable.
ADD_EXECUTABLE(${CMAKE_PROJECT_NAME} ${SOURCES} ${HEADERS} ${GLSL})
# Get the GLM environment variable. Since GLM is a header-only library, we
# just need to add it to the include directory.
SET(GLM_INCLUDE_DIR "$ENV{GLM_INCLUDE_DIR}")
IF(NOT GLM_INCLUDE_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLM_INCLUDE_DIR to the root directory of your GLM installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLM in ${DEF_DIR_GLM}")
IF(IS_DIRECTORY ${DEF_DIR_GLM})
MESSAGE(STATUS "Found!")
SET(GLM_INCLUDE_DIR ${DEF_DIR_GLM})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
INCLUDE_DIRECTORIES(${GLM_INCLUDE_DIR})
# Get the GLFW environment variable. There should be a CMakeLists.txt in the
# specified directory.
SET(GLFW_DIR "$ENV{GLFW_DIR}")
IF(NOT GLFW_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLFW_DIR to the root directory of your GLFW installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLFW in ${DEF_DIR_GLFW}")
IF(IS_DIRECTORY ${DEF_DIR_GLFW})
MESSAGE(STATUS "Found!")
SET(GLFW_DIR ${DEF_DIR_GLFW})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
OPTION(GLFW_BUILD_EXAMPLES "GLFW_BUILD_EXAMPLES" OFF)
OPTION(GLFW_BUILD_TESTS "GLFW_BUILD_TESTS" OFF)
OPTION(GLFW_BUILD_DOCS "GLFW_BUILD_DOCS" OFF)
IF(CMAKE_BUILD_TYPE MATCHES Release)
ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/release)
ELSE()
ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/debug)
ENDIF()
INCLUDE_DIRECTORIES(${GLFW_DIR}/include)
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} glfw ${GLFW_LIBRARIES})
# Get the GLEW environment variable.
SET(GLEW_DIR "$ENV{GLEW_DIR}")
IF(NOT GLEW_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLEW_DIR to the root directory of your GLEW installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLEW in ${DEF_DIR_GLEW}")
IF(IS_DIRECTORY ${DEF_DIR_GLEW})
MESSAGE(STATUS "Found!")
SET(GLEW_DIR ${DEF_DIR_GLEW})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
INCLUDE_DIRECTORIES(${GLEW_DIR}/include)
IF(WIN32)
# With prebuilt binaries
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/Release/Win32/glew32s.lib)
ELSE()
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/libGLEW.a)
ENDIF()
# OS specific options and libraries
IF(WIN32)
# c++11 is enabled by default.
# -Wall produces way too many warnings.
# -pedantic is not supported.
# Disable warning 4996.
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996")
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} opengl32.lib)
ELSE()
# Enable all pedantic warnings.
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pedantic")
IF(APPLE)
# Add required frameworks for GLFW.
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "-framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo")
ELSE()
#Link the Linux OpenGL library
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "GL")
ENDIF()
ENDIF()

11051
L12/resources/bunny.obj Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
#version 120
varying vec3 vNor;
void main()
{
vec3 normal = normalize(vNor);
// Map normal in the range [-1, 1] to color in range [0, 1];
vec3 color = 0.5*normal + 0.5;
gl_FragColor = vec4(color, 1.0);
}

View file

@ -0,0 +1,12 @@
#version 120
attribute vec4 aPos;
attribute vec3 aNor;
uniform mat4 P;
uniform mat4 MV;
varying vec3 vNor;
void main()
{
gl_Position = P * MV * aPos;
vNor = (MV * vec4(aNor, 0.0)).xyz;
}

View file

@ -0,0 +1,8 @@
#version 120
varying vec3 fragColor;
void main()
{
gl_FragColor = vec4(fragColor, 1.0);
}

View file

@ -0,0 +1,11 @@
#version 120
uniform mat4 P;
uniform mat4 MV;
varying vec3 fragColor;
void main()
{
gl_Position = P * MV * gl_Vertex;
fragColor = gl_Color.rgb;
}

68
L12/src/Camera.cpp Normal file
View file

@ -0,0 +1,68 @@
#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>
#include <glm/gtc/matrix_transform.hpp>
#include "Camera.h"
#include "MatrixStack.h"
Camera::Camera() :
aspect(1.0f),
fovy((float)(45.0*M_PI/180.0)),
znear(0.1f),
zfar(1000.0f),
rotations(0.0, 0.0),
translations(0.0f, 0.0f, -5.0f),
rfactor(0.01f),
tfactor(0.001f),
sfactor(0.005f)
{
}
Camera::~Camera()
{
}
void Camera::mouseClicked(float x, float y, bool shift, bool ctrl, bool alt)
{
mousePrev.x = x;
mousePrev.y = y;
if(shift) {
state = Camera::TRANSLATE;
} else if(ctrl) {
state = Camera::SCALE;
} else {
state = Camera::ROTATE;
}
}
void Camera::mouseMoved(float x, float y)
{
glm::vec2 mouseCurr(x, y);
glm::vec2 dv = mouseCurr - mousePrev;
switch(state) {
case Camera::ROTATE:
rotations += rfactor * dv;
break;
case Camera::TRANSLATE:
translations.x -= translations.z * tfactor * dv.x;
translations.y += translations.z * tfactor * dv.y;
break;
case Camera::SCALE:
translations.z *= (1.0f - sfactor * dv.y);
break;
}
mousePrev = mouseCurr;
}
void Camera::applyProjectionMatrix(std::shared_ptr<MatrixStack> P) const
{
// Modify provided MatrixStack
P->multMatrix(glm::perspective(fovy, aspect, znear, zfar));
}
void Camera::applyViewMatrix(std::shared_ptr<MatrixStack> MV) const
{
MV->translate(translations);
MV->rotate(rotations.y, glm::vec3(1.0f, 0.0f, 0.0f));
MV->rotate(rotations.x, glm::vec3(0.0f, 1.0f, 0.0f));
}

50
L12/src/Camera.h Normal file
View file

@ -0,0 +1,50 @@
#pragma once
#ifndef __Camera__
#define __Camera__
#include <memory>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
class MatrixStack;
class Camera
{
public:
enum {
ROTATE = 0,
TRANSLATE,
SCALE
};
Camera();
virtual ~Camera();
void setInitDistance(float z) { translations.z = -std::abs(z); }
void setAspect(float a) { aspect = a; };
void setFovy(float f) { fovy = f; };
void setZnear(float z) { znear = z; };
void setZfar(float z) { zfar = z; };
void setRotationFactor(float f) { rfactor = f; };
void setTranslationFactor(float f) { tfactor = f; };
void setScaleFactor(float f) { sfactor = f; };
void mouseClicked(float x, float y, bool shift, bool ctrl, bool alt);
void mouseMoved(float x, float y);
void applyProjectionMatrix(std::shared_ptr<MatrixStack> P) const;
void applyViewMatrix(std::shared_ptr<MatrixStack> MV) const;
private:
float aspect;
float fovy;
float znear;
float zfar;
glm::vec2 rotations;
glm::vec3 translations;
glm::vec2 mousePrev;
int state;
float rfactor;
float tfactor;
float sfactor;
};
#endif

152
L12/src/GLSL.cpp Normal file
View file

@ -0,0 +1,152 @@
//
// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book
// Created by zwood on 2/21/10.
// Modified by sueda 10/15/15.
//
#include "GLSL.h"
#include <stdio.h>
#include <stdlib.h>
#include <cassert>
#include <cstring>
using namespace std;
namespace GLSL {
const char * errorString(GLenum err)
{
switch(err) {
case GL_NO_ERROR:
return "No error";
case GL_INVALID_ENUM:
return "Invalid enum";
case GL_INVALID_VALUE:
return "Invalid value";
case GL_INVALID_OPERATION:
return "Invalid operation";
case GL_STACK_OVERFLOW:
return "Stack overflow";
case GL_STACK_UNDERFLOW:
return "Stack underflow";
case GL_OUT_OF_MEMORY:
return "Out of memory";
default:
return "No error";
}
}
void checkVersion()
{
int major, minor;
major = minor = 0;
const char *verstr = (const char *)glGetString(GL_VERSION);
if((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) != 2)) {
printf("Invalid GL_VERSION format %d.%d\n", major, minor);
}
if(major < 2) {
printf("This shader example will not work due to the installed Opengl version, which is %d.%d.\n", major, minor);
exit(0);
}
}
void checkError(const char *str)
{
GLenum glErr = glGetError();
if(glErr != GL_NO_ERROR) {
if(str) {
printf("%s: ", str);
}
printf("GL_ERROR = %s.\n", errorString(glErr));
assert(false);
}
}
void printShaderInfoLog(GLuint shader)
{
GLint infologLength = 0;
GLint charsWritten = 0;
GLchar *infoLog = 0;
checkError(GET_FILE_LINE);
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength);
checkError(GET_FILE_LINE);
if(infologLength > 0) {
infoLog = (GLchar *)malloc(infologLength);
if(infoLog == NULL) {
puts("ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog);
checkError(GET_FILE_LINE);
printf("Shader InfoLog:\n%s\n\n", infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint program)
{
GLint infologLength = 0;
GLint charsWritten = 0;
GLchar *infoLog = 0;
checkError(GET_FILE_LINE);
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength);
checkError(GET_FILE_LINE);
if(infologLength > 0) {
infoLog = (GLchar *)malloc(infologLength);
if(infoLog == NULL) {
puts("ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog);
checkError(GET_FILE_LINE);
printf("Program InfoLog:\n%s\n\n", infoLog);
free(infoLog);
}
}
char *textFileRead(const 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 = (int)ftell(fp);
rewind(fp);
if(count > 0) {
content = (char *)malloc(sizeof(char) * (count+1));
count = (int)fread(content,sizeof(char),count,fp);
content[count] = '\0';
}
fclose(fp);
} else {
printf("error loading %s\n", fn);
}
}
return content;
}
int textFileWrite(const char *fn, const char *s)
{
FILE *fp;
int status = 0;
if(fn != NULL) {
fp = fopen(fn,"w");
if(fp != NULL) {
if(fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) {
status = 1;
}
fclose(fp);
}
}
return(status);
}
}

40
L12/src/GLSL.h Normal file
View file

@ -0,0 +1,40 @@
//
// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book
// Created by zwood on 2/21/10.
// Modified by sueda 10/15/15.
//
#pragma once
#ifndef __GLSL__
#define __GLSL__
#define GLEW_STATIC
#include <GL/glew.h>
///////////////////////////////////////////////////////////////////////////////
// For printing out the current file and line number //
///////////////////////////////////////////////////////////////////////////////
#include <sstream>
template <typename T>
std::string NumberToString(T x)
{
std::ostringstream ss;
ss << x;
return ss.str();
}
#define GET_FILE_LINE (std::string(__FILE__) + ":" + NumberToString(__LINE__)).c_str()
///////////////////////////////////////////////////////////////////////////////
namespace GLSL {
void checkVersion();
void checkError(const char *str = 0);
void printProgramInfoLog(GLuint program);
void printShaderInfoLog(GLuint shader);
int textFileWrite(const char *filename, const char *s);
char *textFileRead(const char *filename);
}
#endif

114
L12/src/MatrixStack.cpp Normal file
View file

@ -0,0 +1,114 @@
#include "MatrixStack.h"
#include <stdio.h>
#include <cassert>
#include <vector>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
using namespace std;
MatrixStack::MatrixStack()
{
mstack = make_shared< stack<glm::mat4> >();
mstack->push(glm::mat4(1.0));
}
MatrixStack::~MatrixStack()
{
}
void MatrixStack::pushMatrix()
{
const glm::mat4 &top = mstack->top();
mstack->push(top);
assert(mstack->size() < 100);
}
void MatrixStack::popMatrix()
{
assert(!mstack->empty());
mstack->pop();
// There should always be one matrix left.
assert(!mstack->empty());
}
void MatrixStack::loadIdentity()
{
glm::mat4 &top = mstack->top();
top = glm::mat4(1.0);
}
void MatrixStack::translate(const glm::vec3 &t)
{
glm::mat4 &top = mstack->top();
top *= glm::translate(t);
}
void MatrixStack::translate(float x, float y, float z)
{
translate(glm::vec3(x, y, z));
}
void MatrixStack::scale(const glm::vec3 &s)
{
glm::mat4 &top = mstack->top();
top *= glm::scale(s);
}
void MatrixStack::scale(float x, float y, float z)
{
scale(glm::vec3(x, y, z));
}
void MatrixStack::scale(float s)
{
scale(glm::vec3(s, s, s));
}
void MatrixStack::rotate(float angle, const glm::vec3 &axis)
{
glm::mat4 &top = mstack->top();
top *= glm::rotate(angle, axis);
}
void MatrixStack::rotate(float angle, float x, float y, float z)
{
rotate(angle, glm::vec3(x, y, z));
}
void MatrixStack::multMatrix(const glm::mat4 &matrix)
{
glm::mat4 &top = mstack->top();
top *= matrix;
}
const glm::mat4 &MatrixStack::topMatrix() const
{
return mstack->top();
}
void MatrixStack::print(const glm::mat4 &mat, const char *name)
{
if(name) {
printf("%s = [\n", name);
}
for(int i = 0; i < 4; ++i) {
for(int j = 0; j < 4; ++j) {
// mat[j] returns the jth column
printf("%- 5.2f ", mat[j][i]);
}
printf("\n");
}
if(name) {
printf("];");
}
printf("\n");
}
void MatrixStack::print(const char *name) const
{
print(mstack->top(), name);
}

50
L12/src/MatrixStack.h Normal file
View file

@ -0,0 +1,50 @@
#pragma once
#ifndef _MatrixStack_H_
#define _MatrixStack_H_
#include <stack>
#include <memory>
#include <glm/fwd.hpp>
class MatrixStack
{
public:
MatrixStack();
virtual ~MatrixStack();
// glPushMatrix(): Copies the current matrix and adds it to the top of the stack
void pushMatrix();
// glPopMatrix(): Removes the top of the stack and sets the current matrix to be the matrix that is now on top
void popMatrix();
// glLoadIdentity(): Sets the top matrix to be the identity
void loadIdentity();
// glMultMatrix(): Right multiplies the top matrix
void multMatrix(const glm::mat4 &matrix);
// glTranslate(): Right multiplies the top matrix by a translation matrix
void translate(const glm::vec3 &trans);
void translate(float x, float y, float z);
// glScale(): Right multiplies the top matrix by a scaling matrix
void scale(const glm::vec3 &scale);
void scale(float x, float y, float z);
// glScale(): Right multiplies the top matrix by a scaling matrix
void scale(float size);
// glRotate(): Right multiplies the top matrix by a rotation matrix (angle in radians)
void rotate(float angle, const glm::vec3 &axis);
void rotate(float angle, float x, float y, float z);
// glGet(GL_MODELVIEW_MATRIX): Gets the top matrix
const glm::mat4 &topMatrix() const;
// Prints out the specified matrix
static void print(const glm::mat4 &mat, const char *name = 0);
// Prints out the top matrix
void print(const char *name = 0) const;
private:
std::shared_ptr< std::stack<glm::mat4> > mstack;
};
#endif

126
L12/src/Program.cpp Normal file
View file

@ -0,0 +1,126 @@
#include "Program.h"
#include <iostream>
#include <cassert>
#include "GLSL.h"
using namespace std;
Program::Program() :
vShaderName(""),
fShaderName(""),
pid(0),
verbose(true)
{
}
Program::~Program()
{
}
void Program::setShaderNames(const string &v, const string &f)
{
vShaderName = v;
fShaderName = f;
}
bool Program::init()
{
GLint rc;
// Create shader handles
GLuint VS = glCreateShader(GL_VERTEX_SHADER);
GLuint FS = glCreateShader(GL_FRAGMENT_SHADER);
// Read shader sources
const char *vshader = GLSL::textFileRead(vShaderName.c_str());
const char *fshader = GLSL::textFileRead(fShaderName.c_str());
glShaderSource(VS, 1, &vshader, NULL);
glShaderSource(FS, 1, &fshader, NULL);
// Compile vertex shader
glCompileShader(VS);
glGetShaderiv(VS, GL_COMPILE_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printShaderInfoLog(VS);
cout << "Error compiling vertex shader " << vShaderName << endl;
}
return false;
}
// Compile fragment shader
glCompileShader(FS);
glGetShaderiv(FS, GL_COMPILE_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printShaderInfoLog(FS);
cout << "Error compiling fragment shader " << fShaderName << endl;
}
return false;
}
// Create the program and link
pid = glCreateProgram();
glAttachShader(pid, VS);
glAttachShader(pid, FS);
glLinkProgram(pid);
glGetProgramiv(pid, GL_LINK_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printProgramInfoLog(pid);
cout << "Error linking shaders " << vShaderName << " and " << fShaderName << endl;
}
return false;
}
GLSL::checkError(GET_FILE_LINE);
return true;
}
void Program::bind()
{
glUseProgram(pid);
}
void Program::unbind()
{
glUseProgram(0);
}
void Program::addAttribute(const string &name)
{
attributes[name] = glGetAttribLocation(pid, name.c_str());
}
void Program::addUniform(const string &name)
{
uniforms[name] = glGetUniformLocation(pid, name.c_str());
}
GLint Program::getAttribute(const string &name) const
{
map<string,GLint>::const_iterator attribute = attributes.find(name.c_str());
if(attribute == attributes.end()) {
if(isVerbose()) {
cout << name << " is not an attribute variable" << endl;
}
return -1;
}
return attribute->second;
}
GLint Program::getUniform(const string &name) const
{
map<string,GLint>::const_iterator uniform = uniforms.find(name.c_str());
if(uniform == uniforms.end()) {
if(isVerbose()) {
cout << name << " is not a uniform variable" << endl;
}
return -1;
}
return uniform->second;
}

44
L12/src/Program.h Normal file
View file

@ -0,0 +1,44 @@
#pragma once
#ifndef __Program__
#define __Program__
#include <map>
#include <string>
#define GLEW_STATIC
#include <GL/glew.h>
/**
* An OpenGL Program (vertex and fragment shaders)
*/
class Program
{
public:
Program();
virtual ~Program();
void setVerbose(bool v) { verbose = v; }
bool isVerbose() const { return verbose; }
void setShaderNames(const std::string &v, const std::string &f);
virtual bool init();
virtual void bind();
virtual void unbind();
void addAttribute(const std::string &name);
void addUniform(const std::string &name);
GLint getAttribute(const std::string &name) const;
GLint getUniform(const std::string &name) const;
protected:
std::string vShaderName;
std::string fShaderName;
private:
GLuint pid;
std::map<std::string,GLint> attributes;
std::map<std::string,GLint> uniforms;
bool verbose;
};
#endif

166
L12/src/Shape.cpp Normal file
View file

@ -0,0 +1,166 @@
#include "Shape.h"
#include <algorithm>
#include <iostream>
#include "GLSL.h"
#include "Program.h"
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
using namespace std;
Shape::Shape() :
posBufID(0),
norBufID(0),
texBufID(0)
{
}
Shape::~Shape()
{
}
void Shape::loadMesh(const string &meshName)
{
// Load geometry
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
string errStr;
bool rc = tinyobj::LoadObj(&attrib, &shapes, &materials, &errStr, meshName.c_str());
if(!rc) {
cerr << errStr << endl;
} else {
// Some OBJ files have different indices for vertex positions, normals,
// and texture coordinates. For example, a cube corner vertex may have
// three different normals. Here, we are going to duplicate all such
// vertices.
// Loop over shapes
for(size_t s = 0; s < shapes.size(); s++) {
// Loop over faces (polygons)
size_t index_offset = 0;
for(size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) {
size_t fv = shapes[s].mesh.num_face_vertices[f];
// Loop over vertices in the face.
for(size_t v = 0; v < fv; v++) {
// access to vertex
tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v];
posBuf.push_back(attrib.vertices[3*idx.vertex_index+0]);
posBuf.push_back(attrib.vertices[3*idx.vertex_index+1]);
posBuf.push_back(attrib.vertices[3*idx.vertex_index+2]);
if(!attrib.normals.empty()) {
norBuf.push_back(attrib.normals[3*idx.normal_index+0]);
norBuf.push_back(attrib.normals[3*idx.normal_index+1]);
norBuf.push_back(attrib.normals[3*idx.normal_index+2]);
}
if(!attrib.texcoords.empty()) {
texBuf.push_back(attrib.texcoords[2*idx.texcoord_index+0]);
texBuf.push_back(attrib.texcoords[2*idx.texcoord_index+1]);
}
}
index_offset += fv;
// per-face material (IGNORE)
shapes[s].mesh.material_ids[f];
}
}
}
}
void Shape::fitToUnitBox()
{
// Scale the vertex positions so that they fit within [-1, +1] in all three dimensions.
glm::vec3 vmin(posBuf[0], posBuf[1], posBuf[2]);
glm::vec3 vmax(posBuf[0], posBuf[1], posBuf[2]);
for(int i = 0; i < (int)posBuf.size(); i += 3) {
glm::vec3 v(posBuf[i], posBuf[i+1], posBuf[i+2]);
vmin.x = min(vmin.x, v.x);
vmin.y = min(vmin.y, v.y);
vmin.z = min(vmin.z, v.z);
vmax.x = max(vmax.x, v.x);
vmax.y = max(vmax.y, v.y);
vmax.z = max(vmax.z, v.z);
}
glm::vec3 center = 0.5f*(vmin + vmax);
glm::vec3 diff = vmax - vmin;
float diffmax = diff.x;
diffmax = max(diffmax, diff.y);
diffmax = max(diffmax, diff.z);
float scale = 1.0f / diffmax;
for(int i = 0; i < (int)posBuf.size(); i += 3) {
posBuf[i ] = (posBuf[i ] - center.x) * scale;
posBuf[i+1] = (posBuf[i+1] - center.y) * scale;
posBuf[i+2] = (posBuf[i+2] - center.z) * scale;
}
}
void Shape::init()
{
// Send the position array to the GPU
glGenBuffers(1, &posBufID);
glBindBuffer(GL_ARRAY_BUFFER, posBufID);
glBufferData(GL_ARRAY_BUFFER, posBuf.size()*sizeof(float), &posBuf[0], GL_STATIC_DRAW);
// Send the normal array to the GPU
if(!norBuf.empty()) {
glGenBuffers(1, &norBufID);
glBindBuffer(GL_ARRAY_BUFFER, norBufID);
glBufferData(GL_ARRAY_BUFFER, norBuf.size()*sizeof(float), &norBuf[0], GL_STATIC_DRAW);
}
// Send the texture array to the GPU
if(!texBuf.empty()) {
glGenBuffers(1, &texBufID);
glBindBuffer(GL_ARRAY_BUFFER, texBufID);
glBufferData(GL_ARRAY_BUFFER, texBuf.size()*sizeof(float), &texBuf[0], GL_STATIC_DRAW);
}
// Unbind the arrays
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLSL::checkError(GET_FILE_LINE);
}
void Shape::draw(const shared_ptr<Program> prog) const
{
// Bind position buffer
int h_pos = prog->getAttribute("aPos");
glEnableVertexAttribArray(h_pos);
glBindBuffer(GL_ARRAY_BUFFER, posBufID);
glVertexAttribPointer(h_pos, 3, GL_FLOAT, GL_FALSE, 0, (const void *)0);
// Bind normal buffer
int h_nor = prog->getAttribute("aNor");
if(h_nor != -1 && norBufID != 0) {
glEnableVertexAttribArray(h_nor);
glBindBuffer(GL_ARRAY_BUFFER, norBufID);
glVertexAttribPointer(h_nor, 3, GL_FLOAT, GL_FALSE, 0, (const void *)0);
}
// Bind texcoords buffer
int h_tex = prog->getAttribute("aTex");
if(h_tex != -1 && texBufID != 0) {
glEnableVertexAttribArray(h_tex);
glBindBuffer(GL_ARRAY_BUFFER, texBufID);
glVertexAttribPointer(h_tex, 2, GL_FLOAT, GL_FALSE, 0, (const void *)0);
}
// Draw
int count = posBuf.size()/3; // number of indices to be rendered
glDrawArrays(GL_TRIANGLES, 0, count);
// Disable and unbind
if(h_tex != -1) {
glDisableVertexAttribArray(h_tex);
}
if(h_nor != -1) {
glDisableVertexAttribArray(h_nor);
}
glDisableVertexAttribArray(h_pos);
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLSL::checkError(GET_FILE_LINE);
}

37
L12/src/Shape.h Normal file
View file

@ -0,0 +1,37 @@
#pragma once
#ifndef _SHAPE_H_
#define _SHAPE_H_
#include <string>
#include <vector>
#include <memory>
class Program;
/**
* A shape defined by a list of triangles
* - posBuf should be of length 3*ntris
* - norBuf should be of length 3*ntris (if normals are available)
* - texBuf should be of length 2*ntris (if texture coords are available)
* posBufID, norBufID, and texBufID are OpenGL buffer identifiers.
*/
class Shape
{
public:
Shape();
virtual ~Shape();
void loadMesh(const std::string &meshName);
void fitToUnitBox();
void init();
void draw(const std::shared_ptr<Program> prog) const;
private:
std::vector<float> posBuf;
std::vector<float> norBuf;
std::vector<float> texBuf;
unsigned posBufID;
unsigned norBufID;
unsigned texBufID;
};
#endif

299
L12/src/main.cpp Normal file
View file

@ -0,0 +1,299 @@
#include <iostream>
#include <vector>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/quaternion.hpp>
#include "Camera.h"
#include "GLSL.h"
#include "Program.h"
#include "MatrixStack.h"
#include "Shape.h"
using namespace std;
bool keyToggles[256] = {false}; // only for English keyboards!
GLFWwindow *window; // Main application window
string RESOURCE_DIR = ""; // Where the resources are loaded from
shared_ptr<Program> progNormal;
shared_ptr<Program> progSimple;
shared_ptr<Camera> camera;
shared_ptr<Shape> bunny;
static void error_callback(int error, const char *description)
{
cerr << description << endl;
}
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GL_TRUE);
}
}
static void char_callback(GLFWwindow *window, unsigned int key)
{
keyToggles[key] = !keyToggles[key];
}
static void cursor_position_callback(GLFWwindow* window, double xmouse, double ymouse)
{
int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
if(state == GLFW_PRESS) {
camera->mouseMoved(xmouse, ymouse);
}
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
// Get the current mouse position.
double xmouse, ymouse;
glfwGetCursorPos(window, &xmouse, &ymouse);
// Get current window size.
int width, height;
glfwGetWindowSize(window, &width, &height);
if(action == GLFW_PRESS) {
bool shift = mods & GLFW_MOD_SHIFT;
bool ctrl = mods & GLFW_MOD_CONTROL;
bool alt = mods & GLFW_MOD_ALT;
camera->mouseClicked(xmouse, ymouse, shift, ctrl, alt);
}
}
static void init()
{
GLSL::checkVersion();
// Set background color
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// Enable z-buffer test
glEnable(GL_DEPTH_TEST);
keyToggles[(unsigned)'c'] = true;
// For drawing the bunny
progNormal = make_shared<Program>();
progNormal->setShaderNames(RESOURCE_DIR + "normal_vert.glsl", RESOURCE_DIR + "normal_frag.glsl");
progNormal->setVerbose(true);
progNormal->init();
progNormal->addUniform("P");
progNormal->addUniform("MV");
progNormal->addAttribute("aPos");
progNormal->addAttribute("aNor");
progNormal->setVerbose(false);
// For drawing the frames
progSimple = make_shared<Program>();
progSimple->setShaderNames(RESOURCE_DIR + "simple_vert.glsl", RESOURCE_DIR + "simple_frag.glsl");
progSimple->setVerbose(true);
progSimple->init();
progSimple->addUniform("P");
progSimple->addUniform("MV");
progSimple->setVerbose(false);
bunny = make_shared<Shape>();
bunny->loadMesh(RESOURCE_DIR + "bunny.obj");
bunny->init();
camera = make_shared<Camera>();
// Initialize time.
glfwSetTime(0.0);
// If there were any OpenGL errors, this will print something.
// You can intersperse this line in your code to find the exact location
// of your OpenGL error.
GLSL::checkError(GET_FILE_LINE);
}
void render()
{
// Update time.
double t = glfwGetTime();
// Get current frame buffer size.
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// Use the window size for camera.
glfwGetWindowSize(window, &width, &height);
camera->setAspect((float)width/(float)height);
// Clear buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if(keyToggles[(unsigned)'c']) {
glEnable(GL_CULL_FACE);
} else {
glDisable(GL_CULL_FACE);
}
if(keyToggles[(unsigned)'l']) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
} else {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
auto P = make_shared<MatrixStack>();
auto MV = make_shared<MatrixStack>();
// Apply camera transforms
P->pushMatrix();
camera->applyProjectionMatrix(P);
MV->pushMatrix();
camera->applyViewMatrix(MV);
// Draw origin frame
progSimple->bind();
glUniformMatrix4fv(progSimple->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix()));
glUniformMatrix4fv(progSimple->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix()));
glLineWidth(2);
glBegin(GL_LINES);
glColor3f(1, 0, 0);
glVertex3f(0, 0, 0);
glVertex3f(1, 0, 0);
glColor3f(0, 1, 0);
glVertex3f(0, 0, 0);
glVertex3f(0, 1, 0);
glColor3f(0, 0, 1);
glVertex3f(0, 0, 0);
glVertex3f(0, 0, 1);
glEnd();
glLineWidth(1);
progSimple->unbind();
GLSL::checkError(GET_FILE_LINE);
// Draw the bunnies
progNormal->bind();
// Send projection matrix (same for all bunnies)
glUniformMatrix4fv(progNormal->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix()));
// The center of the bunny is at (-0.2802, 0.932, 0.0851)
glm::vec3 center(-0.2802, 0.932, 0.0851);
// Alpha is the linear interpolation parameter between 0 and 1
float alpha = std::fmod(0.5f*t, 1.0f);
// The axes of rotatio for the source and target bunnies
glm::vec3 axis0, axis1;
axis0.x = keyToggles[(unsigned)'x'] ? 1.0 : 0.0f;
axis0.y = keyToggles[(unsigned)'y'] ? 1.0 : 0.0f;
axis0.z = keyToggles[(unsigned)'z'] ? 1.0 : 0.0f;
axis1.x = keyToggles[(unsigned)'X'] ? 1.0 : 0.0f;
axis1.y = keyToggles[(unsigned)'Y'] ? 1.0 : 0.0f;
axis1.z = keyToggles[(unsigned)'Z'] ? 1.0 : 0.0f;
glm::quat q0, q1;
if(glm::length(axis0) == 0) {
q0 = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
} else {
axis0 = glm::normalize(axis0);
q0 = glm::angleAxis((float)(90.0f/180.0f*M_PI), axis0);
}
if(glm::length(axis1) == 0) {
q1 = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
} else {
axis1 = glm::normalize(axis1);
q1 = glm::angleAxis((float)(90.0f/180.0f*M_PI), axis1);
}
glm::vec3 p0(-1.0f, 0.0f, 0.0f);
glm::vec3 p1( 1.0f, 0.0f, 0.0f);
// Draw the bunny three times: left, right, and interpolated.
// left: use p0 for position and q0 for orientation
// right: use p1 for position and q1 for orientation
// LEFT
MV->pushMatrix();
glUniformMatrix4fv(progNormal->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix()));
MV->popMatrix();
bunny->draw(progNormal);
// RIGHT
MV->pushMatrix();
glUniformMatrix4fv(progNormal->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix()));
MV->popMatrix();
bunny->draw(progNormal);
// INTERPOLATED
MV->pushMatrix();
glUniformMatrix4fv(progNormal->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix()));
MV->popMatrix();
bunny->draw(progNormal);
progNormal->unbind();
// Pop stacks
MV->popMatrix();
P->popMatrix();
GLSL::checkError(GET_FILE_LINE);
}
int main(int argc, char **argv)
{
if(argc < 2) {
cout << "Please specify the resource directory." << endl;
return 0;
}
RESOURCE_DIR = argv[1] + string("/");
// Set error callback.
glfwSetErrorCallback(error_callback);
// Initialize the library.
if(!glfwInit()) {
return -1;
}
// Create a windowed mode window and its OpenGL context.
window = glfwCreateWindow(640, 480, "YOUR NAME", NULL, NULL);
if(!window) {
glfwTerminate();
return -1;
}
// Make the window's context current.
glfwMakeContextCurrent(window);
// Initialize GLEW.
glewExperimental = true;
if(glewInit() != GLEW_OK) {
cerr << "Failed to initialize GLEW" << endl;
return -1;
}
glGetError(); // A bug in glewInit() causes an error that we can safely ignore.
cout << "OpenGL version: " << glGetString(GL_VERSION) << endl;
cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;
// Set vsync.
glfwSwapInterval(1);
// Set keyboard callback.
glfwSetKeyCallback(window, key_callback);
// Set char callback.
glfwSetCharCallback(window, char_callback);
// Set cursor position callback.
glfwSetCursorPosCallback(window, cursor_position_callback);
// Set mouse button callback.
glfwSetMouseButtonCallback(window, mouse_button_callback);
// Initialize scene.
init();
// Loop until the user closes the window.
while(!glfwWindowShouldClose(window)) {
// Render scene.
render();
// Swap front and back buffers.
glfwSwapBuffers(window);
// Poll for and process events.
glfwPollEvents();
}
// Quit program.
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}

1922
L12/src/tiny_obj_loader.h Normal file

File diff suppressed because it is too large Load diff

BIN
L13.zip Normal file

Binary file not shown.

126
L13/CMakeLists.txt Normal file
View file

@ -0,0 +1,126 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
# Name of the project
PROJECT(L13)
# FOR LAB MACHINES ONLY!
# DO NOT EDIT
SET(DEF_DIR_GLM "C:\\c++\\glm")
SET(DEF_DIR_GLFW "C:\\c++\\glfw-3.2.1")
SET(DEF_DIR_GLEW "C:\\c++\\glew-2.0.0")
# Is this the solution?
# Override with `cmake -DSOL=ON ..`
OPTION(SOL "Solution" OFF)
# Use glob to get the list of all source files.
# We don't really need to include header and resource files to build, but it's
# nice to have them also show up in IDEs.
IF(${SOL})
FILE(GLOB_RECURSE SOURCES "src0/*.cpp")
FILE(GLOB_RECURSE HEADERS "src0/*.h")
ELSE()
FILE(GLOB_RECURSE SOURCES "src/*.cpp")
FILE(GLOB_RECURSE HEADERS "src/*.h")
ENDIF()
FILE(GLOB_RECURSE GLSL "resources/*.glsl")
# Set the executable.
ADD_EXECUTABLE(${CMAKE_PROJECT_NAME} ${SOURCES} ${HEADERS} ${GLSL})
# Get the GLM environment variable. Since GLM is a header-only library, we
# just need to add it to the include directory.
SET(GLM_INCLUDE_DIR "$ENV{GLM_INCLUDE_DIR}")
IF(NOT GLM_INCLUDE_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLM_INCLUDE_DIR to the root directory of your GLM installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLM in ${DEF_DIR_GLM}")
IF(IS_DIRECTORY ${DEF_DIR_GLM})
MESSAGE(STATUS "Found!")
SET(GLM_INCLUDE_DIR ${DEF_DIR_GLM})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
INCLUDE_DIRECTORIES(${GLM_INCLUDE_DIR})
# Get the GLFW environment variable. There should be a CMakeLists.txt in the
# specified directory.
SET(GLFW_DIR "$ENV{GLFW_DIR}")
IF(NOT GLFW_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLFW_DIR to the root directory of your GLFW installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLFW in ${DEF_DIR_GLFW}")
IF(IS_DIRECTORY ${DEF_DIR_GLFW})
MESSAGE(STATUS "Found!")
SET(GLFW_DIR ${DEF_DIR_GLFW})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
OPTION(GLFW_BUILD_EXAMPLES "GLFW_BUILD_EXAMPLES" OFF)
OPTION(GLFW_BUILD_TESTS "GLFW_BUILD_TESTS" OFF)
OPTION(GLFW_BUILD_DOCS "GLFW_BUILD_DOCS" OFF)
IF(CMAKE_BUILD_TYPE MATCHES Release)
ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/release)
ELSE()
ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/debug)
ENDIF()
INCLUDE_DIRECTORIES(${GLFW_DIR}/include)
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} glfw ${GLFW_LIBRARIES})
# Get the GLEW environment variable.
SET(GLEW_DIR "$ENV{GLEW_DIR}")
IF(NOT GLEW_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLEW_DIR to the root directory of your GLEW installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLEW in ${DEF_DIR_GLEW}")
IF(IS_DIRECTORY ${DEF_DIR_GLEW})
MESSAGE(STATUS "Found!")
SET(GLEW_DIR ${DEF_DIR_GLEW})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
INCLUDE_DIRECTORIES(${GLEW_DIR}/include)
IF(WIN32)
# With prebuilt binaries
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/Release/Win32/glew32s.lib)
ELSE()
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/libGLEW.a)
ENDIF()
# OS specific options and libraries
IF(WIN32)
# c++11 is enabled by default.
# -Wall produces way too many warnings.
# -pedantic is not supported.
# Disable warning 4996.
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996")
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} opengl32.lib)
ELSE()
# Enable all pedantic warnings.
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pedantic")
IF(APPLE)
# Add required frameworks for GLFW.
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "-framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo")
ELSE()
#Link the Linux OpenGL library
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "GL")
ENDIF()
ENDIF()

View file

@ -0,0 +1,8 @@
#version 120
varying vec3 fragColor;
void main()
{
gl_FragColor = vec4(fragColor, 1.0);
}

View file

@ -0,0 +1,11 @@
#version 120
uniform mat4 P;
uniform mat4 MV;
varying vec3 fragColor;
void main()
{
gl_Position = P * MV * gl_Vertex;
fragColor = gl_Color.rgb;
}

152
L13/src/GLSL.cpp Normal file
View file

@ -0,0 +1,152 @@
//
// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book
// Created by zwood on 2/21/10.
// Modified by sueda 10/15/15.
//
#include "GLSL.h"
#include <stdio.h>
#include <stdlib.h>
#include <cassert>
#include <cstring>
using namespace std;
namespace GLSL {
const char * errorString(GLenum err)
{
switch(err) {
case GL_NO_ERROR:
return "No error";
case GL_INVALID_ENUM:
return "Invalid enum";
case GL_INVALID_VALUE:
return "Invalid value";
case GL_INVALID_OPERATION:
return "Invalid operation";
case GL_STACK_OVERFLOW:
return "Stack overflow";
case GL_STACK_UNDERFLOW:
return "Stack underflow";
case GL_OUT_OF_MEMORY:
return "Out of memory";
default:
return "No error";
}
}
void checkVersion()
{
int major, minor;
major = minor = 0;
const char *verstr = (const char *)glGetString(GL_VERSION);
if((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) != 2)) {
printf("Invalid GL_VERSION format %d.%d\n", major, minor);
}
if(major < 2) {
printf("This shader example will not work due to the installed Opengl version, which is %d.%d.\n", major, minor);
exit(0);
}
}
void checkError(const char *str)
{
GLenum glErr = glGetError();
if(glErr != GL_NO_ERROR) {
if(str) {
printf("%s: ", str);
}
printf("GL_ERROR = %s.\n", errorString(glErr));
assert(false);
}
}
void printShaderInfoLog(GLuint shader)
{
GLint infologLength = 0;
GLint charsWritten = 0;
GLchar *infoLog = 0;
checkError(GET_FILE_LINE);
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength);
checkError(GET_FILE_LINE);
if(infologLength > 0) {
infoLog = (GLchar *)malloc(infologLength);
if(infoLog == NULL) {
puts("ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog);
checkError(GET_FILE_LINE);
printf("Shader InfoLog:\n%s\n\n", infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint program)
{
GLint infologLength = 0;
GLint charsWritten = 0;
GLchar *infoLog = 0;
checkError(GET_FILE_LINE);
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength);
checkError(GET_FILE_LINE);
if(infologLength > 0) {
infoLog = (GLchar *)malloc(infologLength);
if(infoLog == NULL) {
puts("ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog);
checkError(GET_FILE_LINE);
printf("Program InfoLog:\n%s\n\n", infoLog);
free(infoLog);
}
}
char *textFileRead(const 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 = (int)ftell(fp);
rewind(fp);
if(count > 0) {
content = (char *)malloc(sizeof(char) * (count+1));
count = (int)fread(content,sizeof(char),count,fp);
content[count] = '\0';
}
fclose(fp);
} else {
printf("error loading %s\n", fn);
}
}
return content;
}
int textFileWrite(const char *fn, const char *s)
{
FILE *fp;
int status = 0;
if(fn != NULL) {
fp = fopen(fn,"w");
if(fp != NULL) {
if(fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) {
status = 1;
}
fclose(fp);
}
}
return(status);
}
}

40
L13/src/GLSL.h Normal file
View file

@ -0,0 +1,40 @@
//
// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book
// Created by zwood on 2/21/10.
// Modified by sueda 10/15/15.
//
#pragma once
#ifndef __GLSL__
#define __GLSL__
#define GLEW_STATIC
#include <GL/glew.h>
///////////////////////////////////////////////////////////////////////////////
// For printing out the current file and line number //
///////////////////////////////////////////////////////////////////////////////
#include <sstream>
template <typename T>
std::string NumberToString(T x)
{
std::ostringstream ss;
ss << x;
return ss.str();
}
#define GET_FILE_LINE (std::string(__FILE__) + ":" + NumberToString(__LINE__)).c_str()
///////////////////////////////////////////////////////////////////////////////
namespace GLSL {
void checkVersion();
void checkError(const char *str = 0);
void printProgramInfoLog(GLuint program);
void printShaderInfoLog(GLuint shader);
int textFileWrite(const char *filename, const char *s);
char *textFileRead(const char *filename);
}
#endif

114
L13/src/MatrixStack.cpp Normal file
View file

@ -0,0 +1,114 @@
#include "MatrixStack.h"
#include <stdio.h>
#include <cassert>
#include <vector>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
using namespace std;
MatrixStack::MatrixStack()
{
mstack = make_shared< stack<glm::mat4> >();
mstack->push(glm::mat4(1.0));
}
MatrixStack::~MatrixStack()
{
}
void MatrixStack::pushMatrix()
{
const glm::mat4 &top = mstack->top();
mstack->push(top);
assert(mstack->size() < 100);
}
void MatrixStack::popMatrix()
{
assert(!mstack->empty());
mstack->pop();
// There should always be one matrix left.
assert(!mstack->empty());
}
void MatrixStack::loadIdentity()
{
glm::mat4 &top = mstack->top();
top = glm::mat4(1.0);
}
void MatrixStack::translate(const glm::vec3 &t)
{
glm::mat4 &top = mstack->top();
top *= glm::translate(t);
}
void MatrixStack::translate(float x, float y, float z)
{
translate(glm::vec3(x, y, z));
}
void MatrixStack::scale(const glm::vec3 &s)
{
glm::mat4 &top = mstack->top();
top *= glm::scale(s);
}
void MatrixStack::scale(float x, float y, float z)
{
scale(glm::vec3(x, y, z));
}
void MatrixStack::scale(float s)
{
scale(glm::vec3(s, s, s));
}
void MatrixStack::rotate(float angle, const glm::vec3 &axis)
{
glm::mat4 &top = mstack->top();
top *= glm::rotate(angle, axis);
}
void MatrixStack::rotate(float angle, float x, float y, float z)
{
rotate(angle, glm::vec3(x, y, z));
}
void MatrixStack::multMatrix(const glm::mat4 &matrix)
{
glm::mat4 &top = mstack->top();
top *= matrix;
}
const glm::mat4 &MatrixStack::topMatrix() const
{
return mstack->top();
}
void MatrixStack::print(const glm::mat4 &mat, const char *name)
{
if(name) {
printf("%s = [\n", name);
}
for(int i = 0; i < 4; ++i) {
for(int j = 0; j < 4; ++j) {
// mat[j] returns the jth column
printf("%- 5.2f ", mat[j][i]);
}
printf("\n");
}
if(name) {
printf("];");
}
printf("\n");
}
void MatrixStack::print(const char *name) const
{
print(mstack->top(), name);
}

50
L13/src/MatrixStack.h Normal file
View file

@ -0,0 +1,50 @@
#pragma once
#ifndef _MatrixStack_H_
#define _MatrixStack_H_
#include <stack>
#include <memory>
#include <glm/fwd.hpp>
class MatrixStack
{
public:
MatrixStack();
virtual ~MatrixStack();
// glPushMatrix(): Copies the current matrix and adds it to the top of the stack
void pushMatrix();
// glPopMatrix(): Removes the top of the stack and sets the current matrix to be the matrix that is now on top
void popMatrix();
// glLoadIdentity(): Sets the top matrix to be the identity
void loadIdentity();
// glMultMatrix(): Right multiplies the top matrix
void multMatrix(const glm::mat4 &matrix);
// glTranslate(): Right multiplies the top matrix by a translation matrix
void translate(const glm::vec3 &trans);
void translate(float x, float y, float z);
// glScale(): Right multiplies the top matrix by a scaling matrix
void scale(const glm::vec3 &scale);
void scale(float x, float y, float z);
// glScale(): Right multiplies the top matrix by a scaling matrix
void scale(float size);
// glRotate(): Right multiplies the top matrix by a rotation matrix (angle in radians)
void rotate(float angle, const glm::vec3 &axis);
void rotate(float angle, float x, float y, float z);
// glGet(GL_MODELVIEW_MATRIX): Gets the top matrix
const glm::mat4 &topMatrix() const;
// Prints out the specified matrix
static void print(const glm::mat4 &mat, const char *name = 0);
// Prints out the top matrix
void print(const char *name = 0) const;
private:
std::shared_ptr< std::stack<glm::mat4> > mstack;
};
#endif

126
L13/src/Program.cpp Normal file
View file

@ -0,0 +1,126 @@
#include "Program.h"
#include <iostream>
#include <cassert>
#include "GLSL.h"
using namespace std;
Program::Program() :
vShaderName(""),
fShaderName(""),
pid(0),
verbose(true)
{
}
Program::~Program()
{
}
void Program::setShaderNames(const string &v, const string &f)
{
vShaderName = v;
fShaderName = f;
}
bool Program::init()
{
GLint rc;
// Create shader handles
GLuint VS = glCreateShader(GL_VERTEX_SHADER);
GLuint FS = glCreateShader(GL_FRAGMENT_SHADER);
// Read shader sources
const char *vshader = GLSL::textFileRead(vShaderName.c_str());
const char *fshader = GLSL::textFileRead(fShaderName.c_str());
glShaderSource(VS, 1, &vshader, NULL);
glShaderSource(FS, 1, &fshader, NULL);
// Compile vertex shader
glCompileShader(VS);
glGetShaderiv(VS, GL_COMPILE_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printShaderInfoLog(VS);
cout << "Error compiling vertex shader " << vShaderName << endl;
}
return false;
}
// Compile fragment shader
glCompileShader(FS);
glGetShaderiv(FS, GL_COMPILE_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printShaderInfoLog(FS);
cout << "Error compiling fragment shader " << fShaderName << endl;
}
return false;
}
// Create the program and link
pid = glCreateProgram();
glAttachShader(pid, VS);
glAttachShader(pid, FS);
glLinkProgram(pid);
glGetProgramiv(pid, GL_LINK_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printProgramInfoLog(pid);
cout << "Error linking shaders " << vShaderName << " and " << fShaderName << endl;
}
return false;
}
GLSL::checkError(GET_FILE_LINE);
return true;
}
void Program::bind()
{
glUseProgram(pid);
}
void Program::unbind()
{
glUseProgram(0);
}
void Program::addAttribute(const string &name)
{
attributes[name] = glGetAttribLocation(pid, name.c_str());
}
void Program::addUniform(const string &name)
{
uniforms[name] = glGetUniformLocation(pid, name.c_str());
}
GLint Program::getAttribute(const string &name) const
{
map<string,GLint>::const_iterator attribute = attributes.find(name.c_str());
if(attribute == attributes.end()) {
if(isVerbose()) {
cout << name << " is not an attribute variable" << endl;
}
return -1;
}
return attribute->second;
}
GLint Program::getUniform(const string &name) const
{
map<string,GLint>::const_iterator uniform = uniforms.find(name.c_str());
if(uniform == uniforms.end()) {
if(isVerbose()) {
cout << name << " is not a uniform variable" << endl;
}
return -1;
}
return uniform->second;
}

44
L13/src/Program.h Normal file
View file

@ -0,0 +1,44 @@
#pragma once
#ifndef __Program__
#define __Program__
#include <map>
#include <string>
#define GLEW_STATIC
#include <GL/glew.h>
/**
* An OpenGL Program (vertex and fragment shaders)
*/
class Program
{
public:
Program();
virtual ~Program();
void setVerbose(bool v) { verbose = v; }
bool isVerbose() const { return verbose; }
void setShaderNames(const std::string &v, const std::string &f);
virtual bool init();
virtual void bind();
virtual void unbind();
void addAttribute(const std::string &name);
void addUniform(const std::string &name);
GLint getAttribute(const std::string &name) const;
GLint getUniform(const std::string &name) const;
protected:
std::string vShaderName;
std::string fShaderName;
private:
GLuint pid;
std::map<std::string,GLint> attributes;
std::map<std::string,GLint> uniforms;
bool verbose;
};
#endif

360
L13/src/main.cpp Normal file
View file

@ -0,0 +1,360 @@
#include <iostream>
#include <vector>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "GLSL.h"
#include "Program.h"
#include "MatrixStack.h"
using namespace std;
GLFWwindow *window; // Main application window
string RESOURCE_DIR = ""; // Where the resources are loaded from
shared_ptr<Program> prog;
bool keyToggles[256] = {false}; // only for English keyboards!
glm::vec2 cameraRotations(0, 0);
glm::vec2 mousePrev(-1, -1);
// Control points
vector<glm::vec3> cps;
enum SplineType
{
CATMULL_ROM = 0,
BASIS,
SPLINE_TYPE_COUNT
};
SplineType type = CATMULL_ROM;
glm::mat4 Bcr, Bb;
vector<pair<float,float> > usTable;
void buildTable();
static void error_callback(int error, const char *description)
{
cerr << description << endl;
}
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GL_TRUE);
}
if(action == GLFW_PRESS) {
switch(key) {
case GLFW_KEY_S:
type = (SplineType)((type + 1) % SPLINE_TYPE_COUNT);
buildTable();
break;
case GLFW_KEY_C:
cps.clear();
buildTable();
break;
case GLFW_KEY_R:
cps.clear();
int n = 8;
for(int i = 0; i < n; ++i) {
float alpha = i / (n - 1.0f);
float angle = 2.0f * M_PI * alpha;
float radius = cos(2.0f * angle);
glm::vec3 cp;
cp.x = radius * cos(angle);
cp.y = radius * sin(angle);
cp.z = (1.0f - alpha)*(-0.5) + alpha*0.5;
cps.push_back(cp);
}
buildTable();
break;
}
}
}
static void char_callback(GLFWwindow *window, unsigned int key)
{
keyToggles[key] = !keyToggles[key];
}
static void cursor_position_callback(GLFWwindow* window, double xmouse, double ymouse)
{
if(mousePrev.x >= 0) {
glm::vec2 mouseCurr(xmouse, ymouse);
cameraRotations += 0.01f * (mouseCurr - mousePrev);
mousePrev = mouseCurr;
}
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
// Get the current mouse position.
double xmouse, ymouse;
glfwGetCursorPos(window, &xmouse, &ymouse);
// Get current window size.
int width, height;
glfwGetWindowSize(window, &width, &height);
if(action == GLFW_PRESS) {
if(mods & GLFW_MOD_SHIFT) {
// Insert a new control point
// Convert from window coord to world coord assuming that we're
// using an orthgraphic projection from -1 to 1.
float aspect = (float)width/height;
glm::vec4 x;
x[0] = 2.0f * ((xmouse / width) - 0.5f)* aspect;
x[1] = 2.0f * (((height - ymouse) / height) - 0.5f);
x[2] = 0.0f;
x[3] = 1.0f;
// Build the current modelview matrix.
auto MV = make_shared<MatrixStack>();
MV->rotate(cameraRotations[1], glm::vec3(1, 0, 0));
MV->rotate(cameraRotations[0], glm::vec3(0, 1, 0));
// Since the modelview matrix transforms from world to eye coords,
// we want to invert to go from eye to world.
x = glm::inverse(MV->topMatrix()) * x;
cps.push_back(glm::vec3(x));
buildTable();
} else {
mousePrev.x = xmouse;
mousePrev.y = ymouse;
}
} else {
mousePrev[0] = -1;
mousePrev[1] = -1;
}
}
static void init()
{
GLSL::checkVersion();
// Set background color
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// Enable z-buffer test
glEnable(GL_DEPTH_TEST);
// Initialize the GLSL program.
prog = make_shared<Program>();
prog->setVerbose(true);
prog->setShaderNames(RESOURCE_DIR + "simple_vert.glsl", RESOURCE_DIR + "simple_frag.glsl");
prog->init();
prog->addUniform("P");
prog->addUniform("MV");
prog->setVerbose(false);
// Initialize time.
glfwSetTime(0.0);
keyToggles[(unsigned)'l'] = true;
Bcr[0] = glm::vec4( 0.0f, 2.0f, 0.0f, 0.0f);
Bcr[1] = glm::vec4(-1.0f, 0.0f, 1.0f, 0.0f);
Bcr[2] = glm::vec4( 2.0f, -5.0f, 4.0f, -1.0f);
Bcr[3] = glm::vec4(-1.0f, 3.0f, -3.0f, 1.0f);
Bcr *= 0.5;
Bb[0] = glm::vec4( 1.0f, 4.0f, 1.0f, 0.0f);
Bb[1] = glm::vec4(-3.0f, 0.0f, 3.0f, 0.0f);
Bb[2] = glm::vec4( 3.0f, -6.0f, 3.0f, 0.0f);
Bb[3] = glm::vec4(-1.0f, 3.0f, -3.0f, 1.0f);
Bb /= 6.0f;
// If there were any OpenGL errors, this will print something.
// You can intersperse this line in your code to find the exact location
// of your OpenGL error.
GLSL::checkError(GET_FILE_LINE);
}
void buildTable()
{
// INSERT CODE HERE
usTable.clear();
}
float s2u(float s)
{
// INSERT CODE HERE
return 0.0f;
}
void render()
{
// Update time.
//double t = glfwGetTime();
// Get current frame buffer size.
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// Clear buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
auto P = make_shared<MatrixStack>();
auto MV = make_shared<MatrixStack>();
P->pushMatrix();
MV->pushMatrix();
double aspect = (double)width/height;
P->multMatrix(glm::ortho(-aspect, aspect, -1.0, 1.0, -2.0, 2.0));
MV->rotate(cameraRotations.y, glm::vec3(1, 0, 0));
MV->rotate(cameraRotations.x, glm::vec3(0, 1, 0));
// Bind the program
prog->bind();
glUniformMatrix4fv(prog->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix()));
glUniformMatrix4fv(prog->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix()));
// Draw control points
int ncps = (int)cps.size();
glPointSize(5.0f);
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_POINTS);
for(int i = 0; i < ncps; ++i) {
glVertex3f(cps[i].x, cps[i].y, cps[i].z);
}
glEnd();
glLineWidth(1.0f);
if(keyToggles[(unsigned)'l']) {
glColor3f(1.0f, 0.5f, 0.5f);
glBegin(GL_LINE_STRIP);
for(int i = 0; i < ncps; ++i) {
glVertex3f(cps[i].x, cps[i].y, cps[i].z);
}
glEnd();
}
if(ncps >= 4) {
// Draw spline
glm::mat4 B = (type == CATMULL_ROM ? Bcr : Bb);
glLineWidth(3.0f);
for(int k = 0; k < ncps - 3; ++k) {
glm::mat4 Gk;
for(int i = 0; i < 4; ++i) {
Gk[i] = glm::vec4(cps[k+i], 0.0f);
}
int n = 32; // curve discretization
glBegin(GL_LINE_STRIP);
if(k % 2 == 0) {
// Even segment color
glColor3f(0.0f, 1.0f, 0.0f);
} else {
// Odd segment color
glColor3f(0.0f, 0.0f, 1.0f);
}
for(int i = 0; i < n; ++i) {
// u goes from 0 to 1 within this segment
float u = i / (n - 1.0f);
// Compute spline point at u
glm::vec4 uVec(1.0f, u, u*u, u*u*u);
glm::vec3 P(Gk * (B * uVec));
glVertex3fv(&P[0]);
}
glEnd();
}
// Draw equally spaced points on the spline curve
if(keyToggles[(unsigned)'a'] && !usTable.empty()) {
float ds = 0.2;
glColor3f(1.0f, 0.0f, 0.0f);
glPointSize(10.0f);
glBegin(GL_POINTS);
float smax = usTable.back().second; // spline length
for(float s = 0.0f; s < smax; s += ds) {
// Convert from s to (concatenated) u
float uu = s2u(s);
// Convert from concatenated u to the usual u between 0 and 1.
float kfloat;
float u = std::modf(uu, &kfloat);
// k is the index of the starting control point
int k = (int)std::floor(kfloat);
// Compute spline point at u
glm::mat4 Gk;
for(int i = 0; i < 4; ++i) {
Gk[i] = glm::vec4(cps[k+i], 0.0f);
}
glm::vec4 uVec(1.0f, u, u*u, u*u*u);
glm::vec3 P(Gk * (B * uVec));
glVertex3fv(&P[0]);
}
glEnd();
}
}
// Unbind the program
prog->unbind();
// Pop matrix stacks.
MV->popMatrix();
P->popMatrix();
GLSL::checkError(GET_FILE_LINE);
}
int main(int argc, char **argv)
{
if(argc < 2) {
cout << "Please specify the resource directory." << endl;
return 0;
}
RESOURCE_DIR = argv[1] + string("/");
// Set error callback.
glfwSetErrorCallback(error_callback);
// Initialize the library.
if(!glfwInit()) {
return -1;
}
// Create a windowed mode window and its OpenGL context.
window = glfwCreateWindow(640, 480, "YOUR NAME", NULL, NULL);
if(!window) {
glfwTerminate();
return -1;
}
// Make the window's context current.
glfwMakeContextCurrent(window);
// Initialize GLEW.
glewExperimental = true;
if(glewInit() != GLEW_OK) {
cerr << "Failed to initialize GLEW" << endl;
return -1;
}
glGetError(); // A bug in glewInit() causes an error that we can safely ignore.
cout << "OpenGL version: " << glGetString(GL_VERSION) << endl;
cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;
// Set vsync.
glfwSwapInterval(1);
// Set keyboard callback.
glfwSetKeyCallback(window, key_callback);
// Set char callback.
glfwSetCharCallback(window, char_callback);
// Set cursor position callback.
glfwSetCursorPosCallback(window, cursor_position_callback);
// Set mouse button callback.
glfwSetMouseButtonCallback(window, mouse_button_callback);
// Initialize scene.
init();
// Loop until the user closes the window.
while(!glfwWindowShouldClose(window)) {
// Render scene.
render();
// Swap front and back buffers.
glfwSwapBuffers(window);
// Poll for and process events.
glfwPollEvents();
}
// Quit program.
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}

BIN
L14.zip Normal file

Binary file not shown.

148
L14/CMakeLists.txt Normal file
View file

@ -0,0 +1,148 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
# Name of the project
PROJECT(L14)
# FOR LAB MACHINES ONLY!
# DO NOT EDIT
SET(DEF_DIR_GLM "C:\\c++\\glm")
SET(DEF_DIR_GLFW "C:\\c++\\glfw-3.2.1")
SET(DEF_DIR_GLEW "C:\\c++\\glew-2.0.0")
SET(DEF_DIR_EIGEN "C:\\c++\\eigen-eigen-f562a193118d")
# Is this the solution?
# Override with `cmake -DSOL=ON ..`
OPTION(SOL "Solution" OFF)
# Use glob to get the list of all source files.
# We don't really need to include header and resource files to build, but it's
# nice to have them also show up in IDEs.
IF(${SOL})
FILE(GLOB_RECURSE SOURCES "src0/*.cpp")
FILE(GLOB_RECURSE HEADERS "src0/*.h")
ELSE()
FILE(GLOB_RECURSE SOURCES "src/*.cpp")
FILE(GLOB_RECURSE HEADERS "src/*.h")
ENDIF()
FILE(GLOB_RECURSE GLSL "resources/*.glsl")
# Set the executable.
ADD_EXECUTABLE(${CMAKE_PROJECT_NAME} ${SOURCES} ${HEADERS} ${GLSL})
# Get the GLM environment variable. Since GLM is a header-only library, we
# just need to add it to the include directory.
SET(GLM_INCLUDE_DIR "$ENV{GLM_INCLUDE_DIR}")
IF(NOT GLM_INCLUDE_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLM_INCLUDE_DIR to the root directory of your GLM installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLM in ${DEF_DIR_GLM}")
IF(IS_DIRECTORY ${DEF_DIR_GLM})
MESSAGE(STATUS "Found!")
SET(GLM_INCLUDE_DIR ${DEF_DIR_GLM})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
INCLUDE_DIRECTORIES(${GLM_INCLUDE_DIR})
# Get the GLFW environment variable. There should be a CMakeLists.txt in the
# specified directory.
SET(GLFW_DIR "$ENV{GLFW_DIR}")
IF(NOT GLFW_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLFW_DIR to the root directory of your GLFW installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLFW in ${DEF_DIR_GLFW}")
IF(IS_DIRECTORY ${DEF_DIR_GLFW})
MESSAGE(STATUS "Found!")
SET(GLFW_DIR ${DEF_DIR_GLFW})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
OPTION(GLFW_BUILD_EXAMPLES "GLFW_BUILD_EXAMPLES" OFF)
OPTION(GLFW_BUILD_TESTS "GLFW_BUILD_TESTS" OFF)
OPTION(GLFW_BUILD_DOCS "GLFW_BUILD_DOCS" OFF)
IF(CMAKE_BUILD_TYPE MATCHES Release)
ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/release)
ELSE()
ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/debug)
ENDIF()
INCLUDE_DIRECTORIES(${GLFW_DIR}/include)
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} glfw ${GLFW_LIBRARIES})
# Get the GLEW environment variable.
SET(GLEW_DIR "$ENV{GLEW_DIR}")
IF(NOT GLEW_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLEW_DIR to the root directory of your GLEW installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLEW in ${DEF_DIR_GLEW}")
IF(IS_DIRECTORY ${DEF_DIR_GLEW})
MESSAGE(STATUS "Found!")
SET(GLEW_DIR ${DEF_DIR_GLEW})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
INCLUDE_DIRECTORIES(${GLEW_DIR}/include)
IF(WIN32)
# With prebuilt binaries
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/Release/Win32/glew32s.lib)
ELSE()
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/libGLEW.a)
ENDIF()
# Get the EIGEN environment variable. Since EIGEN is a header-only library, we
# just need to add it to the include directory.
SET(EIGEN3_INCLUDE_DIR "$ENV{EIGEN3_INCLUDE_DIR}")
IF(NOT EIGEN3_INCLUDE_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable EIGEN3_INCLUDE_DIR to the root directory of your EIGEN installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for EIGEN in ${DEF_DIR_EIGEN}")
IF(IS_DIRECTORY ${DEF_DIR_EIGEN})
MESSAGE(STATUS "Found!")
SET(EIGEN3_INCLUDE_DIR ${DEF_DIR_EIGEN})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
INCLUDE_DIRECTORIES(${EIGEN3_INCLUDE_DIR})
# OS specific options and libraries
IF(WIN32)
# c++11 is enabled by default.
# -Wall produces way too many warnings.
# -pedantic is not supported.
# Disable warning 4996.
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996")
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} opengl32.lib)
ELSE()
# Enable all pedantic warnings.
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pedantic")
IF(APPLE)
# Add required frameworks for GLFW.
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "-framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo")
ELSE()
#Link the Linux OpenGL library
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "GL")
ENDIF()
ENDIF()

View file

@ -0,0 +1,8 @@
#version 120
varying vec3 fragColor;
void main()
{
gl_FragColor = vec4(fragColor, 1.0);
}

View file

@ -0,0 +1,11 @@
#version 120
uniform mat4 P;
uniform mat4 MV;
varying vec3 fragColor;
void main()
{
gl_Position = P * MV * gl_Vertex;
fragColor = gl_Color.rgb;
}

152
L14/src/GLSL.cpp Normal file
View file

@ -0,0 +1,152 @@
//
// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book
// Created by zwood on 2/21/10.
// Modified by sueda 10/15/15.
//
#include "GLSL.h"
#include <stdio.h>
#include <stdlib.h>
#include <cassert>
#include <cstring>
using namespace std;
namespace GLSL {
const char * errorString(GLenum err)
{
switch(err) {
case GL_NO_ERROR:
return "No error";
case GL_INVALID_ENUM:
return "Invalid enum";
case GL_INVALID_VALUE:
return "Invalid value";
case GL_INVALID_OPERATION:
return "Invalid operation";
case GL_STACK_OVERFLOW:
return "Stack overflow";
case GL_STACK_UNDERFLOW:
return "Stack underflow";
case GL_OUT_OF_MEMORY:
return "Out of memory";
default:
return "No error";
}
}
void checkVersion()
{
int major, minor;
major = minor = 0;
const char *verstr = (const char *)glGetString(GL_VERSION);
if((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) != 2)) {
printf("Invalid GL_VERSION format %d.%d\n", major, minor);
}
if(major < 2) {
printf("This shader example will not work due to the installed Opengl version, which is %d.%d.\n", major, minor);
exit(0);
}
}
void checkError(const char *str)
{
GLenum glErr = glGetError();
if(glErr != GL_NO_ERROR) {
if(str) {
printf("%s: ", str);
}
printf("GL_ERROR = %s.\n", errorString(glErr));
assert(false);
}
}
void printShaderInfoLog(GLuint shader)
{
GLint infologLength = 0;
GLint charsWritten = 0;
GLchar *infoLog = 0;
checkError(GET_FILE_LINE);
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength);
checkError(GET_FILE_LINE);
if(infologLength > 0) {
infoLog = (GLchar *)malloc(infologLength);
if(infoLog == NULL) {
puts("ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog);
checkError(GET_FILE_LINE);
printf("Shader InfoLog:\n%s\n\n", infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint program)
{
GLint infologLength = 0;
GLint charsWritten = 0;
GLchar *infoLog = 0;
checkError(GET_FILE_LINE);
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength);
checkError(GET_FILE_LINE);
if(infologLength > 0) {
infoLog = (GLchar *)malloc(infologLength);
if(infoLog == NULL) {
puts("ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog);
checkError(GET_FILE_LINE);
printf("Program InfoLog:\n%s\n\n", infoLog);
free(infoLog);
}
}
char *textFileRead(const 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 = (int)ftell(fp);
rewind(fp);
if(count > 0) {
content = (char *)malloc(sizeof(char) * (count+1));
count = (int)fread(content,sizeof(char),count,fp);
content[count] = '\0';
}
fclose(fp);
} else {
printf("error loading %s\n", fn);
}
}
return content;
}
int textFileWrite(const char *fn, const char *s)
{
FILE *fp;
int status = 0;
if(fn != NULL) {
fp = fopen(fn,"w");
if(fp != NULL) {
if(fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) {
status = 1;
}
fclose(fp);
}
}
return(status);
}
}

40
L14/src/GLSL.h Normal file
View file

@ -0,0 +1,40 @@
//
// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book
// Created by zwood on 2/21/10.
// Modified by sueda 10/15/15.
//
#pragma once
#ifndef __GLSL__
#define __GLSL__
#define GLEW_STATIC
#include <GL/glew.h>
///////////////////////////////////////////////////////////////////////////////
// For printing out the current file and line number //
///////////////////////////////////////////////////////////////////////////////
#include <sstream>
template <typename T>
std::string NumberToString(T x)
{
std::ostringstream ss;
ss << x;
return ss.str();
}
#define GET_FILE_LINE (std::string(__FILE__) + ":" + NumberToString(__LINE__)).c_str()
///////////////////////////////////////////////////////////////////////////////
namespace GLSL {
void checkVersion();
void checkError(const char *str = 0);
void printProgramInfoLog(GLuint program);
void printShaderInfoLog(GLuint shader);
int textFileWrite(const char *filename, const char *s);
char *textFileRead(const char *filename);
}
#endif

114
L14/src/MatrixStack.cpp Normal file
View file

@ -0,0 +1,114 @@
#include "MatrixStack.h"
#include <stdio.h>
#include <cassert>
#include <vector>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
using namespace std;
MatrixStack::MatrixStack()
{
mstack = make_shared< stack<glm::mat4> >();
mstack->push(glm::mat4(1.0));
}
MatrixStack::~MatrixStack()
{
}
void MatrixStack::pushMatrix()
{
const glm::mat4 &top = mstack->top();
mstack->push(top);
assert(mstack->size() < 100);
}
void MatrixStack::popMatrix()
{
assert(!mstack->empty());
mstack->pop();
// There should always be one matrix left.
assert(!mstack->empty());
}
void MatrixStack::loadIdentity()
{
glm::mat4 &top = mstack->top();
top = glm::mat4(1.0);
}
void MatrixStack::translate(const glm::vec3 &t)
{
glm::mat4 &top = mstack->top();
top *= glm::translate(t);
}
void MatrixStack::translate(float x, float y, float z)
{
translate(glm::vec3(x, y, z));
}
void MatrixStack::scale(const glm::vec3 &s)
{
glm::mat4 &top = mstack->top();
top *= glm::scale(s);
}
void MatrixStack::scale(float x, float y, float z)
{
scale(glm::vec3(x, y, z));
}
void MatrixStack::scale(float s)
{
scale(glm::vec3(s, s, s));
}
void MatrixStack::rotate(float angle, const glm::vec3 &axis)
{
glm::mat4 &top = mstack->top();
top *= glm::rotate(angle, axis);
}
void MatrixStack::rotate(float angle, float x, float y, float z)
{
rotate(angle, glm::vec3(x, y, z));
}
void MatrixStack::multMatrix(const glm::mat4 &matrix)
{
glm::mat4 &top = mstack->top();
top *= matrix;
}
const glm::mat4 &MatrixStack::topMatrix() const
{
return mstack->top();
}
void MatrixStack::print(const glm::mat4 &mat, const char *name)
{
if(name) {
printf("%s = [\n", name);
}
for(int i = 0; i < 4; ++i) {
for(int j = 0; j < 4; ++j) {
// mat[j] returns the jth column
printf("%- 5.2f ", mat[j][i]);
}
printf("\n");
}
if(name) {
printf("];");
}
printf("\n");
}
void MatrixStack::print(const char *name) const
{
print(mstack->top(), name);
}

50
L14/src/MatrixStack.h Normal file
View file

@ -0,0 +1,50 @@
#pragma once
#ifndef _MatrixStack_H_
#define _MatrixStack_H_
#include <stack>
#include <memory>
#include <glm/fwd.hpp>
class MatrixStack
{
public:
MatrixStack();
virtual ~MatrixStack();
// glPushMatrix(): Copies the current matrix and adds it to the top of the stack
void pushMatrix();
// glPopMatrix(): Removes the top of the stack and sets the current matrix to be the matrix that is now on top
void popMatrix();
// glLoadIdentity(): Sets the top matrix to be the identity
void loadIdentity();
// glMultMatrix(): Right multiplies the top matrix
void multMatrix(const glm::mat4 &matrix);
// glTranslate(): Right multiplies the top matrix by a translation matrix
void translate(const glm::vec3 &trans);
void translate(float x, float y, float z);
// glScale(): Right multiplies the top matrix by a scaling matrix
void scale(const glm::vec3 &scale);
void scale(float x, float y, float z);
// glScale(): Right multiplies the top matrix by a scaling matrix
void scale(float size);
// glRotate(): Right multiplies the top matrix by a rotation matrix (angle in radians)
void rotate(float angle, const glm::vec3 &axis);
void rotate(float angle, float x, float y, float z);
// glGet(GL_MODELVIEW_MATRIX): Gets the top matrix
const glm::mat4 &topMatrix() const;
// Prints out the specified matrix
static void print(const glm::mat4 &mat, const char *name = 0);
// Prints out the top matrix
void print(const char *name = 0) const;
private:
std::shared_ptr< std::stack<glm::mat4> > mstack;
};
#endif

126
L14/src/Program.cpp Normal file
View file

@ -0,0 +1,126 @@
#include "Program.h"
#include <iostream>
#include <cassert>
#include "GLSL.h"
using namespace std;
Program::Program() :
vShaderName(""),
fShaderName(""),
pid(0),
verbose(true)
{
}
Program::~Program()
{
}
void Program::setShaderNames(const string &v, const string &f)
{
vShaderName = v;
fShaderName = f;
}
bool Program::init()
{
GLint rc;
// Create shader handles
GLuint VS = glCreateShader(GL_VERTEX_SHADER);
GLuint FS = glCreateShader(GL_FRAGMENT_SHADER);
// Read shader sources
const char *vshader = GLSL::textFileRead(vShaderName.c_str());
const char *fshader = GLSL::textFileRead(fShaderName.c_str());
glShaderSource(VS, 1, &vshader, NULL);
glShaderSource(FS, 1, &fshader, NULL);
// Compile vertex shader
glCompileShader(VS);
glGetShaderiv(VS, GL_COMPILE_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printShaderInfoLog(VS);
cout << "Error compiling vertex shader " << vShaderName << endl;
}
return false;
}
// Compile fragment shader
glCompileShader(FS);
glGetShaderiv(FS, GL_COMPILE_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printShaderInfoLog(FS);
cout << "Error compiling fragment shader " << fShaderName << endl;
}
return false;
}
// Create the program and link
pid = glCreateProgram();
glAttachShader(pid, VS);
glAttachShader(pid, FS);
glLinkProgram(pid);
glGetProgramiv(pid, GL_LINK_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printProgramInfoLog(pid);
cout << "Error linking shaders " << vShaderName << " and " << fShaderName << endl;
}
return false;
}
GLSL::checkError(GET_FILE_LINE);
return true;
}
void Program::bind()
{
glUseProgram(pid);
}
void Program::unbind()
{
glUseProgram(0);
}
void Program::addAttribute(const string &name)
{
attributes[name] = glGetAttribLocation(pid, name.c_str());
}
void Program::addUniform(const string &name)
{
uniforms[name] = glGetUniformLocation(pid, name.c_str());
}
GLint Program::getAttribute(const string &name) const
{
map<string,GLint>::const_iterator attribute = attributes.find(name.c_str());
if(attribute == attributes.end()) {
if(isVerbose()) {
cout << name << " is not an attribute variable" << endl;
}
return -1;
}
return attribute->second;
}
GLint Program::getUniform(const string &name) const
{
map<string,GLint>::const_iterator uniform = uniforms.find(name.c_str());
if(uniform == uniforms.end()) {
if(isVerbose()) {
cout << name << " is not a uniform variable" << endl;
}
return -1;
}
return uniform->second;
}

44
L14/src/Program.h Normal file
View file

@ -0,0 +1,44 @@
#pragma once
#ifndef __Program__
#define __Program__
#include <map>
#include <string>
#define GLEW_STATIC
#include <GL/glew.h>
/**
* An OpenGL Program (vertex and fragment shaders)
*/
class Program
{
public:
Program();
virtual ~Program();
void setVerbose(bool v) { verbose = v; }
bool isVerbose() const { return verbose; }
void setShaderNames(const std::string &v, const std::string &f);
virtual bool init();
virtual void bind();
virtual void unbind();
void addAttribute(const std::string &name);
void addUniform(const std::string &name);
GLint getAttribute(const std::string &name) const;
GLint getUniform(const std::string &name) const;
protected:
std::string vShaderName;
std::string fShaderName;
private:
GLuint pid;
std::map<std::string,GLint> attributes;
std::map<std::string,GLint> uniforms;
bool verbose;
};
#endif

230
L14/src/main.cpp Normal file
View file

@ -0,0 +1,230 @@
#include <iostream>
#include <vector>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#define EIGEN_DONT_ALIGN_STATICALLY
#include <Eigen/Dense>
#include "GLSL.h"
#include "Program.h"
#include "MatrixStack.h"
using namespace std;
GLFWwindow *window; // Main application window
string RESOURCE_DIR = ""; // Where the resources are loaded from
shared_ptr<Program> prog;
bool keyToggles[256] = {false}; // only for English keyboards!
glm::vec2 mouse;
Eigen::Vector4f coeffs0;
Eigen::Vector4f coeffs1;
float xmid;
static void error_callback(int error, const char *description)
{
cerr << description << endl;
}
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GL_TRUE);
}
}
static void char_callback(GLFWwindow *window, unsigned int key)
{
keyToggles[key] = !keyToggles[key];
}
static void cursor_position_callback(GLFWwindow* window, double xmouse, double ymouse)
{
// Convert from window coords to world coords
// (Assumes orthographic projection)
int width, height;
glfwGetWindowSize(window, &width, &height);
glm::vec4 p;
// Inverse of viewing transform
p.x = xmouse / (float)width;
p.y = (height - ymouse) / (float)height;
p.x = 2.0f * (p.x - 0.5f);
p.y = 2.0f * (p.y - 0.5f);
p.z = 0.0f;
p.w = 1.0f;
// Inverse of model-view-projection transform
auto P = make_shared<MatrixStack>();
auto MV = make_shared<MatrixStack>();
float aspect = (float)width/height;
float s = 0.6f;
P->multMatrix(glm::ortho(-s*aspect, s*aspect, -s, s));
MV->translate(glm::vec3(-0.5, -0.5, 0.0));
p = glm::inverse(P->topMatrix() * MV->topMatrix()) * p;
mouse = glm::vec2(p);
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
// Not used for this lab
}
static void init()
{
GLSL::checkVersion();
// Set background color
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Enable z-buffer test
glEnable(GL_DEPTH_TEST);
// Initialize the GLSL program.
prog = make_shared<Program>();
prog->setVerbose(false); // Set this to true when debugging.
prog->setShaderNames(RESOURCE_DIR + "simple_vert.glsl", RESOURCE_DIR + "simple_frag.glsl");
prog->init();
prog->addUniform("P");
prog->addUniform("MV");
//
// Compute the coefficients here
//
xmid = 0.4f;
coeffs0 << -2.0f, 3.0f, 0.0f, 0.0f;
coeffs1 << -2.0f, 3.0f, 0.0f, 0.0f;
// If there were any OpenGL errors, this will print something.
// You can intersperse this line in your code to find the exact location
// of your OpenGL error.
GLSL::checkError(GET_FILE_LINE);
}
void render()
{
// Get current frame buffer size.
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// Clear buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
auto P = make_shared<MatrixStack>();
auto MV = make_shared<MatrixStack>();
P->pushMatrix();
MV->pushMatrix();
float aspect = (float)width/height;
float s = 0.6f;
P->multMatrix(glm::ortho(-s*aspect, s*aspect, -s, s));
MV->translate(glm::vec3(-0.5, -0.5, 0.0));
// Bind the program
prog->bind();
glUniformMatrix4fv(prog->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix()));
glUniformMatrix4fv(prog->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix()));
// Draw grid
int gridSize = 5;
glLineWidth(2.0f);
glColor3f(0.2f, 0.2f, 0.2f);
glBegin(GL_LINES);
for(int i = 1; i < gridSize; ++i) {
float x = i / (float)gridSize;
glVertex2f(x, 0.0f);
glVertex2f(x, 1.0f);
}
for(int i = 1; i < gridSize; ++i) {
float y = i / (float)gridSize;
glVertex2f(0.0f, y);
glVertex2f(1.0f, y);
}
glEnd();
glLineWidth(4.0f);
glColor3f(0.8f, 0.8f, 0.8f);
glBegin(GL_LINE_LOOP);
glVertex2f(0.0f, 0.0f);
glVertex2f(1.0f, 0.0f);
glVertex2f(1.0f, 1.0f);
glVertex2f(0.0f, 1.0f);
glEnd();
//
// Draw cubics here
//
// Unbind the program
prog->unbind();
// Pop matrix stacks.
MV->popMatrix();
P->popMatrix();
GLSL::checkError(GET_FILE_LINE);
}
int main(int argc, char **argv)
{
if(argc < 2) {
cout << "Please specify the resource directory." << endl;
return 0;
}
RESOURCE_DIR = argv[1] + string("/");
// Set error callback.
glfwSetErrorCallback(error_callback);
// Initialize the library.
if(!glfwInit()) {
return -1;
}
// Create a windowed mode window and its OpenGL context.
window = glfwCreateWindow(640, 480, "YOUR NAME", NULL, NULL);
if(!window) {
glfwTerminate();
return -1;
}
// Make the window's context current.
glfwMakeContextCurrent(window);
// Initialize GLEW.
glewExperimental = true;
if(glewInit() != GLEW_OK) {
cerr << "Failed to initialize GLEW" << endl;
return -1;
}
glGetError(); // A bug in glewInit() causes an error that we can safely ignore.
cout << "OpenGL version: " << glGetString(GL_VERSION) << endl;
cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;
// Set vsync.
glfwSwapInterval(1);
// Set keyboard callback.
glfwSetKeyCallback(window, key_callback);
// Set char callback.
glfwSetCharCallback(window, char_callback);
// Set cursor position callback.
glfwSetCursorPosCallback(window, cursor_position_callback);
// Set mouse button callback.
glfwSetMouseButtonCallback(window, mouse_button_callback);
// Initialize scene.
init();
// Loop until the user closes the window.
while(!glfwWindowShouldClose(window)) {
// Render scene.
render();
// Swap front and back buffers.
glfwSwapBuffers(window);
// Poll for and process events.
glfwPollEvents();
}
// Quit program.
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}

BIN
L15.zip Normal file

Binary file not shown.

127
L15/CMakeLists.txt Normal file
View file

@ -0,0 +1,127 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
# Name of the project
PROJECT(L15)
# FOR LAB MACHINES ONLY!
# DO NOT EDIT
SET(DEF_DIR_GLM "C:\\c++\\glm")
SET(DEF_DIR_GLFW "C:\\c++\\glfw-3.2.1")
SET(DEF_DIR_GLEW "C:\\c++\\glew-2.0.0")
# Is this the solution?
# Override with `cmake -DSOL=ON ..`
OPTION(SOL "Solution" OFF)
# Use glob to get the list of all source files.
# We don't really need to include header and resource files to build, but it's
# nice to have them also show up in IDEs.
IF(${SOL})
FILE(GLOB_RECURSE SOURCES "src0/*.cpp")
FILE(GLOB_RECURSE HEADERS "src0/*.h")
FILE(GLOB_RECURSE GLSL "resources0/*.glsl")
ELSE()
FILE(GLOB_RECURSE SOURCES "src/*.cpp")
FILE(GLOB_RECURSE HEADERS "src/*.h")
FILE(GLOB_RECURSE GLSL "resources/*.glsl")
ENDIF()
# Set the executable.
ADD_EXECUTABLE(${CMAKE_PROJECT_NAME} ${SOURCES} ${HEADERS} ${GLSL})
# Get the GLM environment variable. Since GLM is a header-only library, we
# just need to add it to the include directory.
SET(GLM_INCLUDE_DIR "$ENV{GLM_INCLUDE_DIR}")
IF(NOT GLM_INCLUDE_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLM_INCLUDE_DIR to the root directory of your GLM installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLM in ${DEF_DIR_GLM}")
IF(IS_DIRECTORY ${DEF_DIR_GLM})
MESSAGE(STATUS "Found!")
SET(GLM_INCLUDE_DIR ${DEF_DIR_GLM})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
INCLUDE_DIRECTORIES(${GLM_INCLUDE_DIR})
# Get the GLFW environment variable. There should be a CMakeLists.txt in the
# specified directory.
SET(GLFW_DIR "$ENV{GLFW_DIR}")
IF(NOT GLFW_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLFW_DIR to the root directory of your GLFW installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLFW in ${DEF_DIR_GLFW}")
IF(IS_DIRECTORY ${DEF_DIR_GLFW})
MESSAGE(STATUS "Found!")
SET(GLFW_DIR ${DEF_DIR_GLFW})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
OPTION(GLFW_BUILD_EXAMPLES "GLFW_BUILD_EXAMPLES" OFF)
OPTION(GLFW_BUILD_TESTS "GLFW_BUILD_TESTS" OFF)
OPTION(GLFW_BUILD_DOCS "GLFW_BUILD_DOCS" OFF)
IF(CMAKE_BUILD_TYPE MATCHES Release)
ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/release)
ELSE()
ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/debug)
ENDIF()
INCLUDE_DIRECTORIES(${GLFW_DIR}/include)
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} glfw ${GLFW_LIBRARIES})
# Get the GLEW environment variable.
SET(GLEW_DIR "$ENV{GLEW_DIR}")
IF(NOT GLEW_DIR)
# The environment variable was not set
SET(ERR_MSG "Please point the environment variable GLEW_DIR to the root directory of your GLEW installation.")
IF(WIN32)
# On Windows, try the default location
MESSAGE(STATUS "Looking for GLEW in ${DEF_DIR_GLEW}")
IF(IS_DIRECTORY ${DEF_DIR_GLEW})
MESSAGE(STATUS "Found!")
SET(GLEW_DIR ${DEF_DIR_GLEW})
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR ${ERR_MSG})
ENDIF()
ENDIF()
INCLUDE_DIRECTORIES(${GLEW_DIR}/include)
IF(WIN32)
# With prebuilt binaries
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/Release/Win32/glew32s.lib)
ELSE()
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/libGLEW.a)
ENDIF()
# OS specific options and libraries
IF(WIN32)
# c++11 is enabled by default.
# -Wall produces way too many warnings.
# -pedantic is not supported.
# Disable warning 4996.
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996")
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} opengl32.lib)
ELSE()
# Enable all pedantic warnings.
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pedantic")
IF(APPLE)
# Add required frameworks for GLFW.
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "-framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo")
ELSE()
#Link the Linux OpenGL library
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "GL")
ENDIF()
ENDIF()

1011
L15/resources/man.obj Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,8 @@
#version 120
varying vec3 color;
void main()
{
gl_FragColor = vec4(color, 1.0);
}

View file

@ -0,0 +1,11 @@
#version 120
uniform mat4 P;
uniform mat4 MV;
varying vec3 color;
void main()
{
gl_Position = P * MV * gl_Vertex;
color = gl_Color.rgb;
}

View file

@ -0,0 +1,10 @@
#version 120
uniform sampler2D colorTexture;
varying vec2 fragTexCoords;
void main()
{
vec4 c = texture2D(colorTexture, fragTexCoords);
gl_FragColor = vec4(c.rgb, 1.0);
}

View file

@ -0,0 +1,13 @@
#version 120
attribute vec4 vertPos;
attribute vec2 vertTex;
uniform mat4 P;
uniform mat4 MV;
varying vec2 fragTexCoords;
void main()
{
gl_Position = P * MV * vertPos;
fragTexCoords = vertTex;
}

BIN
L15/resources/wood_tex.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

152
L15/src/GLSL.cpp Normal file
View file

@ -0,0 +1,152 @@
//
// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book
// Created by zwood on 2/21/10.
// Modified by sueda 10/15/15.
//
#include "GLSL.h"
#include <stdio.h>
#include <stdlib.h>
#include <cassert>
#include <cstring>
using namespace std;
namespace GLSL {
const char * errorString(GLenum err)
{
switch(err) {
case GL_NO_ERROR:
return "No error";
case GL_INVALID_ENUM:
return "Invalid enum";
case GL_INVALID_VALUE:
return "Invalid value";
case GL_INVALID_OPERATION:
return "Invalid operation";
case GL_STACK_OVERFLOW:
return "Stack overflow";
case GL_STACK_UNDERFLOW:
return "Stack underflow";
case GL_OUT_OF_MEMORY:
return "Out of memory";
default:
return "No error";
}
}
void checkVersion()
{
int major, minor;
major = minor = 0;
const char *verstr = (const char *)glGetString(GL_VERSION);
if((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) != 2)) {
printf("Invalid GL_VERSION format %d.%d\n", major, minor);
}
if(major < 2) {
printf("This shader example will not work due to the installed Opengl version, which is %d.%d.\n", major, minor);
exit(0);
}
}
void checkError(const char *str)
{
GLenum glErr = glGetError();
if(glErr != GL_NO_ERROR) {
if(str) {
printf("%s: ", str);
}
printf("GL_ERROR = %s.\n", errorString(glErr));
assert(false);
}
}
void printShaderInfoLog(GLuint shader)
{
GLint infologLength = 0;
GLint charsWritten = 0;
GLchar *infoLog = 0;
checkError(GET_FILE_LINE);
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength);
checkError(GET_FILE_LINE);
if(infologLength > 0) {
infoLog = (GLchar *)malloc(infologLength);
if(infoLog == NULL) {
puts("ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog);
checkError(GET_FILE_LINE);
printf("Shader InfoLog:\n%s\n\n", infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint program)
{
GLint infologLength = 0;
GLint charsWritten = 0;
GLchar *infoLog = 0;
checkError(GET_FILE_LINE);
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength);
checkError(GET_FILE_LINE);
if(infologLength > 0) {
infoLog = (GLchar *)malloc(infologLength);
if(infoLog == NULL) {
puts("ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog);
checkError(GET_FILE_LINE);
printf("Program InfoLog:\n%s\n\n", infoLog);
free(infoLog);
}
}
char *textFileRead(const 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 = (int)ftell(fp);
rewind(fp);
if(count > 0) {
content = (char *)malloc(sizeof(char) * (count+1));
count = (int)fread(content,sizeof(char),count,fp);
content[count] = '\0';
}
fclose(fp);
} else {
printf("error loading %s\n", fn);
}
}
return content;
}
int textFileWrite(const char *fn, const char *s)
{
FILE *fp;
int status = 0;
if(fn != NULL) {
fp = fopen(fn,"w");
if(fp != NULL) {
if(fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) {
status = 1;
}
fclose(fp);
}
}
return(status);
}
}

40
L15/src/GLSL.h Normal file
View file

@ -0,0 +1,40 @@
//
// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book
// Created by zwood on 2/21/10.
// Modified by sueda 10/15/15.
//
#pragma once
#ifndef __GLSL__
#define __GLSL__
#define GLEW_STATIC
#include <GL/glew.h>
///////////////////////////////////////////////////////////////////////////////
// For printing out the current file and line number //
///////////////////////////////////////////////////////////////////////////////
#include <sstream>
template <typename T>
std::string NumberToString(T x)
{
std::ostringstream ss;
ss << x;
return ss.str();
}
#define GET_FILE_LINE (std::string(__FILE__) + ":" + NumberToString(__LINE__)).c_str()
///////////////////////////////////////////////////////////////////////////////
namespace GLSL {
void checkVersion();
void checkError(const char *str = 0);
void printProgramInfoLog(GLuint program);
void printShaderInfoLog(GLuint shader);
int textFileWrite(const char *filename, const char *s);
char *textFileRead(const char *filename);
}
#endif

185
L15/src/Grid.cpp Normal file
View file

@ -0,0 +1,185 @@
#define GLEW_STATIC
#include <GL/glew.h>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include "Grid.h"
using namespace std;
Grid::Grid() :
nrows(2),
ncols(2),
closest(-1)
{
}
Grid::~Grid()
{
}
void Grid::setSize(int nrows, int ncols)
{
this->nrows = nrows;
this->ncols = ncols;
cps.resize(nrows*ncols);
reset();
}
void Grid::reset()
{
// -1 to +1 in both x and y
for(int col = 0; col < ncols; ++col) {
float x = -1.0f + col/(ncols-1.0f)*2.0f;
for(int row = 0; row < nrows; ++row) {
float y = -1.0f + row/(nrows-1.0f)*2.0f;
glm::vec2 &cp = cps[indexAt(row, col)];
cp.x = x;
cp.y = y;
}
}
}
int Grid::indexAt(int row, int col) const
{
return row*ncols + col;
}
void Grid::moveCP(const glm::vec2 &p)
{
if(closest != -1) {
cps[closest] = p;
}
}
void Grid::findClosest(const glm::vec2 &p)
{
closest = -1;
float dmin = 0.1f;
for(int col = 0; col < ncols; ++col) {
for(int row = 0; row < nrows; ++row) {
const glm::vec2 &cp = cps[indexAt(row, col)];
float d = glm::length(p - cp);
if(d < dmin) {
closest = indexAt(row, col);
dmin = d;
}
}
}
}
void Grid::draw() const
{
// Draw closest control point
glPointSize(6.0f);
glColor3f(0.5f, 0.5f, 0.5f);
if(closest != -1) {
glBegin(GL_POINTS);
const glm::vec2 &cp = cps[closest];
glVertex3f(cp.x, cp.y, 0.01f); // offset slightly above the shape
glEnd();
}
// Draw grid
glLineWidth(1.0f);
for(int col = 0; col < ncols; ++col) {
glBegin(GL_LINE_STRIP);
for(int row = 0; row < nrows; ++row) {
const glm::vec2 &cp = cps[indexAt(row, col)];
glVertex3f(cp.x, cp.y, 0.01f); // offset slightly above the shape
}
glEnd();
}
for(int row = 0; row < nrows; ++row) {
glBegin(GL_LINE_STRIP);
for(int col = 0; col < ncols; ++col) {
const glm::vec2 &cp = cps[indexAt(row, col)];
glVertex3f(cp.x, cp.y, 0.01f); // offset slightly above the shape
}
glEnd();
}
}
vector<glm::vec2> Grid::getTileCPs(int index) const
{
// Return the 4 cps corresponding to the index
// 2---3
// | |
// 0---1
assert(index >= 0);
assert(index + ncols + 1 < cps.size());
vector<glm::vec2> cps_;
cps_.push_back(cps[index]);
cps_.push_back(cps[index + 1]);
cps_.push_back(cps[index + ncols]);
cps_.push_back(cps[index + ncols + 1]);
return cps_;
}
const vector<glm::vec2> & Grid::getAllCPs() const
{
return cps;
}
void Grid::save(const char *filename) const
{
ofstream out(filename);
if(!out.good()) {
cout << "Could not open " << filename << endl;
return;
}
out << nrows << endl;
out << ncols << endl;
for(int k = 0; k < (int)cps.size(); ++k) {
const glm::vec2 &cp = cps[k];
out << cp.x << " " << cp.y << endl;
}
out << "##################################" << endl;
out.close();
}
void Grid::load(const char *filename)
{
ifstream in;
in.open(filename);
if(!in.good()) {
std::cout << "Cannot read " << filename << endl;
return;
}
in >> nrows;
in >> ncols;
cps.resize(nrows*ncols);
cps.clear();
string line;
// Discard rest of the first line.
getline(in, line);
while(1) {
getline(in, line);
if(in.eof()) {
break;
}
// Skip empty lines
if(line.size() < 2) {
continue;
}
// Skip comments
if(line.at(0) == '#') {
continue;
}
// Parse line
stringstream ss(line);
glm::vec2 cp;
ss >> cp.x;
ss >> cp.y;
cps.push_back(cp);
}
in.close();
}

36
L15/src/Grid.h Normal file
View file

@ -0,0 +1,36 @@
#pragma once
#ifndef __Grid__
#define __Grid__
#include <vector>
#include <glm/fwd.hpp>
class Grid
{
public:
Grid();
virtual ~Grid();
void setSize(int nrows, int ncols);
void reset();
void moveCP(const glm::vec2 &p);
void findClosest(const glm::vec2 &p);
void draw() const;
int indexAt(int row, int col) const;
int getRows() const { return nrows; };
int getCols() const { return ncols; };
std::vector<glm::vec2> getTileCPs(int index) const;
const std::vector<glm::vec2> & getAllCPs() const;
void save(const char *filename) const;
void load(const char *filename);
private:
std::vector<glm::vec2> cps;
int nrows;
int ncols;
int closest;
};
#endif

114
L15/src/MatrixStack.cpp Normal file
View file

@ -0,0 +1,114 @@
#include "MatrixStack.h"
#include <stdio.h>
#include <cassert>
#include <vector>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
using namespace std;
MatrixStack::MatrixStack()
{
mstack = make_shared< stack<glm::mat4> >();
mstack->push(glm::mat4(1.0));
}
MatrixStack::~MatrixStack()
{
}
void MatrixStack::pushMatrix()
{
const glm::mat4 &top = mstack->top();
mstack->push(top);
assert(mstack->size() < 100);
}
void MatrixStack::popMatrix()
{
assert(!mstack->empty());
mstack->pop();
// There should always be one matrix left.
assert(!mstack->empty());
}
void MatrixStack::loadIdentity()
{
glm::mat4 &top = mstack->top();
top = glm::mat4(1.0);
}
void MatrixStack::translate(const glm::vec3 &t)
{
glm::mat4 &top = mstack->top();
top *= glm::translate(t);
}
void MatrixStack::translate(float x, float y, float z)
{
translate(glm::vec3(x, y, z));
}
void MatrixStack::scale(const glm::vec3 &s)
{
glm::mat4 &top = mstack->top();
top *= glm::scale(s);
}
void MatrixStack::scale(float x, float y, float z)
{
scale(glm::vec3(x, y, z));
}
void MatrixStack::scale(float s)
{
scale(glm::vec3(s, s, s));
}
void MatrixStack::rotate(float angle, const glm::vec3 &axis)
{
glm::mat4 &top = mstack->top();
top *= glm::rotate(angle, axis);
}
void MatrixStack::rotate(float angle, float x, float y, float z)
{
rotate(angle, glm::vec3(x, y, z));
}
void MatrixStack::multMatrix(const glm::mat4 &matrix)
{
glm::mat4 &top = mstack->top();
top *= matrix;
}
const glm::mat4 &MatrixStack::topMatrix() const
{
return mstack->top();
}
void MatrixStack::print(const glm::mat4 &mat, const char *name)
{
if(name) {
printf("%s = [\n", name);
}
for(int i = 0; i < 4; ++i) {
for(int j = 0; j < 4; ++j) {
// mat[j] returns the jth column
printf("%- 5.2f ", mat[j][i]);
}
printf("\n");
}
if(name) {
printf("];");
}
printf("\n");
}
void MatrixStack::print(const char *name) const
{
print(mstack->top(), name);
}

50
L15/src/MatrixStack.h Normal file
View file

@ -0,0 +1,50 @@
#pragma once
#ifndef _MatrixStack_H_
#define _MatrixStack_H_
#include <stack>
#include <memory>
#include <glm/fwd.hpp>
class MatrixStack
{
public:
MatrixStack();
virtual ~MatrixStack();
// glPushMatrix(): Copies the current matrix and adds it to the top of the stack
void pushMatrix();
// glPopMatrix(): Removes the top of the stack and sets the current matrix to be the matrix that is now on top
void popMatrix();
// glLoadIdentity(): Sets the top matrix to be the identity
void loadIdentity();
// glMultMatrix(): Right multiplies the top matrix
void multMatrix(const glm::mat4 &matrix);
// glTranslate(): Right multiplies the top matrix by a translation matrix
void translate(const glm::vec3 &trans);
void translate(float x, float y, float z);
// glScale(): Right multiplies the top matrix by a scaling matrix
void scale(const glm::vec3 &scale);
void scale(float x, float y, float z);
// glScale(): Right multiplies the top matrix by a scaling matrix
void scale(float size);
// glRotate(): Right multiplies the top matrix by a rotation matrix (angle in radians)
void rotate(float angle, const glm::vec3 &axis);
void rotate(float angle, float x, float y, float z);
// glGet(GL_MODELVIEW_MATRIX): Gets the top matrix
const glm::mat4 &topMatrix() const;
// Prints out the specified matrix
static void print(const glm::mat4 &mat, const char *name = 0);
// Prints out the top matrix
void print(const char *name = 0) const;
private:
std::shared_ptr< std::stack<glm::mat4> > mstack;
};
#endif

126
L15/src/Program.cpp Normal file
View file

@ -0,0 +1,126 @@
#include "Program.h"
#include <iostream>
#include <cassert>
#include "GLSL.h"
using namespace std;
Program::Program() :
vShaderName(""),
fShaderName(""),
pid(0),
verbose(true)
{
}
Program::~Program()
{
}
void Program::setShaderNames(const string &v, const string &f)
{
vShaderName = v;
fShaderName = f;
}
bool Program::init()
{
GLint rc;
// Create shader handles
GLuint VS = glCreateShader(GL_VERTEX_SHADER);
GLuint FS = glCreateShader(GL_FRAGMENT_SHADER);
// Read shader sources
const char *vshader = GLSL::textFileRead(vShaderName.c_str());
const char *fshader = GLSL::textFileRead(fShaderName.c_str());
glShaderSource(VS, 1, &vshader, NULL);
glShaderSource(FS, 1, &fshader, NULL);
// Compile vertex shader
glCompileShader(VS);
glGetShaderiv(VS, GL_COMPILE_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printShaderInfoLog(VS);
cout << "Error compiling vertex shader " << vShaderName << endl;
}
return false;
}
// Compile fragment shader
glCompileShader(FS);
glGetShaderiv(FS, GL_COMPILE_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printShaderInfoLog(FS);
cout << "Error compiling fragment shader " << fShaderName << endl;
}
return false;
}
// Create the program and link
pid = glCreateProgram();
glAttachShader(pid, VS);
glAttachShader(pid, FS);
glLinkProgram(pid);
glGetProgramiv(pid, GL_LINK_STATUS, &rc);
if(!rc) {
if(isVerbose()) {
GLSL::printProgramInfoLog(pid);
cout << "Error linking shaders " << vShaderName << " and " << fShaderName << endl;
}
return false;
}
GLSL::checkError(GET_FILE_LINE);
return true;
}
void Program::bind()
{
glUseProgram(pid);
}
void Program::unbind()
{
glUseProgram(0);
}
void Program::addAttribute(const string &name)
{
attributes[name] = glGetAttribLocation(pid, name.c_str());
}
void Program::addUniform(const string &name)
{
uniforms[name] = glGetUniformLocation(pid, name.c_str());
}
GLint Program::getAttribute(const string &name) const
{
map<string,GLint>::const_iterator attribute = attributes.find(name.c_str());
if(attribute == attributes.end()) {
if(isVerbose()) {
cout << name << " is not an attribute variable" << endl;
}
return -1;
}
return attribute->second;
}
GLint Program::getUniform(const string &name) const
{
map<string,GLint>::const_iterator uniform = uniforms.find(name.c_str());
if(uniform == uniforms.end()) {
if(isVerbose()) {
cout << name << " is not a uniform variable" << endl;
}
return -1;
}
return uniform->second;
}

44
L15/src/Program.h Normal file
View file

@ -0,0 +1,44 @@
#pragma once
#ifndef __Program__
#define __Program__
#include <map>
#include <string>
#define GLEW_STATIC
#include <GL/glew.h>
/**
* An OpenGL Program (vertex and fragment shaders)
*/
class Program
{
public:
Program();
virtual ~Program();
void setVerbose(bool v) { verbose = v; }
bool isVerbose() const { return verbose; }
void setShaderNames(const std::string &v, const std::string &f);
virtual bool init();
virtual void bind();
virtual void unbind();
void addAttribute(const std::string &name);
void addUniform(const std::string &name);
GLint getAttribute(const std::string &name) const;
GLint getUniform(const std::string &name) const;
protected:
std::string vShaderName;
std::string fShaderName;
private:
GLuint pid;
std::map<std::string,GLint> attributes;
std::map<std::string,GLint> uniforms;
bool verbose;
};
#endif

151
L15/src/ShapeCage.cpp Normal file
View file

@ -0,0 +1,151 @@
#include <iostream>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
#include "ShapeCage.h"
#include "GLSL.h"
#include "Grid.h"
using namespace std;
ShapeCage::ShapeCage() :
posBufID(0),
texBufID(0),
elemBufID(0)
{
}
ShapeCage::~ShapeCage()
{
}
void ShapeCage::load(const string &meshName)
{
// Load geometry
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
string errStr;
bool rc = tinyobj::LoadObj(&attrib, &shapes, &materials, &errStr, meshName.c_str());
if(!rc) {
cerr << errStr << endl;
} else {
posBuf = attrib.vertices;
norBuf = attrib.normals;
texBuf = attrib.texcoords;
//assert(posBuf.size() == norBuf.size());
// Loop over shapes
for(size_t s = 0; s < shapes.size(); s++) {
// Loop over faces (polygons)
const tinyobj::mesh_t &mesh = shapes[s].mesh;
size_t index_offset = 0;
for(size_t f = 0; f < mesh.num_face_vertices.size(); f++) {
size_t fv = mesh.num_face_vertices[f];
// Loop over vertices in the face.
for(size_t v = 0; v < fv; v++) {
// access to vertex
tinyobj::index_t idx = mesh.indices[index_offset + v];
elemBuf.push_back(idx.vertex_index);
}
index_offset += fv;
// per-face material (IGNORE)
shapes[s].mesh.material_ids[f];
}
}
}
}
void ShapeCage::toLocal()
{
// Find which tile each vertex belongs to.
// Store (row, col) into tileBuf.
int nVerts = (int)posBuf.size()/3;
posLocalBuf.resize(nVerts*2);
tileIndexBuf.resize(nVerts);
int nrows = grid->getRows();
int ncols = grid->getCols();
// Go through all vertices
for(int k = 0; k < nVerts; ++k) {
float x = posBuf[3*k];
float y = posBuf[3*k+1];
//
// IMPLEMENT ME
// Fill in posLocalBuf and tileIndexBuf.
//
posLocalBuf[2*k+0] = x;
posLocalBuf[2*k+1] = y;
tileIndexBuf[k] = 0;
}
}
void ShapeCage::toWorld()
{
int nVerts = (int)posBuf.size()/3;
for(int k = 0; k < nVerts; ++k) {
float u = posLocalBuf[2*k];
float v = posLocalBuf[2*k+1];
//
// IMPLEMENT ME
// Fill in posBuf from the info stored in posLocalBuf and tileIndexBuf.
//
posBuf[3*k+0] = u;
posBuf[3*k+1] = v;
}
// Send the updated world position array to the GPU
glGenBuffers(1, &posBufID);
glBindBuffer(GL_ARRAY_BUFFER, posBufID);
glBufferData(GL_ARRAY_BUFFER, posBuf.size()*sizeof(float), &posBuf[0], GL_DYNAMIC_DRAW);
}
void ShapeCage::init()
{
// Send the texture coordinates array (if it exists) to the GPU
if(!texBuf.empty()) {
glGenBuffers(1, &texBufID);
glBindBuffer(GL_ARRAY_BUFFER, texBufID);
glBufferData(GL_ARRAY_BUFFER, texBuf.size()*sizeof(float), &texBuf[0], GL_STATIC_DRAW);
} else {
texBufID = 0;
}
// Send the index array to the GPU
glGenBuffers(1, &elemBufID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elemBufID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elemBuf.size()*sizeof(unsigned int), &elemBuf[0], GL_STATIC_DRAW);
// Unbind the arrays
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
assert(glGetError() == GL_NO_ERROR);
}
void ShapeCage::draw(int h_pos, int h_tex) const
{
// Enable and bind position array for drawing
glEnableVertexAttribArray(h_pos);
glBindBuffer(GL_ARRAY_BUFFER, posBufID);
glVertexAttribPointer(h_pos, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Enable and bind texcoord array for drawing
glEnableVertexAttribArray(h_tex);
glBindBuffer(GL_ARRAY_BUFFER, texBufID);
glVertexAttribPointer(h_tex, 2, GL_FLOAT, GL_FALSE, 0, 0);
// Bind element array for drawing
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elemBufID);
// Draw
int nElements = (int)elemBuf.size();
glDrawElements(GL_TRIANGLES, nElements, GL_UNSIGNED_INT, 0);
// Disable and unbind
glDisableVertexAttribArray(h_tex);
glDisableVertexAttribArray(h_pos);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

35
L15/src/ShapeCage.h Normal file
View file

@ -0,0 +1,35 @@
#pragma once
#ifndef _SHAPECAGE_H_
#define _SHAPECAGE_H_
#include <memory>
#include <vector>
class Grid;
class ShapeCage
{
public:
ShapeCage();
virtual ~ShapeCage();
void load(const std::string &meshName);
void setGrid(std::shared_ptr<Grid> g) { grid = g; }
void toLocal();
void toWorld();
void init();
void draw(int h_pos, int h_tex) const;
private:
std::vector<unsigned int> elemBuf;
std::vector<float> posBuf;
std::vector<float> norBuf;
std::vector<float> texBuf;
std::vector<float> posLocalBuf;
std::vector<float> tileIndexBuf;
unsigned posBufID;
unsigned texBufID;
unsigned elemBufID;
std::shared_ptr<Grid> grid;
};
#endif

80
L15/src/Texture.cpp Normal file
View file

@ -0,0 +1,80 @@
#include "Texture.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
using namespace std;
Texture::Texture() :
filename(""),
tid(0)
{
}
Texture::~Texture()
{
}
void Texture::init()
{
// Load texture
int w, h, ncomps;
stbi_set_flip_vertically_on_load(true);
unsigned char *data = stbi_load(filename.c_str(), &w, &h, &ncomps, 0);
if(!data) {
cerr << filename << " not found" << endl;
}
if(ncomps != 3) {
cerr << filename << " must have 3 components (RGB)" << endl;
}
if((w & (w - 1)) != 0 || (h & (h - 1)) != 0) {
cerr << filename << " must be a power of 2" << endl;
}
width = w;
height = h;
// Generate a texture buffer object
glGenTextures(1, &tid);
// Bind the current texture to be the newly generated texture object
glBindTexture(GL_TEXTURE_2D, tid);
// Load the actual texture data
// Base level is 0, number of channels is 3, and border is 0.
glTexImage2D(GL_TEXTURE_2D, 0, ncomps, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
// Generate image pyramid
glGenerateMipmap(GL_TEXTURE_2D);
// Set texture wrap modes for the S and T directions
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Set filtering mode for magnification and minimification
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// Unbind
glBindTexture(GL_TEXTURE_2D, 0);
// Free image, since the data is now on the GPU
stbi_image_free(data);
}
void Texture::setWrapModes(GLint wrapS, GLint wrapT)
{
// Must be called after init()
glBindTexture(GL_TEXTURE_2D, tid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
}
void Texture::bind(GLint handle)
{
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, tid);
glUniform1i(handle, unit);
}
void Texture::unbind()
{
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, 0);
}

32
L15/src/Texture.h Normal file
View file

@ -0,0 +1,32 @@
#pragma once
#ifndef __Texture__
#define __Texture__
#define GLEW_STATIC
#include <GL/glew.h>
#include <string>
class Texture
{
public:
Texture();
virtual ~Texture();
void setFilename(const std::string &f) { filename = f; }
void init();
void setUnit(GLint u) { unit = u; }
GLint getUnit() const { return unit; }
void bind(GLint handle);
void unbind();
void setWrapModes(GLint wrapS, GLint wrapT); // Must be called after init()
private:
std::string filename;
int width;
int height;
GLuint tid;
GLint unit;
};
#endif

260
L15/src/main.cpp Normal file
View file

@ -0,0 +1,260 @@
#include <iostream>
#include <vector>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "GLSL.h"
#include "Program.h"
#include "MatrixStack.h"
#include "ShapeCage.h"
#include "Texture.h"
#include "Grid.h"
using namespace std;
GLFWwindow *window; // Main application window
string RESOURCE_DIR = ""; // Where the resources are loaded from
shared_ptr<Program> progSimple;
shared_ptr<Program> progTex;
shared_ptr<Grid> grid;
shared_ptr<ShapeCage> shape;
shared_ptr<Texture> texture;
bool keyToggles[256] = {false}; // only for English keyboards!
glm::vec2 window2world(double xmouse, double ymouse)
{
// Convert from window coords to world coords
// (Assumes orthographic projection)
int width, height;
glfwGetWindowSize(window, &width, &height);
glm::vec4 p;
// Inverse of viewing transform
p.x = xmouse / (float)width;
p.y = (height - ymouse) / (float)height;
p.x = 2.0f * (p.x - 0.5f);
p.y = 2.0f * (p.y - 0.5f);
p.z = 0.0f;
p.w = 1.0f;
// Inverse of model-view-projection transform
auto P = make_shared<MatrixStack>();
auto MV = make_shared<MatrixStack>();
double aspect = (double)width/height;
double s = 1.1;
P->multMatrix(glm::ortho(-s*aspect, s*aspect, -s, s));
p = glm::inverse(P->topMatrix() * MV->topMatrix()) * p;
return glm::vec2(p);
}
static void error_callback(int error, const char *description)
{
cerr << description << endl;
}
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GL_TRUE);
}
}
static void char_callback(GLFWwindow *window, unsigned int key)
{
keyToggles[key] = !keyToggles[key];
switch(key) {
case 'r':
grid->reset();
break;
case 's':
grid->save("cps.txt");
break;
case 'l':
grid->load("cps.txt");
break;
}
}
static void cursor_position_callback(GLFWwindow* window, double xmouse, double ymouse)
{
int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
if(state == GLFW_PRESS) {
grid->moveCP(window2world(xmouse, ymouse));
} else {
grid->findClosest(window2world(xmouse, ymouse));
}
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
// Not used for this lab
}
static void init()
{
GLSL::checkVersion();
// Set background color
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// Enable z-buffer test
glEnable(GL_DEPTH_TEST);
// Initialize the GLSL program.
progSimple = make_shared<Program>();
progSimple->setVerbose(true); // Set this to true when debugging.
progSimple->setShaderNames(RESOURCE_DIR + "simple_vert.glsl", RESOURCE_DIR + "simple_frag.glsl");
progSimple->init();
progSimple->addUniform("P");
progSimple->addUniform("MV");
progSimple->setVerbose(false);
progTex = make_shared<Program>();
progTex->setVerbose(true); // Set this to true when debugging.
progTex->setShaderNames(RESOURCE_DIR + "tex_vert.glsl", RESOURCE_DIR + "tex_frag.glsl");
progTex->init();
progTex->addAttribute("vertPos");
progTex->addAttribute("vertTex");
progTex->addUniform("P");
progTex->addUniform("MV");
progTex->addUniform("colorTexture");
progTex->setVerbose(false);
texture = make_shared<Texture>();
texture->setFilename(RESOURCE_DIR + "wood_tex.jpg");
texture->init();
texture->setUnit(0);
// Grid of control points
grid = make_shared<Grid>();
grid->setSize(5, 5);
// Load scene
shape = make_shared<ShapeCage>();
shape->load(RESOURCE_DIR + "man.obj");
shape->setGrid(grid);
shape->toLocal();
shape->init();
// If there were any OpenGL errors, this will print something.
// You can intersperse this line in your code to find the exact location
// of your OpenGL error.
GLSL::checkError(GET_FILE_LINE);
}
void render()
{
// Get current frame buffer size.
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// Clear buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if(keyToggles[(unsigned)'c']) {
glEnable(GL_CULL_FACE);
} else {
glDisable(GL_CULL_FACE);
}
if(keyToggles[(unsigned)'z']) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
} else {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
auto P = make_shared<MatrixStack>();
auto MV = make_shared<MatrixStack>();
P->pushMatrix();
MV->pushMatrix();
double aspect = (double)width/height;
double s = 1.1;
P->multMatrix(glm::ortho(-s*aspect, s*aspect, -s, s));
// Draw cage
progSimple->bind();
glUniformMatrix4fv(progSimple->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix()));
glUniformMatrix4fv(progSimple->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix()));
grid->draw();
progSimple->unbind();
// Draw textured shape
progTex->bind();
texture->bind(progTex->getUniform("colorTexture"));
glUniformMatrix4fv(progTex->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix()));
glUniformMatrix4fv(progTex->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix()));
shape->toWorld();
shape->draw(progTex->getAttribute("vertPos"), progTex->getAttribute("vertTex"));
texture->unbind();
progTex->unbind();
// Pop matrix stacks.
MV->popMatrix();
P->popMatrix();
GLSL::checkError(GET_FILE_LINE);
}
int main(int argc, char **argv)
{
if(argc < 2) {
cout << "Please specify the resource directory." << endl;
return 0;
}
RESOURCE_DIR = argv[1] + string("/");
// Set error callback.
glfwSetErrorCallback(error_callback);
// Initialize the library.
if(!glfwInit()) {
return -1;
}
// Create a windowed mode window and its OpenGL context.
window = glfwCreateWindow(640, 480, "YOUR NAME", NULL, NULL);
if(!window) {
glfwTerminate();
return -1;
}
// Make the window's context current.
glfwMakeContextCurrent(window);
// Initialize GLEW.
glewExperimental = true;
if(glewInit() != GLEW_OK) {
cerr << "Failed to initialize GLEW" << endl;
return -1;
}
glGetError(); // A bug in glewInit() causes an error that we can safely ignore.
cout << "OpenGL version: " << glGetString(GL_VERSION) << endl;
cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;
// Set vsync.
glfwSwapInterval(1);
// Set keyboard callback.
glfwSetKeyCallback(window, key_callback);
// Set char callback.
glfwSetCharCallback(window, char_callback);
// Set cursor position callback.
glfwSetCursorPosCallback(window, cursor_position_callback);
// Set mouse button callback.
glfwSetMouseButtonCallback(window, mouse_button_callback);
// Initialize scene.
init();
// Loop until the user closes the window.
while(!glfwWindowShouldClose(window)) {
// Render scene.
render();
// Swap front and back buffers.
glfwSwapBuffers(window);
// Poll for and process events.
glfwPollEvents();
}
// Quit program.
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}

6755
L15/src/stb_image.h Normal file

File diff suppressed because it is too large Load diff

1922
L15/src/tiny_obj_loader.h Normal file

File diff suppressed because it is too large Load diff