Compare commits

...

11 commits

Author SHA1 Message Date
8b276f089f
Add a very important end of line. 2025-01-03 15:05:35 +01:00
Marcel Plch
43549c8cab Functioning clock 2018-04-27 17:07:10 +02:00
Marcel Plch
d3ff1ed2ad Implement .obj loader 2018-04-23 00:42:08 +02:00
Marcel Plch
677177cd49 Implement matrices 2018-04-16 00:40:13 +02:00
Marcel Plch
b9ed7c486e moving triangle, yay 2018-02-17 15:35:02 +01:00
Marcel Plch
42936f5565 create src directory 2018-02-17 15:35:01 +01:00
Marcel Plch
4f80b4157c mouse interaction 2018-02-17 01:33:45 +01:00
Marcel Plch
a21091cad6 triangle render (and correct line endings in code) 2018-02-16 23:48:04 +01:00
Marcel Plch
d8e4055ae3 Code refactoring from C++ to C 2018-02-07 23:18:21 +01:00
Marcel Plch
a3ae4702da Triangle render 2018-02-07 14:22:24 +01:00
Marcel Plch
28aef55a81 Code style improvements 2018-02-07 00:02:56 +01:00
15 changed files with 2710 additions and 99 deletions

View file

@ -1,8 +1,16 @@
# CMake entry point
cmake_minimum_required (VERSION 3.0)
project (OpenGL_Analog_Clock)
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}
@ -10,6 +18,8 @@ set(ALL_LIBS
GLEW
)
set(CMAKE_C_FLAGS "-O0 -ggdb -lm")
add_definitions(
-DTW_STATIC
-DTW_NO_LIB_PRAGMA
@ -18,10 +28,16 @@ add_definitions(
-D_CRT_SECURE_NO_WARNINGS
)
add_executable(clock
main.c
add_executable(
clock
src/main.c
src/clock.c
src/shader.c
src/matrix.c
src/model.c
)
target_link_libraries(clock
target_link_libraries(
clock
${ALL_LIBS}
)

32
Include/clock.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef CLOCK_H
#define CLOCK_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 <model.h>
#include <matrix.h>
#include <shader.h>
// Define macros
#define xfree(p) if (p) free((void *)p)
// Declare functions
int clock_init(GLFWwindow **);
int clock_run(GLFWwindow *);
#endif

12
Include/matrix.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

18
Include/model.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef MODEL_LOADER_H
#define MODEL_LOADER_H
typedef struct _entity {
size_t offset;
size_t size;
} Entity;
typedef struct _model {
GLfloat *object;
size_t bufsize;
Entity *entities[5];
} 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

1057
clock.obj Normal file

File diff suppressed because it is too large Load diff

1009
cube.obj Normal file

File diff suppressed because it is too large Load diff

72
main.c
View file

@ -1,72 +0,0 @@
// Include standard headers
#include <stdio.h>
#include <stdlib.h>
// Include GLEW
#include <GL/glew.h>
// Include GLFW
#include <GLFW/glfw3.h>
GLFWwindow* window;
int main( void )
{
// 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( 1024, 768, "Tutorial 01", NULL, NULL);
if( window == NULL ){
fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
getchar();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
getchar();
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);
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 );
// Draw nothing, see you in tutorial 2 !
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0 );
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}

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,14 @@
#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;
}

201
src/clock.c Normal file
View file

@ -0,0 +1,201 @@
#include <clock.h>
int
clock_init(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
clock_run(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;
}
static GLfloat g_vertex_buffer_data[] = {
-0.3f, -0.3f, 0.0f, 1.0f,
0.3f, -0.3f, 0.0f, 1.0f,
0.0f, 0.3f, 0.0f, 1.0f
};
Model *model;
model = model_load("../clock.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 **matrices = malloc(4 * sizeof(GLfloat *));
GLfloat *temp = matrix_new();
//temp[0] = cos(M_PI*2/60);
//temp[1] = -sin(M_PI*2/60);
//temp[4] = sin(M_PI*2/60);
//temp[5] = cos(M_PI*2/60);
matrices[0] = temp;
time_t t = time(NULL);
for (int i = 1; i < 4; i++) {
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));
matrices[i] = 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);
//glfwGetCursorPos(window, &xpos, &ypos);
//g_vertex_buffer_data[0] = (float)xpos / 1280 * 2 - 1 - 0.15;
//g_vertex_buffer_data[1] = 2 - (float)ypos / 720 * 2 - 1 - 0.15;
//g_vertex_buffer_data[3] = (float)xpos / 1280 * 2 - 1 + 0.15;
//g_vertex_buffer_data[4] = 2 - (float)ypos / 720 * 2 - 1 - 0.15;
//g_vertex_buffer_data[6] = (float)xpos / 1280 * 2 - 1;
//g_vertex_buffer_data[7] = 2 - (float)ypos / 720 * 2 - 1 + 0.15;
time_t t = time(NULL);
for (int i = 1; i < 4; i++) {
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));
matrices[i] = temp_mat;
t /= 60;
}
for (int i = 2; i < 5; i++) {
GLfloat *slice;
slice = matrix_transform(&(orig[model->entities[i]->offset]), model->entities[i]->size, matrices[i-1]);
memcpy(&(temp[model->entities[i]->offset]), slice, model->entities[i]->size* 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
for (int i = 0; i < 4; i++) {
free(matrices[i]);
}
free(matrices);
glfwTerminate();
return 0;
}

14
src/main.c Normal file
View file

@ -0,0 +1,14 @@
// Include APIs
#include "clock.h"
int
main(int argc, char *argv[]) {
GLFWwindow *window;
if (clock_init(&window)) {
return -1;
}
return clock_run(window);
}

66
src/matrix.c Normal file
View file

@ -0,0 +1,66 @@
#include "clock.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 *helper = NULL;
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;
}

107
src/model.c Normal file
View file

@ -0,0 +1,107 @@
#include <clock.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;
for (int i = 0; i < 5; i++) {
model->entities[i] = calloc(1, sizeof(Entity));
}
}
void
model_free(Model *self) {
free(self->object);
free(self);
for (int i = 0; i < 5; i++) {
free(self->entities[i]);
}
}
Model *
model_load(const char *path) {
Model *model;
GLfloat *vertices;
int **faces;
size_t vertcount, facecount[5] = {0};
char type, check, *buffer;
FILE *f;
GLfloat colorset[3];
size_t entity_read;
f = fopen(path, "r");
buffer = malloc(255);
vertices = malloc(3 * sizeof(GLfloat));
faces = malloc(5*sizeof(int *));
for (int i = 0; i < 5; i++) {
faces[i] = malloc(3 * sizeof(int));
}
type = 0;
vertcount = 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[entity_read] = realloc(faces[entity_read], (facecount[entity_read]+1)*3*sizeof(GLfloat));
check = fscanf(f, "%d %d %d\n", &(faces[entity_read][facecount[entity_read]*3]),
&(faces[entity_read][facecount[entity_read]*3+1]),
&(faces[entity_read][facecount[entity_read]*3+2]));
facecount[entity_read]++;
}
else if (type == 'o') {
check = fscanf(f, "%s\n", buffer);
if (strstr(buffer, "Sphere")) {
entity_read = 0;
}
else if (strstr(buffer, "Text")) {
entity_read = 1;
}
else if (strstr(buffer, "Sec")) {
entity_read = 2;
}
else if (strstr(buffer, "Min")) {
entity_read = 3;
}
else if (strstr(buffer, "Hrs")) {
entity_read = 4;
}
}
else {
check = fscanf(f, "%*[^\n]\n", NULL);
continue;
}
} while(check != EOF);
int total_facecount = 0;
for (int i = 0; i < 5; i++) {
total_facecount += facecount[i];
}
model = model_new(total_facecount*3);
int offset = 0;
for (int ent = 0; ent < 5; ent++) {
model->entities[ent]->offset = offset;
for (int i = 0; i < facecount[ent]; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
model->object[i*12+j*4+k+offset] = vertices[(faces[ent][i*3+j]-1)*3+k];
}
model->object[i*12+j*4+3+offset] = 1;
}
}
offset += facecount[ent]*4*3;
model->entities[ent]->size = facecount[ent]*3;
}
return model;
}

118
src/shader.c Normal file
View file

@ -0,0 +1,118 @@
#include "clock.h"
#include "shader.h"
static int
load_code(const char *filepath, char **code) {
FILE *file;
int cursor;
char 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", filepath);
return 1;
}
cursor = 0;
while ((c = fgetc(file)) != EOF) {
(*code)[cursor] = c;
cursor++;
}
return 0;
}
static int
compile_code(const char *filepath, const char *code,
GLuint ShaderID, GLuint *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;
const char *vertex_code = NULL;
const 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);
GLuint 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:
xfree(vertex_code);
xfree(fragment_code);
return retval;
}