2023-10-25 13:02:23 +00:00
|
|
|
#include <cx.h>
|
|
|
|
|
|
|
|
int cx_glinit(GLFWwindow **window) {
|
2023-12-13 09:56:21 +00:00
|
|
|
// Initialise GLFW
|
|
|
|
if(!glfwInit()) {
|
|
|
|
fprintf(stderr, "Failed to initialize GLFW\n");
|
|
|
|
getchar();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
glfwWindowHint(GLFW_SAMPLES, 4);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
|
|
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
|
|
|
|
|
|
// Open a window and create its OpenGL context
|
|
|
|
*window = glfwCreateWindow(1280, 720, "CONTROL-X", NULL, NULL);
|
|
|
|
if (*window == NULL) {
|
|
|
|
fprintf(stderr, "Failed to open GLFW window.\n");
|
|
|
|
glfwTerminate();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
glfwMakeContextCurrent(*window);
|
|
|
|
|
|
|
|
// Initialize GLEW
|
|
|
|
if (glewInit() != GLEW_OK) {
|
|
|
|
fprintf(stderr, "Failed to initialize GLEW\n");
|
|
|
|
glfwTerminate();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure we can capture the escape key being pressed below
|
|
|
|
glfwSetInputMode(*window, GLFW_STICKY_KEYS, GL_TRUE);
|
|
|
|
|
|
|
|
// Dark grey background
|
|
|
|
glClearColor(0.15f, 0.15f, 0.15f, 0.0f);
|
2023-10-25 13:02:23 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cx_glrun(GLFWwindow *window) {
|
2023-12-13 09:56:21 +00:00
|
|
|
GLuint VertexArrayID;
|
|
|
|
GLuint programID;
|
2023-10-25 13:02:23 +00:00
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
glGenVertexArrays(1, &VertexArrayID);
|
|
|
|
glBindVertexArray(VertexArrayID);
|
2023-10-25 13:02:23 +00:00
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
// Create and compile our GLSL program from the shaders
|
2023-10-25 13:02:23 +00:00
|
|
|
if (LoadShaders(&programID,
|
|
|
|
"../shaders/SimpleVertexShader.vertexshader",
|
|
|
|
"../shaders/SimpleFragmentShader.fragmentshader")) {
|
|
|
|
fprintf(stderr, "Could not load shaders.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
|
|
|
|
// Load model to render from file
|
2023-10-25 13:02:23 +00:00
|
|
|
Model *model;
|
|
|
|
model = model_load("../triangle.obj");
|
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
// Allocate the render buffer
|
|
|
|
// GL uses this to feed the GPU
|
|
|
|
GLfloat *render_buffer;
|
|
|
|
render_buffer = malloc(model->bufsize * 4 * sizeof(GLfloat));
|
|
|
|
memcpy(render_buffer, model->object, model->bufsize * 4 * sizeof(GLfloat));
|
|
|
|
|
|
|
|
// Bind the render buffer to OpenGL
|
|
|
|
GLuint vertexbuffer;
|
|
|
|
glGenBuffers(1, &vertexbuffer);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, model->bufsize*4*sizeof(GLfloat), render_buffer, GL_STATIC_DRAW);
|
|
|
|
|
|
|
|
// 1rst attribute buffer : vertices
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
|
|
|
|
glVertexAttribPointer(
|
|
|
|
0, // attribute 0 in the pipeline
|
|
|
|
4, // size
|
|
|
|
GL_FLOAT, // type
|
|
|
|
GL_FALSE, // normalized?
|
|
|
|
0, // stride
|
|
|
|
NULL // array buffer offset
|
|
|
|
);
|
|
|
|
|
|
|
|
// Remainder from cursor experiments, might be useful later
|
2023-10-25 13:02:23 +00:00
|
|
|
double xpos, ypos;
|
|
|
|
glfwGetCursorPos(window, &xpos, &ypos);
|
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
GLfloat *rotation_matrix = matrix_new();
|
|
|
|
GLfloat *projection_matrix = matrix_new();
|
2023-10-25 13:02:23 +00:00
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
// Temporary storage of transformation results
|
|
|
|
GLfloat *temp_buffer;
|
|
|
|
GLfloat *projected_buffer;
|
2023-10-25 13:02:23 +00:00
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
projection_matrix[14] = -1.0f;
|
|
|
|
projection_matrix[0] = (GLfloat)9/16; // Widescreen FOV
|
2023-10-25 13:02:23 +00:00
|
|
|
|
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
do {
|
|
|
|
// Clear the screen. It's not mentioned before Tutorial 02,
|
2023-10-25 13:02:23 +00:00
|
|
|
// but it can cause flickering, so it's there nonetheless.
|
2023-12-13 09:56:21 +00:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
2023-10-25 13:02:23 +00:00
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
// Use our shader
|
|
|
|
glUseProgram(programID);
|
2023-10-25 13:02:23 +00:00
|
|
|
time_t t = time(NULL);
|
|
|
|
|
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
rotation_matrix[0] = cos(M_PI*2/60*(t%60));
|
|
|
|
rotation_matrix[4] = -sin(M_PI*2/60*(t%60));
|
|
|
|
rotation_matrix[1] = sin(M_PI*2/60*(t%60));
|
|
|
|
rotation_matrix[5] = cos(M_PI*2/60*(t%60));
|
2023-10-25 13:02:23 +00:00
|
|
|
|
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
// BANANA, ROH-TAH-TEH
|
|
|
|
temp_buffer = matrix_transform(model->object, model->bufsize, rotation_matrix);
|
2023-10-25 13:02:23 +00:00
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
// Guess I'm just projecting.
|
|
|
|
projected_buffer = matrix_transform(temp_buffer, model->bufsize, projection_matrix);
|
2023-10-25 13:02:23 +00:00
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
memcpy(render_buffer, projected_buffer, model->bufsize * 4 * sizeof(GLfloat));
|
|
|
|
free(temp_buffer);
|
|
|
|
free(projected_buffer);
|
2023-10-25 13:02:23 +00:00
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
glBufferData(GL_ARRAY_BUFFER, model->bufsize*4*sizeof(GLfloat), render_buffer, GL_STATIC_DRAW);
|
2023-10-25 13:02:23 +00:00
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
// 1rst attribute buffer : vertices
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
|
|
|
|
glVertexAttribPointer(
|
|
|
|
0, // attribute 0 in the pipeline
|
|
|
|
4, // size
|
|
|
|
GL_FLOAT, // type
|
|
|
|
GL_FALSE, // normalized?
|
|
|
|
0, // stride
|
|
|
|
NULL // array buffer offset
|
|
|
|
);
|
2023-10-25 13:02:23 +00:00
|
|
|
|
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
// Draw!
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, model->bufsize); // 3 indices starting at 0 -> 1 triangle
|
2023-10-25 13:02:23 +00:00
|
|
|
|
2023-12-13 09:56:21 +00:00
|
|
|
glDisableVertexAttribArray(0);
|
|
|
|
|
|
|
|
// Swap buffers
|
|
|
|
glfwSwapBuffers(window);
|
|
|
|
glfwPollEvents();
|
2023-10-25 13:02:23 +00:00
|
|
|
|
|
|
|
// Check if the ESC key was pressed or the window was closed
|
|
|
|
usleep(1000000/60);
|
2023-12-13 09:56:21 +00:00
|
|
|
} while(glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
|
|
|
|
!glfwWindowShouldClose(window));
|
|
|
|
|
|
|
|
// Close OpenGL window and terminate GLFW
|
|
|
|
glfwTerminate();
|
|
|
|
free(rotation_matrix);
|
|
|
|
free(projection_matrix);
|
|
|
|
model_free(model);
|
|
|
|
free(render_buffer);
|
2023-10-25 13:02:23 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|