opengl

Sample code from LearnOpenGL.com
Log | Files | Refs

commit 5e1ed285640869a5036e294645c88031282f1d40
parent 308b64833daaec450691c9e37f33f58b9786eb7a
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Tue, 27 Jun 2023 14:40:48 +0900

add err handling, some vector functions

Diffstat:
MMakefile | 22++++++++++++++--------
Aerr.c | 13+++++++++++++
Aerr.h | 3+++
Mglm.c | 166++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mglm.h | 47+++++++++++++++++++++++++++++------------------
Aglm_test.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmain.c | 42+++++++++++++++++++++++++++---------------
Mmain.h | 2--
Mshader.c | 3+--
Mshaders/fragment.sl | 4++--
Mshaders/vertex.sl | 9+++------
11 files changed, 313 insertions(+), 62 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,6 +1,7 @@ CC = tcc -SRC = main.c shader.c glm.c src/glad.c -HDR = main.h glm.h +SRC = main.c shader.c glm.c err.c src/glad.c +TSRC = glm.c glm_test.c err.c +HDR = main.h glm.h err.h OUT = main INCS = -I./include @@ -11,15 +12,20 @@ LDFLAGS = -lglfw -lGL -lX11 -lpthread -lXrandr -lXi -ldl -lm all: $(SRC) $(HDR) $(CC) -o $(OUT) $(CFLAGS) $(INCS) $(LDFLAGS) $(SRC) - -gcc: - make "CC=gcc" - -clang: - make "CC=clang" run: all ./$(OUT) + +test: $(TSRC) + $(CC) -o test $(CFLAGS) $(INCS) $(LDFLAGS) $(TSRC) + ./test + rm -f test clean: rm -f main + +gcc: + make "CC=gcc" + +clang: + make "CC=clang" diff --git a/err.c b/err.c @@ -0,0 +1,13 @@ +#include <stdarg.h> +#include <stdio.h> + +char errstr[512]; + +int +errorf(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vsnprintf(errstr, sizeof(errstr), fmt, ap); + va_end(ap); +} diff --git a/err.h b/err.h @@ -0,0 +1,3 @@ +extern char errstr[512]; + +int errorf(char *fmt, ...); diff --git a/glm.c b/glm.c @@ -1,22 +1,170 @@ +#include <assert.h> +#include <math.h> +#include <stdio.h> #include <stdlib.h> #include "glm.h" +#include "err.h" -vec3 -*makeVec3(float *vals) +char * +vecStr(char *s, vec *v) { - return (vec3 *)vals; + int cur = 0; + cur += sprintf(s, "["); + for (int i = 0; i < v->size; i++) { + cur += sprintf(&s[cur], "%f%s", v->data[i], + i == v->size-1 ? "]" : ", "); + } + s[cur] = '\0'; + return s; } -vec4 -*makeVec4(float *vals) +vec * +vecMake(float *data, int size) { - return (vec4 *)vals; + vec *v = (vec *)malloc(sizeof(vec)); + v->data = (float *)malloc(sizeof(float)*size); + for (int i = 0; i < size; i++) { + v->data[i] = data[i]; + } + v->size = size; + return v; +} + +void +vecFree(vec *v) +{ + free(v->data); + free(v); +} + +int +vecEq(vec *v, vec *w) +{ + if (v->size != w->size) + return 0; + for (int i = 0; i < v->size; i++) + if (v->data[i] != w->data[i]) + return 0; + return 1; +} + +vec * +vecAdd(vec *v, const vec *w) +{ + if (v->size != w->size) { + assert(!"vector sizes don't match"); + } + for (int i = 0; i < v->size; i++) { + v->data[i] += w->data[i]; + } + return v; +} + +vec * +vecSub(vec *v, const vec *w) +{ + if (v->size != w->size) { + assert(!"vector sizes don't match"); + } + for (int i = 0; i < v->size; i++) { + v->data[i] -= w->data[i]; + } + return v; +} + +float +vecDot(const vec *v, const vec *w) +{ + if (v->size != w->size) { + assert(!"vector sizes don't match"); + } + float ret = 0; + for (int i = 0; i < v->size; i++) { + ret += v->data[i] * w->data[i]; + } + return ret; +} + +vec * +vecCross(vec *v, const vec *w) +{ + if (v->size != 3 || w->size != 3) { + assert(!"vector sizes must be 3"); + } + float p[3]; + p[0] = v->data[1]*w->data[2] - v->data[2]*w->data[1]; + p[1] = v->data[2]*w->data[0] - v->data[0]*w->data[2]; + p[2] = v->data[0]*w->data[1] - v->data[1]*w->data[0]; + for (int i = 0; i < 3; i++) + v->data[i] = p[i]; + return v; +} + +mat * +matMake(float *data, int size) +{ + mat *m = (mat *)malloc(sizeof(mat)); + m->data = (float *)malloc(sizeof(float)*size*size); + for (int i = 0; i < size*size; i++) { + m->data[i] = data[i]; + } + m->size = size; + return m; +} + +void +matFree(mat *m) +{ + free(m->data); + free(m); +} + +float +*matDataPtr(mat *m) +{ + return m->data; +} + +mat * +matDot(mat *m, const mat *n) // m_ij = m->data[i + m->size*j] +{ + if (m->size != n->size) { + assert(!"mat sizes don't match"); + } + float *data = (float *)malloc(sizeof(float)*m->size*m->size); + for (int i = 0; i < m->size; i++) { + for (int j = 0; j < m->size; j++) { + data[i+m->size*j] = 0; + for (int k = 0; k < m->size; k++) { + data[i+m->size*j] += m->data[i+m->size*k] * + n->data[k+m->size*j]; + } + } + } + free(m->data); + m->data = data; + return m; +} + + +mat * +translate(mat *m, const vec *v) +{ + return NULL; } -mat4 -*makeMat4(float *vals) +// TODO: implementation in progress. use arbitrary axis. +mat * +rotate(mat *m, float rad, vec *axis) { - return (mat4 *)vals; + mat *rot = matMake((float[]){ // column major... + cos(rad), sin(rad), 0, 0, + -sin(rad), cos(rad), 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1}, 4); + matDot(m, rot); + matFree(rot); + return m; } diff --git a/glm.h b/glm.h @@ -1,21 +1,33 @@ -typedef float vec3[3]; +typedef struct vec { + float *data; + int size; +} vec; -vec3 *makeVec3(float *); +// mat is square matrix of which size is size by size. +typedef struct mat { + float *data; // column major + int size; +} mat; -typedef float vec4[4]; +// VecStr() set s the string representation of v and returns the same char*. +char *vecStr(char *s, vec *v); +// VecMake() allocates a vec and copy the data to its data. +// Caller is responsible to free the vec by calling vecFree(). +vec *vecMake(float *data, int size); +// VecFree() frees v. +void vecFree(vec* v); +// VecEq() tests equality of v and w. +int vecEq(vec *v, vec *w); +// VecAdd() adds w to v. w is unchanged. Returns the address of v or NULL if +// an error occurs. +vec *vecAdd(vec *v, const vec *w); +vec *vecSub(vec *v, const vec *w); +float vecDot(const vec *v, const vec *w); +vec *vecCross(vec *v, const vec *w); -vec4 *makeVec4(float *); -void freeVec4(vec4 *); +mat *matMake(float *data, int size); +void matFree(mat *m); +float *matDataPtr(mat *m); - -typedef float mat4[16]; -// column major: -// | 0 4 8 12 | -// | 1 5 9 13 | -// | 2 6 10 14 | -// | 3 7 11 15 | - -mat4 *makeMat4(float *); -void freeMat4(mat4 *); - -mat4 *translate(mat4 *, vec3 *); -\ No newline at end of file +mat *translate(mat *m, const vec *v); +mat *rotate(mat *m, float rad, vec *axis); diff --git a/glm_test.c b/glm_test.c @@ -0,0 +1,64 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "glm.h" +#include "err.h" + +int vecAddTest(); +int vecEqTest(); + +int +main(void) +{ + if (vecEqTest() < 0) + fprintf(stderr, "vecEqTest: %s\n", errstr); + if (vecAddTest() < 0) + fprintf(stderr, "vecAddTest: %s\n", errstr); + return 0; +} + +int +vecEqTest() +{ + float data0[] = {1.0, 2.0, 3.0, 4.0}; + float data1[] = {1.0, 2.0, 3.0, 4.0}; + vec *v = vecMake(data0, 4); + vec *w = vecMake(data1, 4); + char s[2][256]; + if (!vecEq(v, w)) { + errorf("%s != %s", vecStr(s[0], v), vecStr(s[1], w)); + return -1; + } + vecFree(v); + v = vecMake(data0, 3); + if (vecEq(v, w)) { + errorf("%s != %s", vecStr(s[0], v), vecStr(s[1], w)); + return -1; + } + return 0; +} + +int +vecAddTest() +{ + float data0[] = {1.0, 2.0, 3.0}; + float data1[] = {2.0, 4.0, 6.0}; + vec *v0 = vecMake(data0, 3); + vec *v = vecMake(data0, 3); + vec *w = vecMake(data1, 3); + vecAdd(v, w); + for (int i = 0; i < 3; i++) { + data0[i] += data1[i]; + } + vec *u = vecMake(data0, 3); + char s[4][256]; + if (vecEq(v, u)) + return 0; + else { + errorf("%s + %s = %s, want: %s", + vecStr(s[0], v0), vecStr(s[1], w), + vecStr(s[2], v), vecStr(s[3], u)); + return -1; + } +} diff --git a/main.c b/main.c @@ -8,6 +8,7 @@ #include "main.h" #include "glm.h" +#include "err.h" #define STB_IMAGE_IMPLEMENTATION #define STBI_NO_SIMD // TODO: confirm this workaround. #include "stb_image.h" @@ -37,8 +38,12 @@ processInput(GLFWwindow *window) spacePressing = 0; } else if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) { alpha += 0.01; + if (alpha > 1.0) + alpha = 1.0; } else if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) { alpha -= 0.01; + if (alpha < 0) + alpha = 0; } } @@ -48,17 +53,22 @@ main(void) float theta = 0; float delta = 0.01; float vertices[] = { - // positions, colors, texture coords - 0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, - -0.5, 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, - -0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, - 0.5, -0.5, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, + // positions, texture coords + 0.5, 0.5, 0.0, 1.0, 1.0, + -0.5, 0.5, 0.0, 0.0, 1.0, + -0.5, -0.5, 0.0, 0.0, 0.0, + 0.5, -0.5, 0.0, 1.0, 0.0, }; unsigned int indices[] = { 0, 1, 2, 0, 2, 3, - }; - + }; + mat *trans = matMake((float[]){1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0,}, 4); + vec *axis = vecMake((float[]){0.0, 0.0, 1.0}, 3); + // initialize glfw glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); @@ -99,15 +109,12 @@ main(void) glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)(3*sizeof(float))); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), - (void *)(6*sizeof(float))); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); @@ -141,6 +148,7 @@ main(void) glGenerateMipmap(GL_TEXTURE_2D); stbi_image_free(data); } + while (!glfwWindowShouldClose(window)) { processInput(window); @@ -148,17 +156,21 @@ main(void) glClear(GL_COLOR_BUFFER_BIT); if (rotating) { - theta += delta; + rotate(trans, delta, axis); } - ShaderSetFloat(shader, "theta", theta); + ShaderSetFloat(shader, "alpha", alpha); glUniform1i(glGetUniformLocation(shader->ID, "texture0"), 0); glUniform1i(glGetUniformLocation(shader->ID, "texture1"), 1); - ShaderSetFloat(shader, "alpha", alpha); + unsigned int tloc = glGetUniformLocation(shader->ID, "transform"); + glUniformMatrix4fv(tloc, 1, GL_FALSE, matDataPtr(trans)); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glfwPollEvents(); glfwSwapBuffers(window); } + + matFree(trans); + vecFree(axis); glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); diff --git a/main.h b/main.h @@ -1,5 +1,3 @@ -extern char errstr[512]; - typedef struct Shader { unsigned int ID; } Shader; diff --git a/shader.c b/shader.c @@ -9,8 +9,7 @@ #include <GLFW/glfw3.h> #include "main.h" - -char errstr[512]; +#include "err.h" char * readfile(const char *file) diff --git a/shaders/fragment.sl b/shaders/fragment.sl @@ -1,13 +1,13 @@ #version 330 core in vec2 texCoord; +out vec4 FragColor; uniform sampler2D texture0; uniform sampler2D texture1; uniform float alpha; -out vec4 FragColor; void main() { FragColor = mix(texture(texture0, texCoord), - texture(texture1, 2*(vec2(1, 1)-texCoord)), alpha); + texture(texture1, vec2(1, 1)-texCoord), alpha); } diff --git a/shaders/vertex.sl b/shaders/vertex.sl @@ -1,15 +1,12 @@ #version 330 core layout (location = 0) in vec3 aPos; -layout (location = 1) in vec3 aColor; -layout (location = 2) in vec2 aTexCoord; +layout (location = 1) in vec2 aTexCoord; out vec2 texCoord; -uniform float theta; +uniform mat4 transform; void main() { - vec2 pxy = aPos.xy; - mat2 rot = mat2(cos(theta), -sin(theta), sin(theta), cos(theta)); - gl_Position = vec4(pxy*rot, aPos.z, 1.0); + gl_Position = transform * vec4(aPos, 1.0); texCoord = aTexCoord; }