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:
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;
}