This commit is contained in:
Michael Zhang 2023-04-08 20:40:50 -05:00
parent d1eab0d16f
commit 0212326d0a
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
10 changed files with 120 additions and 361 deletions

View file

@ -1,2 +1,4 @@
---
BasedOnStyle: LLVM
AlignAfterOpenBracket: BlockIndent

View file

@ -12,6 +12,7 @@
#include <istream>
#include <optional>
#include <sstream>
#include <string>
// Unfortunately this must be included first because it does some annoying check
// that vomits if GLFW has already been included (dumb)
@ -19,25 +20,41 @@
#include "GLFW/glfw3.h"
#define DEBUG_ON \
0 // repetitive of the debug flag in the shader loading code, included here
// for clarity only
// repetitive of the debug flag in the shader loading code, included here
// for clarity only
#define DEBUG_ON 1
// This file contains the code that reads the shaders from their files and
// compiles them
#include "ShaderStuff.hpp"
using namespace std;
//----------------------------------------------------------------------------
// Forward-declaring some functions for later implementation
/// Print the matrix
void printMatrix(string name, GLfloat *matrix);
/// Transpose a matrix
void transposeMatrix(GLfloat *matrix);
/// Zero-initialize a GLfloat array
void zeroInitGlfloats(GLfloat *arr, uint32_t len);
/// Multiplies two matrices and puts them into result.
///
/// - Left matrix must be ROW-order
/// - Right matrix must be COLUMN-order
///
/// Result will be row-order
void slow4x4MatrixMultiplyIntoRowOrder(GLfloat *left, GLfloat *right,
GLfloat *result);
/// Result will be column-order
void slow4x4MatrixMultiplyIntoColumnOrder(
GLfloat *left, GLfloat *right, GLfloat *result
);
void slow4x4MatrixMultiplyAllRowOrder(
GLfloat *left, GLfloat *right, GLfloat *result
);
//----------------------------------------------------------------------------
@ -50,7 +67,8 @@ typedef struct {
GLfloat r, g, b;
} ColorType3D;
GLfloat M[16]; // general transformation matrix
// general transformation matrix
GLfloat M[16];
// define some assorted global variables, to make life easier
GLint m_location;
@ -60,8 +78,11 @@ GLint window_height = 500;
GLdouble pi = 4.0 * atan(1.0);
// Added state
GLdouble scale_x = 1.0, scale_y = 1.0;
const GLdouble SCALE_DELTA = 0.05;
GLdouble scale_x = 1.0, scale_y = 1.0;
// Matrices
GLfloat rotation_matrix[16], translation_matrix[16], scale_matrix[16];
GLFWcursor *hand_cursor, *arrow_cursor; // some different cursors
@ -76,8 +97,8 @@ static void error_callback(int error, const char *description) {
//----------------------------------------------------------------------------
// function that is called whenever a keyboard event occurs; defines how
// keyboard input will be handled
static void key_callback(GLFWwindow *window, int key, int scancode, int action,
int mods) {
static void
key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) {
// checks to see if the escape key was pressed
if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
// closes the window
@ -102,8 +123,8 @@ static void key_callback(GLFWwindow *window, int key, int scancode, int action,
//----------------------------------------------------------------------------
// function that is called whenever a mouse or trackpad button press event
// occurs
static void mouse_button_callback(GLFWwindow *window, int button, int action,
int mods) {
static void
mouse_button_callback(GLFWwindow *window, int button, int action, int mods) {
glfwGetCursorPos(window, &mouse_x, &mouse_y);
// Check which mouse button triggered the event, e.g. GLFW_MOUSE_BUTTON_LEFT,
@ -131,6 +152,10 @@ void init(void) {
FloatType2D vertices[NVERTICES];
GLuint vao[1], buffer, program, location1, location2;
zeroInitGlfloats(rotation_matrix, 16);
zeroInitGlfloats(translation_matrix, 16);
zeroInitGlfloats(scale_matrix, 16);
// clang-format off
// set up some hard-coded colors and geometry
// this part can be customized to read in an object description from a file
@ -163,8 +188,10 @@ void init(void) {
// position and color data
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) + sizeof(colors), vertices,
GL_STATIC_DRAW);
glBufferData(
GL_ARRAY_BUFFER, sizeof(vertices) + sizeof(colors), vertices,
GL_STATIC_DRAW
);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(colors), colors);
@ -183,8 +210,9 @@ void init(void) {
glVertexAttribPointer(location1, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
location2 = glGetAttribLocation(program, "vertex_color");
glEnableVertexAttribArray(location2);
glVertexAttribPointer(location2, 3, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(sizeof(vertices)));
glVertexAttribPointer(
location2, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(vertices))
);
m_location = glGetUniformLocation(program, "M");
// Define static OpenGL state variables
@ -200,7 +228,6 @@ void init(void) {
//----------------------------------------------------------------------------
int main(int argc, char **argv) {
int i;
GLFWwindow *window;
@ -237,9 +264,9 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE);
}
glfwSwapInterval(
1); // tells the system to wait for the rendered frame to finish updating
// before swapping buffers; can help to avoid tearing
// tells the system to wait for the rendered frame to finish updating before
// swapping buffers; can help to avoid tearing
glfwSwapInterval(1);
// Define the keyboard callback function
glfwSetKeyCallback(window, key_callback);
@ -257,33 +284,40 @@ int main(int argc, char **argv) {
// fill/re-fill the window with the background color
glClear(GL_COLOR_BUFFER_BIT);
rotation_matrix[0] = 1.0;
rotation_matrix[5] = 1.0;
rotation_matrix[10] = 1.0;
rotation_matrix[15] = 1.0;
scale_matrix[0] = scale_x;
scale_matrix[5] = scale_y;
scale_matrix[10] = 1.0;
scale_matrix[15] = 1.0;
// define/re-define the modelview matrix. In this template, we define M to
// be the identity matrix; you will need define M according to the user's
// actions.
/* for (i = 0; i < 16; i++) {
M[i] = (i % 5 == 0);
}*/
M[0] = scale_x;
M[5] = scale_y;
M[10] = 1.0;
M[15] = 1.0;
slow4x4MatrixMultiplyIntoColumnOrder(rotation_matrix, scale_matrix, M);
// sanity check that your matrix contents are what you expect them to be
if (DEBUG_ON)
printf("M = [%f %f %f %f\n %f %f %f %f\n %f %f %f %f\n %f %f "
"%f %f]\n",
M[0], M[4], M[8], M[12], M[1], M[5], M[9], M[13], M[2], M[6],
M[10], M[14], M[3], M[7], M[11], M[15]);
if (DEBUG_ON) {
printf("--------------");
printf("scale_x = %f , scale_y = %f\n", scale_x, scale_y);
printMatrix("rotation_matrix", rotation_matrix);
printMatrix("scale_matrix", scale_matrix);
printMatrix("M", M);
}
glUniformMatrix4fv(
m_location, 1, GL_FALSE,
M); // send the updated model transformation matrix to the GPU
glDrawArrays(
GL_TRIANGLES, 0,
NVERTICES); // draw a triangle between the first vertex and each
// successive vertex pair in the hard-coded model
glFlush(); // ensure that all OpenGL calls have executed before swapping
// buffers
// send the updated model transformation matrix to the GPU
glUniformMatrix4fv(m_location, 1, GL_FALSE, M);
// draw a triangle between the first vertex and each successive vertex pair
// in the hard-coded model
glDrawArrays(GL_TRIANGLES, 0, NVERTICES);
// ensure that all OpenGL calls have executed before swapping buffers
glFlush();
glfwSwapBuffers(window); // swap buffers
glfwWaitEvents(); // wait for a new event before re-drawing
@ -292,21 +326,57 @@ int main(int argc, char **argv) {
// Clean up
glfwDestroyWindow(window);
glfwTerminate(); // destroys any remaining objects, frees resources allocated
// by GLFW
// destroys any remaining objects, frees resources allocated by GLFW
glfwTerminate();
exit(EXIT_SUCCESS);
} // end main
void slow4x4MatrixMultiplyIntoRowOrder(GLfloat *left, GLfloat *right,
GLfloat *result) {
void printMatrix(string name, GLfloat *matrix) {
printf(
"%s = [%f %f %f %f\n"
" %f %f %f %f\n"
" %f %f %f %f\n"
" %f %f %f %f]\n",
name.c_str(), matrix[0], matrix[4], matrix[8], matrix[12], matrix[1],
matrix[5], matrix[9], matrix[13], matrix[2], matrix[6], matrix[10],
matrix[14], matrix[3], matrix[7], matrix[11], matrix[15]
);
}
void transposeMatrix(GLfloat *matrix) {}
void zeroInitGlfloats(GLfloat *arr, uint32_t len) {
for (auto i = 0; i < len; ++i) {
arr[i] = 0.0f;
}
}
void slow4x4MatrixMultiplyIntoColumnOrder(
GLfloat *left, GLfloat *right, GLfloat *result
) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
for (int k = 0; k < 4; ++k) {
const int resultIdx = i * 4 + j;
const GLfloat leftVal = left[i * 4 + k];
const GLfloat rightVal = right[j * 4 + k];
result[i * 4 + j] += leftVal * rightVal;
result[j * 4 + i] += leftVal * rightVal;
}
}
}
}
void slow4x4MatrixMultiplyAllRowOrder(
GLfloat *left, GLfloat *right, GLfloat *result
) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
for (int k = 0; k < 4; ++k) {
const GLfloat leftVal = left[i * 4 + k];
const GLfloat rightVal = right[j * 4 + k];
result[j * 4 + i] += leftVal * rightVal;
}
}
}

View file

@ -4,7 +4,7 @@
#ifndef SHADERSTUFF
#define SHADERSTUFF 1
#define DEBUG_ON 0
// #define DEBUG_ON 0
#define BUFFER_OFFSET(bytes) ((GLvoid*) (bytes))
// Create a NULL-terminated string by reading the provided file

View file

@ -1,60 +0,0 @@
#include "controls.h"
#include "GLFW/glfw3.h"
#include <spdlog/spdlog.h>
void key_callback(GLFWwindow *window, int key, int scancode, int action,
int mods) {
int state = glfwGetKey(window, GLFW_KEY_E);
// checks to see if the escape or q key was pressed
if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
if ((mods & GLFW_MOD_CONTROL) > 0) {
if (action == GLFW_PRESS) {
ctrl_pressed = true;
spdlog::debug("Press ctrl");
} else if (action == GLFW_RELEASE) {
ctrl_pressed = false;
spdlog::debug("Release ctrl");
}
} else {
}
}
void mouse_button_callback(GLFWwindow *window, int button, int action,
int mods) {
glfwGetCursorPos(window, &mouse_x, &mouse_y);
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
}
// Pressed the left mouse button, starting drag
if (ctrl_pressed && button == GLFW_MOUSE_BUTTON_LEFT &&
action == GLFW_PRESS) {
is_dragging = true;
drag_start_x = mouse_x;
drag_start_y = mouse_y;
spdlog::debug("Start drag at ({}, {})!", drag_start_x, drag_start_y);
}
// Check which mouse button triggered the event, e.g. GLFW_MOUSE_BUTTON_LEFT,
// etc. and what the button action was, e.g. GLFW_PRESS, GLFW_RELEASE, etc.
// (Note that ordinary trackpad click = mouse left button)
// Also check if any modifier keys were active at the time of the button
// press, e.g. GLFW_MOD_ALT, etc. Take the appropriate action, which could
// (optionally) also include changing the cursor's appearance
}
void cursor_pos_callback(GLFWwindow *window, double xpos, double ypos) {
// determine the direction of the mouse or cursor motion
// update the current mouse or cursor location
mouse_x = xpos;
mouse_y = ypos;
// (necessary to quantify the amount and direction of cursor motion)
// take the appropriate action
if (is_dragging) {
}
}

View file

@ -1,25 +0,0 @@
#ifndef PERIPHERALS_H_
#define PERIPHERALS_H_
#include "GLFW/glfw3.h"
extern GLdouble mouse_x, mouse_y;
extern GLfloat M[16];
extern bool is_dragging, ctrl_pressed;
extern GLdouble drag_start_x, drag_start_y;
// function that is called whenever a keyboard event occurs; defines how
// keyboard input will be handled
void key_callback(GLFWwindow *window, int key, int scancode, int action,
int mods);
// function that is called whenever a mouse or trackpad button press event
// occurs
void mouse_button_callback(GLFWwindow *window, int button, int action,
int mods);
// function that is called whenever a cursor motion event occurs
void cursor_pos_callback(GLFWwindow *window, double xpos, double ypos);
#endif

View file

@ -1,149 +0,0 @@
#include <spdlog/spdlog.h>
#include <string>
#include <stdio.h>
#include "glad/glad.h"
#include "GLFW/glfw3.h"
// Basic OpenGL program
// Based on example code from: Interactive Computer Graphics: A Top-Down
// Approach with Shader-Based OpenGL (6th Edition), by Ed Angel
#ifndef SHADERSTUFF
#define SHADERSTUFF 1
#define DEBUG_ON 0
#define BUFFER_OFFSET(bytes) ((GLvoid *)(bytes))
// Create a NULL-terminated string by reading the provided file
static char *readShaderSource(const char *shaderFile) {
FILE *fp;
long length, count;
char *buffer;
// struct stat fileinfo;
// open the file containing the text of the shader code
fp = fopen(shaderFile, "rb");
// check for errors in opening the file
if (fp == NULL) {
spdlog::info(":skull: can't open shader source file {}", shaderFile);
return NULL;
}
// determine the file size
fseek(fp, 0, SEEK_END); // move position indicator to the end of the file;
length = ftell(fp); // return the value of the current position
if (DEBUG_ON)
fprintf(stdout, "length in bytes of shader file: %ld\n", length);
// allocate a buffer with the indicated number of bytes, plus one
buffer = new char[length + 1];
// read the appropriate number of bytes from the file
fseek(fp, 0, SEEK_SET); // move position indicator to the start of the file
count = fread(buffer, 1, length, fp); // read all of the bytes
if (DEBUG_ON)
fprintf(stdout, "count of bytes successfully read: %ld\n", count);
// append a NULL character to indicate the end of the string
buffer[count] = '\0'; // because on some systems, count != length
// close the file
fclose(fp);
// return the string
return buffer;
}
// Create a GLSL program object from vertex and fragment shader files
GLuint InitShader(const char *vShaderFileName, const char *fShaderFileName) {
GLuint vertex_shader, fragment_shader;
GLuint program;
// check GLSL version
if (DEBUG_ON)
printf("GLSL version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
// Create shader handlers
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
// Read source code from file
std::string vs_text = readShaderSource(vShaderFileName);
std::string fs_text = readShaderSource(fShaderFileName);
// error check
if (vs_text == "") {
printf("Failed to read from vertex shader file %s\n", vShaderFileName);
exit(1);
} else if (DEBUG_ON) {
printf("read shader code:\n%s\n", vs_text.c_str());
}
if (fs_text == "") {
printf("Failed to read from fragment shader file %s\n", fShaderFileName);
exit(1);
} else if (DEBUG_ON) {
printf("read shader code:\n%s\n", fs_text.c_str());
}
// Set shader source
const char *vv = vs_text.c_str();
const char *ff = fs_text.c_str();
glShaderSource(vertex_shader, 1, &vv, NULL);
glShaderSource(fragment_shader, 1, &ff, NULL);
// Compile shaders
glCompileShader(vertex_shader);
glCompileShader(fragment_shader);
// Check for errors in compiling shaders
GLint compiled;
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
printf("vertex_shader failed to compile\n");
if (DEBUG_ON) {
GLint logMaxSize, logLength;
glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &logMaxSize);
printf("printing error message of %d bytes\n", logMaxSize);
char *logMsg = new char[logMaxSize];
glGetShaderInfoLog(vertex_shader, logMaxSize, &logLength, logMsg);
printf("%d bytes retrieved\n", logLength);
printf("error message: %s\n", logMsg);
delete[] logMsg;
}
exit(1);
}
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
printf("fragment_shader failed to compile\n");
if (DEBUG_ON) {
GLint logMaxSize, logLength;
glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &logMaxSize);
printf("printing error message of %d bytes\n", logMaxSize);
char *logMsg = new char[logMaxSize];
glGetShaderInfoLog(fragment_shader, logMaxSize, &logLength, logMsg);
printf("%d bytes retrieved\n", logLength);
printf("error message: %s\n", logMsg);
delete[] logMsg;
}
exit(1);
}
// Create the program
program = glCreateProgram();
// Attach shaders to program
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
// Link and set program to use
glLinkProgram(program);
glUseProgram(program);
return program;
}
#endif

View file

@ -1,21 +0,0 @@
#include "state.h"
void State::populate_matrix(GLfloat *matrix) {
// 0 1 2 3
// 4 5 6 7
// 8 9 10 11
// 12 13 14 15
matrix[0] = this->x_scale;
matrix[5] = this->y_scale;
matrix[10] = 1.0;
matrix[15] = 1.0;
/*
for (int i = 0; i < 16; i++) {
matrix[i] = (i % 5 == 0);
}
*/
}
void State::start_dragging(pii at) { this->drag_start = at; }

View file

@ -1,33 +0,0 @@
#ifndef STATE_H_
#define STATE_H_
#include <optional>
#include <utility>
using namespace std;
#include "GLFW/glfw3.h"
typedef pair<int, int> pii;
const double X_DELTA = 0.1, Y_DELTA = 0.1;
/// The state of the program
struct State {
pii mouse;
/// Where the dragging started (if it started)
optional<pii> drag_start;
/// Scaling factors
double x_scale = 1.0;
double y_scale = 1.0;
void populate_matrix(GLfloat *matrix);
void start_dragging(pii at);
private:
GLfloat M[16];
};
#endif

View file

@ -1,13 +0,0 @@
#include "util.h"
#include <spdlog/spdlog.h>
optional<string> env(string ident) {
char *result = getenv(ident.c_str());
if (!result)
return {};
return string(result);
}
void error_callback(int error, const char *description) {
spdlog::error("{}", description);
}

View file

@ -1,12 +0,0 @@
#ifndef UTIL_H_
#define UTIL_H_
#include <optional>
#include <string>
using namespace std;
optional<string> env(string ident);
void error_callback(int error, const char *description);
#endif