Compare commits

...

44 Commits
u01 ... main

Author SHA1 Message Date
Luca Conte 63c44f9f7a go back I want to be monkey 2025-05-15 15:33:51 +02:00
Luca Conte dd201108e6 load obj files 2025-05-15 15:28:30 +02:00
Luca Conte 6ccfb7e818 fix projection 2025-04-23 17:20:35 +02:00
Luca Conte cced3c5c83 include string.h for memcpy 2025-04-23 11:59:55 +02:00
Luca Conte daa584842c add mat3 stuff 2025-04-22 22:07:54 +02:00
Luca Conte f695d0bb39 add helper function for building programs 2025-04-22 19:54:52 +02:00
Luca Conte 76d8f1d58f use stderr for logs 2025-04-22 19:54:33 +02:00
Luca Conte 1e2adcfe37 cube tower 2025-04-22 19:40:48 +02:00
Luca Conte 1db1b9378b draw multiple cubes and make every side have a different colour 2025-04-22 19:29:36 +02:00
Luca Conte c5f7407199 maintenance and added vec3Set 2025-04-22 19:29:18 +02:00
Luca Conte b798a9a26e fix for backface culling 2025-04-20 02:29:31 +02:00
Luca Conte 1a84ed5ab6 transparent background because it looks cool 2025-04-20 02:04:25 +02:00
Luca Conte 5046266906 solid cube 2025-04-20 02:04:02 +02:00
Luca Conte 0aeec51093 projection 2025-04-20 01:26:39 +02:00
Luca Conte cbc94e8459 test look at 2025-04-20 00:56:51 +02:00
Luca Conte 5fc371cded redo look-at, test cube with lines 2025-04-20 00:52:53 +02:00
Luca Conte 548b167968 work in progress 2025-04-20 00:30:37 +02:00
Luca Conte e0f3c7d2ff matrix math beginnings 2025-04-02 17:26:16 +02:00
Luca Conte 40979a9a31 enable backface culling 2025-03-31 13:18:54 +02:00
Luca Conte e2771c9f36 fix wrong order import 2025-03-31 13:18:44 +02:00
Luca Conte e054627c25 correct function source 2025-03-11 18:08:46 +01:00
Luca Conte e8b713db85 u03-4 2025-03-11 12:06:49 +01:00
Luca Conte 4cc7e98998 fix error message 2025-03-11 11:29:02 +01:00
Luca Conte d22e2b8e81 seperate color buffer 2025-03-11 10:53:06 +01:00
Luca Conte 9f7ce25ef2 fix math dependency 2025-03-11 10:52:47 +01:00
Luca Conte 94a2fee653 u02 2025-03-10 21:28:54 +01:00
Luca Conte c986407284 additional contact info 2025-03-09 23:15:33 +01:00
Luca Conte dc823025c0 fix typo 2025-03-09 22:50:35 +01:00
Luca Conte 2821655ef2 add macos link 2025-03-09 22:49:30 +01:00
Luca Conte afaea873c5 fix wording 2025-03-09 22:47:27 +01:00
Luca Conte 5a50b11481 free shader buffer when done compiling 2025-03-09 22:44:32 +01:00
Luca Conte ffeb906f7b cross platform make 2025-03-09 22:32:47 +01:00
Luca Conte d39fde8b05 fix makefile 2025-03-09 22:19:46 +01:00
Luca Conte 0166975973 add makefile 2025-03-09 22:14:49 +01:00
Luca Conte d315e30782 remove dollar signs 2025-03-09 22:11:59 +01:00
Luca Conte 7195aced19 more typos 2025-03-09 22:11:20 +01:00
Luca Conte 5c57fde82d fix some typos 2025-03-09 22:09:54 +01:00
Luca Conte 0ed01d8eac add some more info 2025-03-09 22:05:05 +01:00
Luca Conte 56890b78f4 add some helpful links from old moodle course 2025-03-09 21:35:53 +01:00
Luca Conte 6c9c7bae69 fix include 2025-03-09 21:01:53 +01:00
Luca Conte 9c4c081108 add additional instructions 2025-03-09 20:10:25 +01:00
Luca Conte 67efc6ba09 update installation instructions 2025-03-09 18:16:44 +01:00
Luca Conte 9516aeeb6a add fps display 2025-03-06 03:46:55 +01:00
Luca Conte 6b87b05634 update readme install and build instructions 2025-03-06 02:50:15 +01:00
17 changed files with 2053376 additions and 61 deletions

33
Makefile Normal file
View File

@ -0,0 +1,33 @@
# Detect OS
OS := $(shell uname)
GLEW_LIBS := $(shell pkgconf --libs glew)
GLFW_LIBS := $(shell pkgconf --libs glfw3)
# Set libraries for Linux
ifeq ($(OS), Linux)
OPENGL_LIB := -lGL
# Set libraries for Windows (MSYS2)
else
OPENGL_LIB := -lopengl32
endif
# Source files
SRC := src/main.c src/log.c src/shader.c
# Output binary
OUT := cg1
# Compiler
CC := gcc
# Build target
$(OUT): $(SRC)
$(CC) -o $(OUT) $(SRC) $(GLEW_LIBS) $(GLFW_LIBS) $(OPENGL_LIB)
# Clean target
clean:
rm -f $(OUT)
# mark phony targets
.PHONY: clean

217
README.md
View File

@ -1,14 +1,75 @@
# Dependencies Installieren
Dieses Readme soll helfen, die Umgebung für die Computergrafik Übungen einzurichten.
**Merke:** Ich nutze [Meson](https://mesonbuild.com/) statt Make, somit wird `pkgconf` nicht benötigt, und Cross-Platform Entwicklung wird etwas erleichtert. Diese Anleitung ist jedoch auch für Makefile Nutzer geeignet.
Unter Linux ist das Bearbeiten der Aufgaben am einfachsten. Dieses Readme beschreibt aber auch Möglichkeiten, die Aufgaben unter Windows zu bearbeiten, sowie eine Anleitung für [macOS](#macos).
Für Windows gibt es zwei Möglichkeiten:
- [WSL (Windows Subsystem for Linux)](#wsl)
- Nutzt die Linux Umgebung unter Windows
- [Nativ Windows mit MSYS2 bzw MINGW64](#windows-native)
- Nutzt Windows spezifische Tools
Der Entwicklungsprozess ist mit beiden Methoden relativ gleich. Nur im Aufsetzen der Umgebung gibt es Unterschiede.
Die Performance wird mit dem nativen Windows Ansatz besser sein, jedoch sind auch schwächere Geräte meist problemlos in der Lage, die Aufgaben unter WSL zu bearbeiten.
# Ubuntu / WSL
Package Datenbank synchronisieren
```bash
sudo apt-get update
sudo apt-get install libglfw3 libglfw3-dev
sudo apt-get install libglew-dev
sudo apt update
```
Grundlegende Tools wie gcc und make installieren
```
sudo apt install build-essential
```
Meson und Ninja (wird für Meson benötigt) installieren
```
sudo apt install meson ninja-build
```
pkgconf installieren (wird für Make benötigt)
```
sudo apt install pkgconf
```
GLFW installieren
```
sudo apt install libglfw3 libglfw3-dev
```
GLEW installieren
```
sudo apt install libglew-dev
```
# WSL
## WSL Updaten
**Für grafische Anwendungen wird WSL 2 benötigt.**
Ist WSL 2 bereits installiert, können benötigte Pakete installiert werden wie oben beschrieben.
## WSL Installieren
[Installieren von Linux unter Windows mit WSL - Microsoft Learn](https://learn.microsoft.com/de-de/windows/wsl/install)
## WSL zu WSL 2 upgraden
### Virtualisierung Aktivieren
Virtualisierung kann über die Powershell oder im BIOS aktiviert werden und ist notwendig für WSL 2
```
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
```
Anschließend Windows neustarten
### WSL Updaten
```
# aktuelle Version anzeigen
@ -21,10 +82,150 @@ wsl --set-version <distro-name> 2
wsl --update
```
## Virtualisierung Aktivieren
## Hilfreiche Links
(Danke an Rebecca Trautner)
- [Using c++ and WSL in VS Code](https://code.visualstudio.com/docs/cpp/config-wsl)
- [Diagnosing "cannot open display" type issues in WSLg](https://github.com/microsoft/wslg/wiki/Diagnosing-%22cannot-open-display%22-type-issues-with-WSLg)
# Windows Native
## MSYS2 Installation
MSYS2 dient als Entwicklungsumgebung und stellt Tools wie Make und gcc zur Verfügung
[Download und Installationsanleitung](https://www.msys2.org/)
Alle folgenden Schritte sollten im MSYS2 MINGW64 Terminal ausgeführt werden.
## Libraries installieren
Package Datenbank synchronisieren
```
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
pacman -Syu
```
Libraries installieren
```
pacman -S mingw-w64-x86_64-glfw mingw-w64-x86_64-glew
```
## Meson installieren (Empfehlung)
```
pacman -S mingw-w64-x86_64-meson
```
## gcc installieren
```
pacman -S mingw-w64-x86_64-gcc
```
## git installieren (Empfehlung)
```
pacman -S git
```
## mingw64 Pfad zur "Path" Umgebungsvariable hinzufügen
Dieser Schritt ist nur notwendig, wenn das Programm auch ohne MSYS2 gestartet werden soll (also Doppelclick auf die `.exe` Datei)
```
C:\msys64\mingw64\bin
```
- Windows Suche -> "Umgebungsvariablen" eintippen
- -> "Umgebungsvariablen..."
- -> "Path" -> "Bearbeiten" -> "Neu" -> Pfad einfügen
- Neue Umgebungsvariablen werden erst nach Programm Neustart übernommen
Der Code dieses Projekts ist außerdem darauf ausgelegt, dass die Datei aus dem Wurzelverzeichnis des Repositories ausgeführt wird. Die Shader Pfade z.B. sind relativ zum Wurzelverzeichnis. Die Datei muss also aus dem `/build` Verzeichnis in das Wurzelverzeichnis des Repositories verschoben werden. Alternativ, um die `.exe` Datei von einem anderen Verzeichnis auszuführen, kann man Mit Rechtsclick -> "Verknüpfung erstellen" eine Verknüpfung erstellen und anschließend in den Eigenschaften das Start-Verzeichnis ändern:
`C:/Pfad/Zum/Projekt/build` -> `C:/Pfad/Zum/Projekt`
# Kompilieren und Ausführen
Nach den oben beschriebenen Schritten sollte das Projekt kompiliert und ausgeführt werden können.
## Meson
```bash
meson setup build # muss nur beim ersten Mal ausgeführt werden
meson compile -C build # kompiliert das Projekt
# Ausführen
./build/cg1 # linux
./build/cg1.exe # windows
```
## Make
```bash
make # kompiliert das Projekt
# Ausführen
./cg1 # linux
./cg1.exe # windows
```
# MacOS
**Merke:** Da ich selber kein MacOS habe kann ich diese Schritte leider nicht replizieren. Diese Anleitung wurde geschrieben von Paul-Christoph Otte (Danke!), welcher 2024 dieses Modul belegt hat. Entsprechend wird hier *nicht* Meson genutzt.
---
Eine kleine Anleitung für CG1 mit VSCode und einem MacBook M1:
1. Homebrew installieren
2. Mit Homebrew glew, glfw, pkgconf installieren (brew install glew / brew install glfw / brew install pkgconf)
3. unter /usr/local/ einen neuen Ordner "include" erstellen
4. Dort Ordner reinkopieren (habe welche geschickt bekommen, dürfte aber auch gehen, wenn ihr die Ordner von homebrew reinkopiert. Die liegen unter /opt/homebrew/Cellar/)
5. In VSCode den IntelliSenseMode auf gcc ändern (standardmäßig war bei mir clang, bei M1: macos-gcc-arm64)
6. Include-path in vscode hinzufügen: /usr/local/include (In c_cpp_properties.json date)
7. in main.c includes anpassen:
```c
#include <GL/glew.h>
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
```
8. im Makefile:
```makefile
GLEW_LIBS=$(shell pkgconf glew --libs)
GLFW_LIBS=$(shell pkgconf glfw3 --libs)
cg1: main.c
gcc -o cg1 -std=c17 main.c -w $(GLEW_LIBS) $(GLFW_LIBS) -framework OpenGL
```
---
**Weitere Info von Dennis zu macOS:**
unter macOS gibt es noch ein interessantes Problem: Die OpenGL-Version unterstützt offenbar nicht die Ausgabevariable `gl_FragColor` im Fragment-Shader.
Stattdessen müsst ihr selbst eine Ausgabevariable deklarieren:
```glsl
layout (location = 0) out fragColor;
```
Diese kann dann statt `gl_FragColor` verwendet werden.
---
Bei weiteren Fragen, meldet euch gerne bei Dennis oder bei mir per E-Mail oder sprecht uns in einer der Übungen an.
<dennis.allerkamp@hs-hannover.de> | <luca.conte@stud.hs-hannover.de>
Oder noch besser: Stellt die Fragen im Selbsthilfeforum, für den Fall, dass andere das gleiche Problem haben. Dann haben alle was davon. :)

View File

@ -1,9 +1,14 @@
project('cg1', 'c')
cc = meson.get_compiler('c')
m_dep = cc.find_library('m', required : false)
src_files = [
'./src/main.c',
'./src/shader.c',
'./src/log.c'
'./src/log.c',
'./src/matrix-math.c',
'./src/wavefrontobj.c'
]
executable('cg1',
@ -11,6 +16,7 @@ executable('cg1',
dependencies: [
dependency('GL'),
dependency('glew'),
dependency('glfw3')
dependency('glfw3'),
m_dep
]
)

34
obj/cube.obj Normal file
View File

@ -0,0 +1,34 @@
# Blender 4.4.3
# www.blender.org
o Cube
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
vn -0.0000 1.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 1.000000 1.000000
s 0
f 5/1/1 3/2/1 1/3/1
f 3/1/2 8/2/2 4/3/2
f 7/1/3 6/2/3 8/3/3
f 2/1/4 8/2/4 6/3/4
f 1/1/5 4/2/5 2/3/5
f 5/1/6 2/2/6 6/3/6
f 5/1/1 7/4/1 3/2/1
f 3/1/2 7/4/2 8/2/2
f 7/1/3 5/4/3 6/2/3
f 2/1/4 4/4/4 8/2/4
f 1/1/5 3/4/5 4/2/5
f 5/1/6 1/4/6 2/2/6

2066
obj/monkey.obj Normal file

File diff suppressed because it is too large Load Diff

2033859
obj/smooth_monkey.obj Normal file

File diff suppressed because it is too large Load Diff

16109
obj/teapot.obj Normal file

File diff suppressed because it is too large Load Diff

View File

@ -22,10 +22,10 @@ extern unsigned int logLevel;
#define DEBUG_COL "\x1B[90m"
#define NORMAL_COL "\x1B[0m"
#define FATAL(...) if (logLevel >= LOG_LEVEL_FATAL) { printf("| %sFATAL%s | ", FATAL_COL, NORMAL_COL); printf(__VA_ARGS__); printf("\n"); }
#define ERROR(...) if (logLevel >= LOG_LEVEL_ERROR) { printf("| %sERROR%s | ", ERROR_COL, NORMAL_COL); printf(__VA_ARGS__); printf("\n"); }
#define WARN(...) if (logLevel >= LOG_LEVEL_WARN) { printf("| %sWARN%s | ", WARN_COL, NORMAL_COL); printf(__VA_ARGS__); printf("\n"); }
#define INFO(...) if (logLevel >= LOG_LEVEL_INFO) { printf("| %sINFO%s | ", INFO_COL, NORMAL_COL); printf(__VA_ARGS__); printf("\n"); }
#define DEBUG(...) if (logLevel >= LOG_LEVEL_DEBUG) { printf("| %sDEBUG%s | ", DEBUG_COL, NORMAL_COL); printf(__VA_ARGS__); printf("\n"); }
#define FATAL(...) if (logLevel >= LOG_LEVEL_FATAL) { fprintf(stderr, "| %sFATAL%s | ", FATAL_COL, NORMAL_COL); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
#define ERROR(...) if (logLevel >= LOG_LEVEL_ERROR) { fprintf(stderr, "| %sERROR%s | ", ERROR_COL, NORMAL_COL); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
#define WARN(...) if (logLevel >= LOG_LEVEL_WARN) { fprintf(stderr, "| %sWARN%s | ", WARN_COL, NORMAL_COL); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
#define INFO(...) if (logLevel >= LOG_LEVEL_INFO) { fprintf(stderr, "| %sINFO%s | ", INFO_COL, NORMAL_COL); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
#define DEBUG(...) if (logLevel >= LOG_LEVEL_DEBUG) { fprintf(stderr, "| %sDEBUG%s | ", DEBUG_COL, NORMAL_COL); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
#endif // LOG_H

View File

@ -1,42 +1,96 @@
#include <GL/glew.h>
#include <GL/gl.h>
#include <GLFW/glfw3.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "shader.h"
#include "log.h"
#include "src/shader.h"
#include "shader.h"
#include "matrix-math.h"
#include "wavefrontobj.h"
#define STATUS_INTERVAL 0.5
#define PI 3.14159f
GLuint program;
GLuint vertexArrayObject;
GLuint numVertices;
GLuint initialWindowWidth = 800;
GLuint initialWindowHeight = 600;
GLfloat aspect;
mat4 projectionMatrix;
int frameCount = 0;
struct timespec last_time, current_time;
typedef struct ColorRGB {
GLfloat r;
GLfloat g;
GLfloat b;
} ColorRGB;
// Color Conversion Functions from https://gist.github.com/ciembor/1494530
GLfloat hueToRgb(GLfloat p, GLfloat q, GLfloat t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1./6) return p + (q - p) * 6 * t;
if (t < 1./2) return q;
if (t < 2./3) return p + (q - p) * (2./3 - t) * 6;
return p;
}
// Color Conversion Functions from https://gist.github.com/ciembor/1494530
ColorRGB hslToRgb(GLfloat h, GLfloat s, GLfloat l) {
ColorRGB result = {0, 0, 0};
if(0 == s) {
result.r = result.g = result.b = l; // achromatic
} else {
float q = l < 0.5 ? l * (1 + s) : l + s - l * s;
float p = 2 * l - q;
result.r = hueToRgb(p, q, h + 1./3);
result.g = hueToRgb(p, q, h);
result.b = hueToRgb(p, q, h - 1./3);
}
return result;
}
void initialiseStatusDisplay() {
clock_gettime(CLOCK_MONOTONIC, &last_time);
}
void updateStatusDisplay() {
frameCount++;
clock_gettime(CLOCK_MONOTONIC, &current_time);
double elapsed = (current_time.tv_sec - last_time.tv_sec) +
(current_time.tv_nsec - last_time.tv_nsec) / 1e9;
if (elapsed >= STATUS_INTERVAL) {
double fps = frameCount / elapsed;
frameCount = 0;
last_time = current_time;
printf("\rFPS: %.2f ", fps);
fflush(stdout);
}
}
void recalculateProjectionMatrix() {
mat4BuildPerspective(projectionMatrix, 60 * M_PI / 180, aspect, 0.1, 10);
DEBUG("Recalculating Projection Matrix");
}
void init(void) {
INFO("Compiling Shaders...");
// create and compile vertex shader
INFO("Compiling Vertex Shader...");
ShaderCompileResult vertexShader = readAndCompileShaderFromFile("src/shaders/vertex.glsl", GL_VERTEX_SHADER);
if (!vertexShader.success) {
FATAL("Failed to compile Vertex Shader");
exit(1);
}
// create and compile fragment shader
INFO("Compiling Fragment Shader...");
ShaderCompileResult fragmentShader = readAndCompileShaderFromFile("src/shaders/fragment.glsl", GL_FRAGMENT_SHADER);
if (!fragmentShader.success) {
FATAL("Failed to compile Vertex Shader");
exit(1);
}
// create and link shader program
INFO("Linking Shader Program...");
ProgramLinkResult linkResult = linkShaderProgram(vertexShader.shader, fragmentShader.shader);
INFO("Building Programs...");
ProgramLinkResult linkResult = buildShaderProgram("src/shaders/vertex.glsl", "src/shaders/fragment.glsl");
if (!linkResult.success) {
FATAL("Failed to link Program");
exit(1);
@ -47,20 +101,39 @@ void init(void) {
INFO("Shader Program Done.");
// create triangle buffer
GLfloat triangleVertices[] =
{
//X //Y // R //G /B
0.0f, 0.5f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, 1.0f, 0.0f, 1.0f,
0.5f, -0.5f, 1.0f, 1.0f, 0.0f
};
/**
* -0.35 0.35
* | -0.2 0.2 |
* | | | |
*
* 0----1 4----5 --- 0.6
* | | | |
* | | | |
* | 2--------3 | --- 0.1
* | |
* | 9--------8 | --- -0.1
* | | | |
* | | | |
* 11---10 7----6 --- -0.6
*
* 12-----------------13 --- -0.7
* | |
* 15-----------------14 --- -0.9
*
*/
DEBUG("Loading OBJ File");
ParsedObjFile f = readObjFile("obj/smooth_monkey.obj");
numVertices = f.length * sizeof(face) / sizeof(vertex);
DEBUG("Creating vertext buffer");
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, f.length * sizeof(face), f.faces, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
DEBUG("Creating vertex array object");
// create vertex array object
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
@ -69,35 +142,91 @@ void init(void) {
// vertex position data
glVertexAttribPointer(
0, // shader location
2, // number of values to read
3, // number of values to read
GL_FLOAT, // type of value
GL_FALSE, // if values are normalised
5 * sizeof(GLfloat), // stride - distance between vertices
sizeof(vertex), // stride - distance between vertices
0 // start offset
);
glEnableVertexAttribArray(0);
// vertex color data
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat)));
glVertexAttribPointer(
1,
3,
GL_FLOAT,
GL_FALSE,
sizeof(vertex),
(void*)offsetof(vertex, normal)
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClearColor(0.0f, 0.0f, 0.0f, 0.3f);
glViewport(0, 0, initialWindowWidth, initialWindowHeight);
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
glEnable(GL_DEPTH_TEST);
initialiseStatusDisplay();
recalculateProjectionMatrix();
INFO("--- Initialisation done ---");
}
GLfloat currentHue = 0.0f;
void draw(void) {
glClear(GL_COLOR_BUFFER_BIT);
updateStatusDisplay();
// counter for animation
currentHue += 0.005f;
if (currentHue > 1.0) currentHue = 0.0f;
// clear colour and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// select program
glUseProgram(program);
// build view matrix
mat4 viewMatrix;
// mat4Identity(viewMatrix);
vec3 cameraPos = {cos(currentHue * M_PI * 2), 0.0f, sin(currentHue * M_PI * 2)};
vec3 cameraLookAt = {0.0f, 0.2f, 0.0f};
vec3 cameraUp = {0.0f, 1.0f, 0.0f};
mat4BuildLookAt(viewMatrix, cameraPos, cameraLookAt, cameraUp);
GLuint projectionLocation = glGetUniformLocation(program, "uProjection");
glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, projectionMatrix);
// build model Matrix
mat4 modelMatrix;
mat4 modelViewMatrix;
vec3 scale = {0.2f, 0.2f, 0.2f};
mat4Identity(modelMatrix);
mat4Scale(modelMatrix, modelMatrix, scale);
mat4Multiply(modelViewMatrix, viewMatrix, modelMatrix);
glUniformMatrix4fv(glGetUniformLocation(program, "uModelView"), 1, GL_FALSE, modelViewMatrix);
glBindVertexArray(vertexArrayObject);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
aspect = (float)width / height;
recalculateProjectionMatrix();
}
int main(int argc, char const *argv[])
@ -119,7 +248,11 @@ int main(int argc, char const *argv[])
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow *window = glfwCreateWindow(initialWindowWidth, initialWindowHeight, "CG1", NULL, NULL);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER , GLFW_TRUE);
GLFWwindow* window = glfwCreateWindow(initialWindowWidth, initialWindowHeight, "CG1", NULL, NULL);
aspect = (float)initialWindowWidth / initialWindowHeight;
if (!window) {
FATAL("Failed to open window");
glfwTerminate();

518
src/matrix-math.c Normal file
View File

@ -0,0 +1,518 @@
#include "matrix-math.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
/**
* overwrites a 4x4 matrix with the identity matrix
*/
void mat4Identity(mat4 mat) {
for (int i = 0; i < 16; i++) {
mat[i] = (i % 4 == i / 4) ? 1 : 0;
}
}
/**
* copies a mat4 from src to dst
*/
void mat4Copy(mat4 src, mat4 dst) {
for (int i = 0; i < 16; i++) {
dst[i] = src[i];
}
}
/**
* sets all the values in a mat4 to zero
*/
void mat4Empty(mat4 mat) {
for (int i = 0; i < 16; i++) {
mat[i] = 0;
}
}
/**
* mutliplies A with B and stores the result in result
*/
void mat4Multiply(mat4 result, mat4 A, mat4 B) {
// if result is one of the arguments, modify copy instead of result directly
if (result == A || result == B) {
mat4 tempResult;
mat4Multiply(tempResult, A, B);
mat4Copy(tempResult, result);
return;
}
// loops over cells of the result matrix
for (int i = 0; i < 16; i++) {
int col = i / 4;
int row = i % 4;
// pointer to the current cell
GLfloat* curr = &(result[i]);
// initialise current cell with 0
*curr = 0;
// loop over the row of A and column of B
// continuously adding the multiplication of the two values to the result cell
for (int j = 0; j < 4; j++) {
*curr += A[row + j * 4] * B[j + col * 4];
}
}
}
/**
* prints a mat4 to the screen
*/
void mat4Print(mat4 m) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
printf("%.2f ", m[j * 4 + i]);
}
printf("\n");
}
}
/**
* translates by the vector v
*/
void mat4Translate(mat4 out, mat4 in, vec3 v) {
mat4 T;
mat4Identity(T);
T[12] = v[0];
T[13] = v[1];
T[14] = v[2];
mat4Multiply(out, T, in);
}
/**
* scales by the vector v
*/
void mat4Scale(mat4 out, mat4 in, vec3 v) {
mat4 T;
mat4Identity(T);
T[0] = v[0];
T[5] = v[1];
T[10] = v[2];
mat4Multiply(out, T, in);
}
/**
* rotates around the X axis by the angle a (in radians)
*/
void mat4RotateX(mat4 out, mat4 in, GLfloat a) {
mat4 T;
mat4Identity(T);
T[5] = cos(a);
T[6] = sin(a);
T[9] = -sin(a);
T[10] = cos(a);
mat4Multiply(out, T, in);
}
/**
* rotates around the Y axis by the angle a (in radians)
*/
void mat4RotateY(mat4 out, mat4 in, GLfloat a) {
mat4 T;
mat4Identity(T);
T[0] = cos(a);
T[2] = -sin(a);
T[8] = sin(a);
T[10] = cos(a);
mat4Multiply(out, T, in);
}
/**
* rotates around the Z axis by the angle a (in radians)
*/
void mat4RotateZ(mat4 out, mat4 in, GLfloat a) {
mat4 T;
mat4Identity(T);
T[0] = cos(a);
T[1] = sin(a);
T[4] = -sin(a);
T[5] = cos(a);
mat4Multiply(out, T, in);
}
/**
* builds a look-at matrix, overwriting out
* eye is the position of the camera
* look is the position of the target to be looked at
* up is the up vector
*/
void mat4BuildLookAt(mat4 out, vec3 eye, vec3 look, vec3 up) {
vec3 n;
vec3 u;
vec3 v;
vec3 t;
vec3Subtract(n, eye, look);
vec3CrossProduct(u, up, n);
vec3CrossProduct(v, n, u);
vec3Normalise(n, n);
vec3Normalise(u, u);
vec3Normalise(v, v);
t[0] = - vec3DotProduct(u, eye);
t[1] = - vec3DotProduct(v, eye);
t[2] = - vec3DotProduct(n, eye);
out[0] = u[0]; out[4] = u[1]; out[8] = u[2]; out[12] = t[0];
out[1] = v[0]; out[5] = v[1]; out[9] = v[2]; out[13] = t[1];
out[2] = n[0]; out[6] = n[1]; out[10] = n[2]; out[14] = t[2];
out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 1;
}
/**
* builds a projection matrix, overwriting out
* r, l, t, b are the right, left, top and bottom of the frustum
* n and f are the distance of the near and far planes from the camera
*/
void mat4BuildProjection(mat4 out, GLfloat r, GLfloat l, GLfloat t, GLfloat b, GLfloat n, GLfloat f) {
mat4Identity(out);
out[0] = 2.0f / (r - l);
out[5] = 2.0f / (t - b);
out[8] = 1.0f / n * (r + l) / (r - l);
out[9] = 1.0f / n * (t + b) / (t - b);
out[10] = -1.0f / n * (f + n) / (f - n);
out[11] = -1.0f / n;
out[14] = - 2.0f * f / (f - n);
out[15] = 0.0f;
}
/**
* builds a perspective projection matrix, overwriting out
* fovy is the field of view in the y direction
* aspect is the aspect ratio
* n and f are the distance of the near and far planes from the camera
*/
void mat4BuildPerspective(mat4 out, GLfloat fovy, GLfloat aspect, GLfloat n, GLfloat f) {
GLfloat t = n * tan(0.5f * fovy);
GLfloat b = -t;
GLfloat r = aspect * t;
GLfloat l = -r;
mat4BuildProjection(out, r, l, t, b, n, f);
}
/**
* linearly interpolates between a and b, storing the result in out
*/
void mat4Interpolate(mat4 out, mat4 a, mat4 b, GLfloat f) {
for (int i = 0; i < 16; i++) {
out[i] = (1 - f) * a[i] + f * b[i];
}
}
void mat4From3(mat4 out, mat3 in) {
mat4Identity(out);
memcpy(&out[0], &in[0], sizeof(GLfloat) * 3);
memcpy(&out[4], &in[3], sizeof(GLfloat) * 3);
memcpy(&out[8], &in[6], sizeof(GLfloat) * 3);
}
/**
* https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix
*/
void mat4Inverse(mat4 out, mat4 m) {
GLfloat inv[16], det;
int i;
inv[0] = m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10];
inv[4] = -m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10];
inv[8] = m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9];
inv[12] = -m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9];
inv[1] = -m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10];
inv[5] = m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10];
inv[9] = -m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9];
inv[13] = m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9];
inv[2] = m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6];
inv[6] = -m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6];
inv[10] = m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5];
inv[14] = -m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5];
inv[3] = -m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6];
inv[7] = m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6];
inv[11] = -m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5];
inv[15] = m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5];
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
if (det == 0) {
mat4Copy(m, out); // singular matrix, can't invert
return;
}
det = 1.0 / det;
for (i = 0; i < 16; i++)
out[i] = inv[i] * det;
return;
}
/**
* subtracts b from a, storing the result in out
*/
void vec3Subtract(vec3 out, vec3 a, vec3 b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
}
/**
* calculates the cross product of a and b, storing the result in out
*/
void vec3CrossProduct(vec3 out, vec3 a, vec3 b) {
vec3 result;
result[0] = a[1] * b[2] - a[2] * b[1];
result[1] = a[2] * b[0] - a[0] * b[2];
result[2] = a[0] * b[1] - a[1] * b[0];
out[0] = result[0];
out[1] = result[1];
out[2] = result[2];
}
/**
* normalizes in storing the result in out
*/
void vec3Normalise(vec3 out, vec3 in) {
GLfloat length = vec3Length(in);
out[0] = in[0] / length;
out[1] = in[1] / length;
out[2] = in[2] / length;
}
/**
* returns the length of the vector in
*/
GLfloat vec3Length(vec3 in) {
return sqrt(in[0] * in[0] + in[1] * in[1] + in[2] * in[2]);
}
/**
* returns the dot product of the vectors a and b
*/
GLfloat vec3DotProduct(vec3 a, vec3 b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
/**
* sets the values of out to x, y and z
*/
void vec3Set(vec3 out, GLfloat x, GLfloat y, GLfloat z) {
out[0] = x;
out[1] = y;
out[2] = z;
}
void vec3Multiply(vec3 out, vec3 in, GLfloat x) {
out[0] = in[0] * x;
out[1] = in[1] * x;
out[2] = in[2] * x;
}
void vec2Subtract(vec2 out, vec2 a, vec2 b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
}
void mat3Copy(mat3 src, mat3 dst) {
for (int i = 0; i < 9; i++) {
dst[i] = src[i];
}
}
void mat3From4(mat3 out, mat4 in) {
memcpy(&out[0], &in[0], sizeof(GLfloat) * 3);
memcpy(&out[3], &in[4], sizeof(GLfloat) * 3);
memcpy(&out[6], &in[8], sizeof(GLfloat) * 3);
}
void mat3Transpose(mat3 out, mat3 in) {
mat3 result;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
result[i * 3 + j] = in[j * 3 + i];
}
}
mat3Copy(result, out);
}
void mat3Minor(mat3 out, mat3 in) {
mat3 result;
// TODO: check if this is correct
result[0] = in[4] * in[8] - in[5] * in[7];
result[1] = in[3] * in[8] - in[5] * in[6];
result[2] = in[3] * in[7] - in[4] * in[6];
result[3] = in[1] * in[8] - in[2] * in[7];
result[4] = in[0] * in[8] - in[2] * in[6];
result[5] = in[0] * in[7] - in[1] * in[6];
result[6] = in[1] * in[5] - in[2] * in[4];
result[7] = in[0] * in[5] - in[2] * in[3];
result[8] = in[0] * in[4] - in[1] * in[3];
mat3Copy(result, out);
}
void mat3Cofactor(mat3 out, mat3 in) {
mat3Minor(out, in);
out[1] *= -1;
out[3] *= -1;
out[5] *= -1;
out[7] *= -1;
}
void mat3Adjoint(mat3 out, mat3 in) {
mat3Cofactor(out, in);
mat3Transpose(out, in);
}
void mat3MultiplyScalar(mat3 out, mat3 in, GLfloat x) {
for (int i = 0; i < 9; i++) {
out[i] = in[i] * x;
}
}
GLfloat mat3Determinant(mat3 M) {
return
+ M[0] * M[4] * M[8]
+ M[3] * M[7] * M[2]
+ M[6] * M[1] * M[5]
- M[2] * M[4] * M[6]
- M[5] * M[7] * M[0]
- M[8] * M[1] * M[3]
;
}
void mat3Inverse(mat3 out, mat3 in) {
mat3 result;
mat3Adjoint(result, in);
mat3MultiplyScalar(result, result, 1 / mat3Determinant(in));
mat3Copy(result, out);
}

55
src/matrix-math.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef MATRIX_MATH_H
#define MATRIX_MATH_H
#include <GL/gl.h>
/**
* !!! ALL matrices are in column major
*/
typedef GLfloat vec4[4];
typedef GLfloat vec3[3];
typedef GLfloat vec2[2];
typedef GLfloat mat4[16];
typedef GLfloat mat3[9];
extern void mat4Identity(mat4 mat);
extern void mat4Copy(mat4 src, mat4 dst);
extern void mat4Empty(mat4 mat);
extern void mat4Multiply(mat4 result, mat4 A, mat4 B);
extern void mat4Print(mat4 m);
extern void mat4Translate(mat4 out, mat4 in, vec3 v);
extern void mat4Scale(mat4 out, mat4 in, vec3 v);
extern void mat4RotateX(mat4 out, mat4 in, GLfloat a);
extern void mat4RotateY(mat4 out, mat4 in, GLfloat a);
extern void mat4RotateZ(mat4 out, mat4 in, GLfloat a);
extern void mat4BuildLookAt(mat4 out, vec3 eye, vec3 center, vec3 up);
extern void mat4BuildProjection(mat4 out, GLfloat r, GLfloat l, GLfloat t, GLfloat b, GLfloat n, GLfloat f);
extern void mat4BuildPerspective(mat4 out, GLfloat fovy, GLfloat aspect, GLfloat n, GLfloat f);
extern void mat4Interpolate(mat4 out, mat4 a, mat4 b, GLfloat f);
extern void mat4From3(mat4 out, mat3 in);
extern void mat4Inverse(mat4 m, mat4 out);
extern void vec3Subtract(vec3 out, vec3 a, vec3 b);
extern void vec3CrossProduct(vec3 out, vec3 a, vec3 b);
extern void vec3Normalise(vec3 out, vec3 in);
extern GLfloat vec3Length(vec3 in);
extern GLfloat vec3DotProduct(vec3 a, vec3 b);
extern void vec3Set(vec3 out, GLfloat x, GLfloat y, GLfloat z);
extern void vec3Multiply(vec3 out, vec3 in, GLfloat x);
extern void vec2Subtract(vec2 out, vec2 a, vec2 b);
extern void mat3Copy(mat3 src, mat3 dst);
extern void mat3Inverse(mat3 out, mat3 in);
extern GLfloat mat3Determinant(mat3 m);
extern void mat3MultiplyScalar(mat3 out, mat3 in, GLfloat x);
extern void mat3Adjoint(mat3 out, mat3 in);
extern void mat3Cofactor(mat3 out, mat3 in);
extern void mat3Minor(mat3 out, mat3 in);
extern void mat3Transpose(mat3 out, mat3 in);
extern void mat3From4(mat3 out, mat4 in);
#endif

View File

@ -73,6 +73,8 @@ ShaderCompileResult readAndCompileShaderFromFile(const char* filepath, GLenum sh
result.success = true;
}
free((void*)shaderSource);
return result; // Return the ShaderCompileResult struct
}
@ -114,4 +116,27 @@ ProgramLinkResult linkShaderProgram(GLuint vertexShader, GLuint fragmentShader)
result.success = true;
return result;
}
}
ProgramLinkResult buildShaderProgram(const char* vertexShaderPath, const char* fragmentShaderPath) {
ProgramLinkResult result = { .success = false, .program = 0 };
ShaderCompileResult vertexShader = readAndCompileShaderFromFile(vertexShaderPath, GL_VERTEX_SHADER);
if (!vertexShader.success) {
FATAL("Failed to compile vertex shader");
return result;
}
ShaderCompileResult fragmentShader = readAndCompileShaderFromFile(fragmentShaderPath, GL_FRAGMENT_SHADER);
if (!fragmentShader.success) {
FATAL("Failed to compile fragment shader");
return result;
}
result = linkShaderProgram(vertexShader.shader, fragmentShader.shader);
glDeleteShader(vertexShader.shader);
glDeleteShader(fragmentShader.shader);
return result;
}

View File

@ -17,5 +17,6 @@ typedef struct {
extern const char* readFileToMemory(const char* filepath);
extern ShaderCompileResult readAndCompileShaderFromFile(const char* filepath, GLenum shaderType);
extern ProgramLinkResult linkShaderProgram(GLuint vertexShader, GLuint fragmentShader);
extern ProgramLinkResult buildShaderProgram(const char* vertexShaderPath, const char* fragmentShaderPath);
#endif // SHADER_H

View File

@ -1,5 +1,6 @@
#version 330 core
in vec3 vertexColor;
in vec3 vNormal;
void main() {
gl_FragColor = vec4(vertexColor, 1.0);
gl_FragColor = vec4(vNormal * 0.5 + vec3(0.5), 1.0);
}

View File

@ -1,10 +1,12 @@
#version 330 core
layout (location = 0) in vec2 aPosition;
layout (location = 1) in vec3 aColor;
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aNormal;
uniform mat4 uModelView;
uniform mat4 uProjection;
out vec3 vertexColor;
out vec3 vNormal;
void main() {
vertexColor = aColor;
gl_Position = vec4(aPosition, 0.0, 1.0);
vNormal = aNormal;
gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);
}

242
src/wavefrontobj.c Normal file
View File

@ -0,0 +1,242 @@
#include <GL/glew.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wavefrontobj.h"
#define OBJ_LINE_BUFFER_SIZE 256
/**
*
* ADJUSTMENT NEEDED FOR
* - Face Definitions other than vertex/texture/normal
* - Vertex positions including w
* - Any faces using vertices yet to be defined
* (File is read top to bottom. A face using a vertex
* defined underneath it in the file will not work)
*
*/
void storeFace(
face* f,
vec3 v1, vec2 vt1, vec3 vn1,
vec3 v2, vec2 vt2, vec3 vn2,
vec3 v3, vec2 vt3, vec3 vn3
) {
memcpy(&f->v1.position, v1, sizeof(vec3));
memcpy(&f->v2.position, v2, sizeof(vec3));
memcpy(&f->v3.position, v3, sizeof(vec3));
memcpy(&f->v1.normal, vn1, sizeof(vec3));
memcpy(&f->v2.normal, vn2, sizeof(vec3));
memcpy(&f->v3.normal, vn3, sizeof(vec3));
memcpy(&f->v1.texture, vt1, sizeof(vec2));
memcpy(&f->v2.texture, vt2, sizeof(vec2));
memcpy(&f->v3.texture, vt3, sizeof(vec2));
}
// void storeTB(face* f,
// vec3 v1, vec2 vt1, vec3 vn1,
// vec3 v2, vec2 vt2, vec3 vn2,
// vec3 v3, vec2 vt3, vec3 vn3
// ) {
// // https://www.opengl-tutorial.org/intermediate-tutorials/tutorial-13-normal-mapping/
// vec3 deltaPos1;
// vec3 deltaPos2;
// vec3Subtract(deltaPos1, v2, v1);
// vec3Subtract(deltaPos1, v3, v1);
// vec2 deltaTex1;
// vec2 deltaTex2;
// vec2Subtract(deltaTex1, vt2, vt1);
// vec2Subtract(deltaTex2, vt3, vt1);
// GLfloat r = 1.0f / (deltaTex1[0] * deltaTex2[1] - deltaTex1[1] * deltaTex2[0]);
// vec3Multiply(deltaPos1, deltaPos1, deltaTex2[1]);
// vec3Multiply(deltaPos2, deltaPos2, deltaTex1[1]);
// vec3 tangent;
// vec3Subtract(tangent, deltaPos1, deltaPos2);
// vec3Multiply(tangent, tangent, r);
// memcpy(&f->v1.tangent, &tangent, sizeof(vec3));
// memcpy(&f->v2.tangent, &tangent, sizeof(vec3));
// memcpy(&f->v3.tangent, &tangent, sizeof(vec3));
// }
ParsedObjFile readObjFile(char* path) {
ParsedObjFile parsedFile;
FILE* fp = fopen(path, "r");
if (fp == NULL) {
fprintf(stderr, "File could not be opened: %s", path);
parsedFile.faces = NULL;
parsedFile.length = 0;
}
uint numVertices = 0;
uint numVertexNormals = 0;
uint numFaces = 0;
uint numTextureCoords = 0;
char buf[OBJ_LINE_BUFFER_SIZE];
while (fgets(buf, OBJ_LINE_BUFFER_SIZE, fp)) {
if (buf[0] == 'v') {
if (buf[1] == ' ') {
numVertices++;
} else if (buf[1] == 't') {
numTextureCoords++;
} else if (buf[1] == 'n') {
numVertexNormals++;
}
}
if (buf[0] == 'f') {
int numSpaces = 0;
for (int i = 0; i < strlen(buf); i++) {
if (buf[i] == ' ') {
numSpaces++;
}
}
numFaces += numSpaces - 2;
}
}
// printf("Vertices: %d\nFaces: %d\nNormals:%d\nTextures:%d\n", numVertices, numFaces, numVertexNormals, numTextureCoords);
vec3* vertices = (vec3*) malloc(sizeof(vec3) * numVertices);
vec3* normals = (vec3*) malloc(sizeof(vec3) * numVertexNormals);
vec2* textures = (vec2*) malloc(sizeof(vec2) * numTextureCoords);
face* faces = (face*) malloc(sizeof(face) * numFaces);
parsedFile.faces = faces;
parsedFile.length = numFaces;
rewind(fp);
uint curVertex = 0;
uint curNormal = 0;
uint curFace = 0;
uint curTexture = 0;
while (fgets(buf, OBJ_LINE_BUFFER_SIZE, fp)) {
if (buf[0] == 'v') {
if (buf[1] == ' ') {
sscanf(buf,
"v %f %f %f",
&vertices[curVertex][0],
&vertices[curVertex][1],
&vertices[curVertex][2]
);
curVertex++;
} else if (buf[1] == 't') {
int readValues = sscanf(buf,
"vt %f %f",
&textures[curTexture][0],
&textures[curTexture][1]
);
if (readValues != 2) {
textures[curTexture][1] = 0;
}
curTexture++;
} else if (buf[1] == 'n') {
sscanf(buf,
"vn %f %f %f",
&normals[curNormal][0],
&normals[curNormal][1],
&normals[curNormal][2]
);
curNormal++;
}
}
if (buf[0] == 'f') {
int v1, v2, v3;
int vt1, vt2, vt3;
int vn1, vn2, vn3;
sscanf(buf,
"f %d/%d/%d %d/%d/%d %d/%d/%d",
&v1, &vt1, &vn1,
&v2, &vt2, &vn2,
&v3, &vt3, &vn3
);
storeFace(&faces[curFace],
vertices[v1 - 1], textures[vt1 - 1], normals[vn1 - 1],
vertices[v2 - 1], textures[vt2 - 1], normals[vn2 - 1],
vertices[v3 - 1], textures[vt3 - 1], normals[vn3 - 1]
);
// storeTB(&faces[curFace],
// vertices[v1 - 1], textures[vt1 - 1], normals[vn1 - 1],
// vertices[v2 - 1], textures[vt2 - 1], normals[vn2 - 1],
// vertices[v3 - 1], textures[vt3 - 1], normals[vn3 - 1]
// );
curFace++;
int numSpaces = 0;
for (int i = 0; i < strlen(buf); i++) {
if (buf[i] == ' ') {
numSpaces++;
}
}
if (numSpaces == 4) {
// storeTB(&faces[curFace],
// vertices[v1 - 1], textures[vt1 - 1], normals[vn1 - 1],
// vertices[v2 - 1], textures[vt2 - 1], normals[vn2 - 1],
// vertices[v3 - 1], textures[vt3 - 1], normals[vn3 - 1]
// );
sscanf(buf,
"f %d/%d/%d %*d/%*d/%*d %d/%d/%d %d/%d/%d",
&v1, &vt1, &vn1,
&v2, &vt2, &vn2,
&v3, &vt3, &vn3
);
storeFace(&faces[curFace],
vertices[v1 - 1], textures[vt1 - 1], normals[vn1 - 1],
vertices[v2 - 1], textures[vt2 - 1], normals[vn2 - 1],
vertices[v3 - 1], textures[vt3 - 1], normals[vn3 - 1]
);
curFace++;
}
// TODO: textures
}
}
free(vertices);
free(normals);
fclose(fp);
return parsedFile;
}
void clearParsedFile(ParsedObjFile file) {
free(file.faces);
}

30
src/wavefrontobj.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef WAVEFRONTOBJ_H
#define WAVEFRONTOBJ_H
#include <GL/glew.h>
#include "matrix-math.h"
typedef struct {
vec3 position;
vec3 normal;
vec2 texture;
// vec3 tangent;
} vertex;
typedef struct {
vertex v1;
vertex v2;
vertex v3;
} face;
typedef struct {
face* faces;
GLuint length;
} ParsedObjFile;
extern ParsedObjFile readObjFile(char* path);
extern void clearParsedFile(ParsedObjFile file);
#endif