Import simplified code.

Code imported from my seminary work.
In this simplified version it rotates a triangle
using OpenGL libraries.

Crashes upon exit.
This commit is contained in:
Marcel Plch 2023-10-25 15:02:23 +02:00
parent 87f41525f6
commit 9c5b5d7471
Signed by: dormouse
GPG key ID: FCCCBD4835BFEABF
13 changed files with 582 additions and 0 deletions

44
CMakeLists.txt Normal file
View file

@ -0,0 +1,44 @@
# CMake entry point
cmake_minimum_required (VERSION 3.27.1)
project(OpenGL_Analog_Clock C)
cmake_policy(SET CMP0072 NEW)
find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)
find_package(glfw3 REQUIRED)
include_directories(
include/
.
)
set(ALL_LIBS
${OPENGL_LIBRARY}
glfw
GLEW
m
)
set(CMAKE_C_FLAGS "-O0 -ggdb -Wall")
add_definitions(
-DTW_STATIC
-DTW_NO_LIB_PRAGMA
-DTW_NO_DIRECT3D
-DGLEW_STATIC
-D_CRT_SECURE_NO_WARNINGS
)
add_executable(
cx
src/main.c
src/cx.c
src/tensor.c
src/model.c
src/shader.c
)
target_link_libraries(
cx
${ALL_LIBS}
)

30
include/cx.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef CX_H
#define CX_H
// Include standard headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
// Include GLEW
#include <GL/glew.h>
// Include GLFW
#include <GLFW/glfw3.h>
// Include project headers
#include <tensor.h>
#include <model.h>
#include <tensor.h>
#include <shader.h>
// Declare functions
int cx_glinit(GLFWwindow **);
int cx_glrun(GLFWwindow *);
#endif

12
include/model.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef MODEL_LOADER_H
#define MODEL_LOADER_H
typedef struct _model {
GLfloat *object;
size_t bufsize;
} Model;
Model * model_load(const char *);
#endif

7
include/shader.h Normal file
View file

@ -0,0 +1,7 @@
#ifndef SHADER_H
#define SHADER_H
int LoadShaders(GLuint *, const char *, const char *);
#endif

12
include/tensor.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef MATRIX_H
#define MATRIX_H
GLfloat *matrix_new(void);
GLfloat *matrix_multip(GLfloat *, GLfloat *);
GLfloat *matrix_transform(GLfloat *, int,
GLfloat *);
#endif

View file

@ -0,0 +1,12 @@
#version 330 core
in float colorF;
out vec3 color;
void main() {
if (colorF == 0)
color = vec3(1, 1, 1);
else
color = vec3(0, 0, 0);
}

View file

@ -0,0 +1,15 @@
#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec4 position;
out float colorF;
void main() {
if (position.z <= 0.0)
colorF = 0;
else
colorF = 1;
gl_Position = position;
}

174
src/cx.c Normal file
View file

@ -0,0 +1,174 @@
#include <cx.h>
int cx_glinit(GLFWwindow **window) {
// 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, "OpenGL Clock", 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);
return 0;
}
int cx_glrun(GLFWwindow *window) {
GLuint VertexArrayID;
GLuint programID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Create and compile our GLSL program from the shaders
if (LoadShaders(&programID,
"../shaders/SimpleVertexShader.vertexshader",
"../shaders/SimpleFragmentShader.fragmentshader")) {
fprintf(stderr, "Could not load shaders.\n");
return -1;
}
Model *model;
model = model_load("../triangle.obj");
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, model->bufsize*4*sizeof(GLfloat), model->object, GL_STATIC_DRAW);
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
GLfloat *matrix;
GLfloat *temp = matrix_new();
matrix = temp;
time_t t = time(NULL);
temp = matrix_new();
temp[0] = cos(M_PI*2/60*(t%60));
temp[4] = -sin(M_PI*2/60*(t%60));
temp[1] = sin(M_PI*2/60*(t%60));
temp[5] = cos(M_PI*2/60*(t%60));
matrix = temp;
t /= 60;
GLfloat *projection = matrix_new();
GLfloat *buffer;
projection[14] = -1.0f;
buffer = matrix_new();
buffer[0] = (GLfloat)9/16;
temp = matrix_multip(projection, buffer);
free(buffer);
free(projection);
projection = temp;
temp = malloc(model->bufsize * 4 * sizeof(GLfloat));
buffer = malloc(model->bufsize * 4 * sizeof(GLfloat));
memcpy(temp, model->object, model->bufsize * 4 * sizeof(GLfloat));
GLfloat *orig;
orig = malloc(model->bufsize * 4 * sizeof(GLfloat));
memcpy(orig, model->object, model->bufsize * 4 * sizeof(GLfloat));
do {
// Clear the screen. It's not mentioned before Tutorial 02,
// but it can cause flickering, so it's there nonetheless.
glClear(GL_COLOR_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
time_t t = time(NULL);
GLfloat *temp_mat;
temp_mat = matrix_new();
temp_mat[0] = cos(M_PI*2/60*(t%60));
temp_mat[4] = -sin(M_PI*2/60*(t%60));
temp_mat[1] = sin(M_PI*2/60*(t%60));
temp_mat[5] = cos(M_PI*2/60*(t%60));
matrix = temp_mat;
t /= 60;
for (int i = 2; i < 5; i++) {
GLfloat *slice;
slice = matrix_transform(orig, model->bufsize, matrix);
memcpy(temp, slice, model->bufsize* 4 * sizeof(GLfloat));
free(slice);
}
free(buffer);
buffer = matrix_transform(temp, model->bufsize, projection);
memcpy(model->object, buffer, model->bufsize * 4 * sizeof(GLfloat));
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, model->bufsize * 4 * sizeof(GLfloat), model->object, GL_STATIC_DRAW);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
4, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
NULL // array buffer offset
);
// Draw!
glDrawArrays(GL_TRIANGLES, 0, model->bufsize); // 3 indices starting at 0 -> 1 triangle
glDisableVertexAttribArray(0);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
// Check if the ESC key was pressed or the window was closed
usleep(1000000/60);
} while(glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
!glfwWindowShouldClose(window));
// Close OpenGL window and terminate GLFW
free(matrix);
glfwTerminate();
return 0;
}

18
src/main.c Normal file
View file

@ -0,0 +1,18 @@
// Include standard headers
#include <stdio.h>
#include <stdlib.h>
// Include project headers
#include <cx.h>
int
main(void) {
GLFWwindow *window;
if (cx_glinit(&window)) {
return -1;
}
return cx_glrun(window);
}

70
src/model.c Normal file
View file

@ -0,0 +1,70 @@
#include <cx.h>
Model *
model_new(size_t size) {
Model *model = calloc(1, sizeof(Model));
model->object = calloc((size ? size : 1) *4 , sizeof(GLfloat));
model->bufsize = size;
return model;
}
void
model_free(Model *self) {
free(self->object);
free(self);
}
Model *
model_load(const char *path) {
Model *model;
GLfloat *vertices;
int *faces;
size_t vertcount, facecount;
char type, check;
FILE *f;
f = fopen(path, "r");
vertices = malloc(3 * sizeof(GLfloat));
faces = malloc(3*sizeof(int *));
type = 0;
vertcount = 0;
facecount = 0;
do {
check = fscanf(f, "%c", &type);
if (check == EOF) {
break;
}
else if (type == 'v') {
vertices = realloc(vertices, (vertcount+1)*3*sizeof(GLfloat));
check = fscanf(f, "%f %f %f\n", &(vertices[vertcount*3]),
&(vertices[vertcount*3+1]),
&(vertices[vertcount*3+2]));
vertcount++;
}
else if (type == 'f') {
faces = realloc(faces, (facecount+1)*3*sizeof(GLfloat));
check = fscanf(f, "%d %d %d\n", &(faces[facecount*3]),
&(faces[facecount*3+1]),
&(faces[facecount*3+2]));
facecount++;
}
else {
check = fscanf(f, "%*[^\n]\n");
continue;
}
} while(check != EOF);
model = model_new(facecount*3);
for (int i = 0; i < facecount; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
model->object[i*12+j*4+k] = vertices[(faces[i*3+j]-1)*3+k];
}
model->object[i*12+j*4+3] = 1;
}
model->bufsize = facecount*3;
}
return model;
}

118
src/shader.c Normal file
View file

@ -0,0 +1,118 @@
#include "cx.h"
static int
load_code(const char *filepath, char **code) {
FILE *file;
int cursor;
int c;
file = fopen(filepath, "r");
if (file == NULL) {
fprintf(stderr, "Could not open %s.\n", filepath);
return 1;
}
*code = malloc(256 * sizeof(char));
if (code == NULL) {
fprintf(stderr, "Out of memory");
return 1;
}
cursor = 0;
while ((c = fgetc(file)) != EOF) {
(*code)[cursor] = c;
cursor++;
}
(*code)[cursor] = '\0';
return 0;
}
static int
compile_code(const char *filepath, const char *code,
GLuint ShaderID, GLint *Result) {
int InfoLogLength;
// Compile Shader
printf("Compiling shader : %s\n", filepath);
glShaderSource(ShaderID, 1, (const char **)&code, NULL);
glCompileShader(ShaderID);
// Check Shader
glGetShaderiv(ShaderID, GL_COMPILE_STATUS, Result);
glGetShaderiv(ShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
char *ShaderErrorMessage = malloc(InfoLogLength+1);
glGetShaderInfoLog(ShaderID, InfoLogLength, NULL, ShaderErrorMessage);
printf("%s\n", ShaderErrorMessage);
free(ShaderErrorMessage);
return -1;
}
return 0;
}
int
LoadShaders(GLuint *programID, const char *vertex_file_path,
const char *fragment_file_path) {
int retval = -1;
char *vertex_code = NULL;
char *fragment_code = NULL;
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Read the Vertex Shader code from the file
if (load_code(vertex_file_path, (char **)&vertex_code)) {
goto end;
}
// Read the Fragment Shader code from the file
if (load_code(fragment_file_path, (char **)&fragment_code)) {
goto end;
}
GLint Result = GL_FALSE;
// Compile Vertex Shader
if (compile_code(vertex_file_path, vertex_code, VertexShaderID, &Result)) {
goto end;
}
// Compile Fragment Shader
if (compile_code(fragment_file_path, fragment_code, FragmentShaderID, &Result)) {
goto end;
}
// Link the program
printf("Linking program\n");
*programID = glCreateProgram();
glAttachShader(*programID, VertexShaderID);
glAttachShader(*programID, FragmentShaderID);
glLinkProgram(*programID);
GLint InfoLogLength;
// Check the program
glGetProgramiv(*programID, GL_LINK_STATUS, &Result);
glGetProgramiv(*programID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
char *ProgramErrorMessage = malloc(InfoLogLength+1);
glGetProgramInfoLog(*programID, InfoLogLength, NULL, ProgramErrorMessage);
printf("%s\n", ProgramErrorMessage);
}
glDetachShader(*programID, VertexShaderID);
glDetachShader(*programID, FragmentShaderID);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
// If code got here, it means it was successful
retval = 0;
end:
free(vertex_code);
free(fragment_code);
return retval;
}

63
src/tensor.c Normal file
View file

@ -0,0 +1,63 @@
#include "cx.h"
GLfloat *
matrix_new() {
GLfloat *mat;
mat = calloc(16, sizeof(GLfloat));
for (int i = 0; i < 4; i++) {
mat[i*4+i] = 1;
}
return mat;
}
GLfloat *
matrix_multip(GLfloat *mat1, GLfloat *mat2) {
GLfloat *result;
GLfloat dot_prod;
result = matrix_new();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
dot_prod = 0;
for (int k = 0; k < 4; k++) {
dot_prod += mat1[i*4+k] * mat2[j+k*4];
}
result[j+i*4] = dot_prod;
}
}
return result;
}
GLfloat *
matrix_transform(GLfloat *vects, int vectcount,
GLfloat *mat) {
GLfloat dot_prod;
GLfloat *result;
result = calloc(vectcount*4, sizeof(GLfloat));
for (int k = 0; k < vectcount; k++) {
for (int j = 0; j < 4; j++) {
dot_prod = 0;
for (int i = 0; i < 4; i++) {
dot_prod += vects[k*4+i] * mat[i+j*4];
}
result[j+k*4] = dot_prod;
}
if (result[k*4+3] != 0.0f) {
GLfloat div = result[k*4+3];
for (int i = 0; i < 4; i++) {
result[k*4+i] /= div;
}
}
}
return result;
}

7
triangle.obj Normal file
View file

@ -0,0 +1,7 @@
o Triangle.001
v -0.250000 -0.200000 0.000000
v 0.250000 -0.200000 0.000000
v 0.000000 0.400000 0.000000
s off
f 1 2 3