diff options
| author | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2023-12-30 12:19:17 +0100 | 
|---|---|---|
| committer | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2023-12-30 12:20:30 +0100 | 
| commit | b0adc3b8710bab4e67a28a001836b9d3d51cb3cc (patch) | |
| tree | 55825526b5361cd91165b05520f37146863e7fb4 | |
| parent | 7dbb36c6f46012f8234f1449270b28edbe148b1d (diff) | |
| download | vlkn-b0adc3b8710bab4e67a28a001836b9d3d51cb3cc.tar.xz | |
lots of things aaaaaaaa
Signed-off-by: Anna (navi) Figueiredo Gomes <navi@vlhl.dev>
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | linmath.h | 605 | ||||
| -rw-r--r-- | main.c | 761 | ||||
| -rw-r--r-- | pfp.png | bin | 0 -> 455024 bytes | |||
| -rw-r--r-- | shader.frag | 4 | ||||
| -rw-r--r-- | shader.vert | 26 | 
6 files changed, 1339 insertions, 61 deletions
| @@ -1,8 +1,8 @@  CFLAGS = -O2 -g -LDFLAGS != pkg-config --libs vulkan sdl2 +LDFLAGS != pkg-config --libs vulkan sdl2 libpng  vulkan: main.c vert.spv frag.spv -	gcc $(CFLAGS) -o vk main.c $(LDFLAGS) +	gcc $(CFLAGS) -o vk main.c $(LDFLAGS) -lm  %.spv: shader.%  	glslc $^ -o $@ diff --git a/linmath.h b/linmath.h new file mode 100644 index 0000000..dd329e1 --- /dev/null +++ b/linmath.h @@ -0,0 +1,605 @@ +#ifndef LINMATH_H +#define LINMATH_H + +#include <string.h> +#include <math.h> +#include <string.h> + +#ifdef LINMATH_NO_INLINE +#define LINMATH_H_FUNC static +#else +#define LINMATH_H_FUNC static inline +#endif + +#define LINMATH_H_DEFINE_VEC(n) \ +typedef float vec##n[n]; \ +LINMATH_H_FUNC void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \ +{ \ +	int i; \ +	for(i=0; i<n; ++i) \ +		r[i] = a[i] + b[i]; \ +} \ +LINMATH_H_FUNC void vec##n##_sub(vec##n r, vec##n const a, vec##n const b) \ +{ \ +	int i; \ +	for(i=0; i<n; ++i) \ +		r[i] = a[i] - b[i]; \ +} \ +LINMATH_H_FUNC void vec##n##_scale(vec##n r, vec##n const v, float const s) \ +{ \ +	int i; \ +	for(i=0; i<n; ++i) \ +		r[i] = v[i] * s; \ +} \ +LINMATH_H_FUNC float vec##n##_mul_inner(vec##n const a, vec##n const b) \ +{ \ +	float p = 0.f; \ +	int i; \ +	for(i=0; i<n; ++i) \ +		p += b[i]*a[i]; \ +	return p; \ +} \ +LINMATH_H_FUNC float vec##n##_len(vec##n const v) \ +{ \ +	return sqrtf(vec##n##_mul_inner(v,v)); \ +} \ +LINMATH_H_FUNC void vec##n##_norm(vec##n r, vec##n const v) \ +{ \ +	float k = 1.f / vec##n##_len(v); \ +	vec##n##_scale(r, v, k); \ +} \ +LINMATH_H_FUNC void vec##n##_min(vec##n r, vec##n const a, vec##n const b) \ +{ \ +	int i; \ +	for(i=0; i<n; ++i) \ +		r[i] = a[i]<b[i] ? a[i] : b[i]; \ +} \ +LINMATH_H_FUNC void vec##n##_max(vec##n r, vec##n const a, vec##n const b) \ +{ \ +	int i; \ +	for(i=0; i<n; ++i) \ +		r[i] = a[i]>b[i] ? a[i] : b[i]; \ +} \ +LINMATH_H_FUNC void vec##n##_dup(vec##n r, vec##n const src) \ +{ \ +	int i; \ +	for(i=0; i<n; ++i) \ +		r[i] = src[i]; \ +} + +LINMATH_H_DEFINE_VEC(2) +LINMATH_H_DEFINE_VEC(3) +LINMATH_H_DEFINE_VEC(4) + +LINMATH_H_FUNC void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b) +{ +	r[0] = a[1]*b[2] - a[2]*b[1]; +	r[1] = a[2]*b[0] - a[0]*b[2]; +	r[2] = a[0]*b[1] - a[1]*b[0]; +} + +LINMATH_H_FUNC void vec3_reflect(vec3 r, vec3 const v, vec3 const n) +{ +	float p = 2.f * vec3_mul_inner(v, n); +	int i; +	for(i=0;i<3;++i) +		r[i] = v[i] - p*n[i]; +} + +LINMATH_H_FUNC void vec4_mul_cross(vec4 r, vec4 const a, vec4 const b) +{ +	r[0] = a[1]*b[2] - a[2]*b[1]; +	r[1] = a[2]*b[0] - a[0]*b[2]; +	r[2] = a[0]*b[1] - a[1]*b[0]; +	r[3] = 1.f; +} + +LINMATH_H_FUNC void vec4_reflect(vec4 r, vec4 const v, vec4 const n) +{ +	float p  = 2.f*vec4_mul_inner(v, n); +	int i; +	for(i=0;i<4;++i) +		r[i] = v[i] - p*n[i]; +} + +typedef vec4 mat4x4[4]; +LINMATH_H_FUNC void mat4x4_identity(mat4x4 M) +{ +	int i, j; +	for(i=0; i<4; ++i) +		for(j=0; j<4; ++j) +			M[i][j] = i==j ? 1.f : 0.f; +} +LINMATH_H_FUNC void mat4x4_dup(mat4x4 M, mat4x4 const N) +{ +	int i; +	for(i=0; i<4; ++i) +		vec4_dup(M[i], N[i]); +} +LINMATH_H_FUNC void mat4x4_row(vec4 r, mat4x4 const M, int i) +{ +	int k; +	for(k=0; k<4; ++k) +		r[k] = M[k][i]; +} +LINMATH_H_FUNC void mat4x4_col(vec4 r, mat4x4 const M, int i) +{ +	int k; +	for(k=0; k<4; ++k) +		r[k] = M[i][k]; +} +LINMATH_H_FUNC void mat4x4_transpose(mat4x4 M, mat4x4 const N) +{ +    // Note: if M and N are the same, the user has to +    // explicitly make a copy of M and set it to N. +	int i, j; +	for(j=0; j<4; ++j) +		for(i=0; i<4; ++i) +			M[i][j] = N[j][i]; +} +LINMATH_H_FUNC void mat4x4_add(mat4x4 M, mat4x4 const a, mat4x4 const b) +{ +	int i; +	for(i=0; i<4; ++i) +		vec4_add(M[i], a[i], b[i]); +} +LINMATH_H_FUNC void mat4x4_sub(mat4x4 M, mat4x4 const a, mat4x4 const b) +{ +	int i; +	for(i=0; i<4; ++i) +		vec4_sub(M[i], a[i], b[i]); +} +LINMATH_H_FUNC void mat4x4_scale(mat4x4 M, mat4x4 const a, float k) +{ +	int i; +	for(i=0; i<4; ++i) +		vec4_scale(M[i], a[i], k); +} +LINMATH_H_FUNC void mat4x4_scale_aniso(mat4x4 M, mat4x4 const a, float x, float y, float z) +{ +	vec4_scale(M[0], a[0], x); +	vec4_scale(M[1], a[1], y); +	vec4_scale(M[2], a[2], z); +	vec4_dup(M[3], a[3]); +} +LINMATH_H_FUNC void mat4x4_mul(mat4x4 M, mat4x4 const a, mat4x4 const b) +{ +	mat4x4 temp; +	int k, r, c; +	for(c=0; c<4; ++c) for(r=0; r<4; ++r) { +		temp[c][r] = 0.f; +		for(k=0; k<4; ++k) +			temp[c][r] += a[k][r] * b[c][k]; +	} +	mat4x4_dup(M, temp); +} +LINMATH_H_FUNC void mat4x4_mul_vec4(vec4 r, mat4x4 const M, vec4 const v) +{ +	int i, j; +	for(j=0; j<4; ++j) { +		r[j] = 0.f; +		for(i=0; i<4; ++i) +			r[j] += M[i][j] * v[i]; +	} +} +LINMATH_H_FUNC void mat4x4_translate(mat4x4 T, float x, float y, float z) +{ +	mat4x4_identity(T); +	T[3][0] = x; +	T[3][1] = y; +	T[3][2] = z; +} +LINMATH_H_FUNC void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z) +{ +	vec4 t = {x, y, z, 0}; +	vec4 r; +	int i; +	for (i = 0; i < 4; ++i) { +		mat4x4_row(r, M, i); +		M[3][i] += vec4_mul_inner(r, t); +	} +} +LINMATH_H_FUNC void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 const a, vec3 const b) +{ +	int i, j; +	for(i=0; i<4; ++i) for(j=0; j<4; ++j) +		M[i][j] = i<3 && j<3 ? a[i] * b[j] : 0.f; +} +LINMATH_H_FUNC void mat4x4_rotate(mat4x4 R, mat4x4 const M, float x, float y, float z, float angle) +{ +	float s = sinf(angle); +	float c = cosf(angle); +	vec3 u = {x, y, z}; + +	if(vec3_len(u) > 1e-4) { +		vec3_norm(u, u); +		mat4x4 T; +		mat4x4_from_vec3_mul_outer(T, u, u); + +		mat4x4 S = { +			{    0,  u[2], -u[1], 0}, +			{-u[2],     0,  u[0], 0}, +			{ u[1], -u[0],     0, 0}, +			{    0,     0,     0, 0} +		}; +		mat4x4_scale(S, S, s); + +		mat4x4 C; +		mat4x4_identity(C); +		mat4x4_sub(C, C, T); + +		mat4x4_scale(C, C, c); + +		mat4x4_add(T, T, C); +		mat4x4_add(T, T, S); + +		T[3][3] = 1.f; +		mat4x4_mul(R, M, T); +	} else { +		mat4x4_dup(R, M); +	} +} +LINMATH_H_FUNC void mat4x4_rotate_X(mat4x4 Q, mat4x4 const M, float angle) +{ +	float s = sinf(angle); +	float c = cosf(angle); +	mat4x4 R = { +		{1.f, 0.f, 0.f, 0.f}, +		{0.f,   c,   s, 0.f}, +		{0.f,  -s,   c, 0.f}, +		{0.f, 0.f, 0.f, 1.f} +	}; +	mat4x4_mul(Q, M, R); +} +LINMATH_H_FUNC void mat4x4_rotate_Y(mat4x4 Q, mat4x4 const M, float angle) +{ +	float s = sinf(angle); +	float c = cosf(angle); +	mat4x4 R = { +		{   c, 0.f,  -s, 0.f}, +		{ 0.f, 1.f, 0.f, 0.f}, +		{   s, 0.f,   c, 0.f}, +		{ 0.f, 0.f, 0.f, 1.f} +	}; +	mat4x4_mul(Q, M, R); +} +LINMATH_H_FUNC void mat4x4_rotate_Z(mat4x4 Q, mat4x4 const M, float angle) +{ +	float s = sinf(angle); +	float c = cosf(angle); +	mat4x4 R = { +		{   c,   s, 0.f, 0.f}, +		{  -s,   c, 0.f, 0.f}, +		{ 0.f, 0.f, 1.f, 0.f}, +		{ 0.f, 0.f, 0.f, 1.f} +	}; +	mat4x4_mul(Q, M, R); +} +LINMATH_H_FUNC void mat4x4_invert(mat4x4 T, mat4x4 const M) +{ +	float s[6]; +	float c[6]; +	s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1]; +	s[1] = M[0][0]*M[1][2] - M[1][0]*M[0][2]; +	s[2] = M[0][0]*M[1][3] - M[1][0]*M[0][3]; +	s[3] = M[0][1]*M[1][2] - M[1][1]*M[0][2]; +	s[4] = M[0][1]*M[1][3] - M[1][1]*M[0][3]; +	s[5] = M[0][2]*M[1][3] - M[1][2]*M[0][3]; + +	c[0] = M[2][0]*M[3][1] - M[3][0]*M[2][1]; +	c[1] = M[2][0]*M[3][2] - M[3][0]*M[2][2]; +	c[2] = M[2][0]*M[3][3] - M[3][0]*M[2][3]; +	c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2]; +	c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3]; +	c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3]; +	 +	/* Assumes it is invertible */ +	float idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] ); +	 +	T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet; +	T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet; +	T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet; +	T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet; + +	T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet; +	T[1][1] = ( M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet; +	T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet; +	T[1][3] = ( M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet; + +	T[2][0] = ( M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet; +	T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet; +	T[2][2] = ( M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet; +	T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet; + +	T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet; +	T[3][1] = ( M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet; +	T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet; +	T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet; +} +LINMATH_H_FUNC void mat4x4_orthonormalize(mat4x4 R, mat4x4 const M) +{ +	mat4x4_dup(R, M); +	float s = 1.f; +	vec3 h; + +	vec3_norm(R[2], R[2]); +	 +	s = vec3_mul_inner(R[1], R[2]); +	vec3_scale(h, R[2], s); +	vec3_sub(R[1], R[1], h); +	vec3_norm(R[1], R[1]); + +	s = vec3_mul_inner(R[0], R[2]); +	vec3_scale(h, R[2], s); +	vec3_sub(R[0], R[0], h); + +	s = vec3_mul_inner(R[0], R[1]); +	vec3_scale(h, R[1], s); +	vec3_sub(R[0], R[0], h); +	vec3_norm(R[0], R[0]); +} + +LINMATH_H_FUNC void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f) +{ +	M[0][0] = 2.f*n/(r-l); +	M[0][1] = M[0][2] = M[0][3] = 0.f; +	 +	M[1][1] = 2.f*n/(t-b); +	M[1][0] = M[1][2] = M[1][3] = 0.f; + +	M[2][0] = (r+l)/(r-l); +	M[2][1] = (t+b)/(t-b); +	M[2][2] = -(f+n)/(f-n); +	M[2][3] = -1.f; +	 +	M[3][2] = -2.f*(f*n)/(f-n); +	M[3][0] = M[3][1] = M[3][3] = 0.f; +} +LINMATH_H_FUNC void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f) +{ +	M[0][0] = 2.f/(r-l); +	M[0][1] = M[0][2] = M[0][3] = 0.f; + +	M[1][1] = 2.f/(t-b); +	M[1][0] = M[1][2] = M[1][3] = 0.f; + +	M[2][2] = -2.f/(f-n); +	M[2][0] = M[2][1] = M[2][3] = 0.f; +	 +	M[3][0] = -(r+l)/(r-l); +	M[3][1] = -(t+b)/(t-b); +	M[3][2] = -(f+n)/(f-n); +	M[3][3] = 1.f; +} +LINMATH_H_FUNC void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f) +{ +	/* NOTE: Degrees are an unhandy unit to work with. +	 * linmath.h uses radians for everything! */ +	float const a = 1.f / tanf(y_fov / 2.f); + +	m[0][0] = a / aspect; +	m[0][1] = 0.f; +	m[0][2] = 0.f; +	m[0][3] = 0.f; + +	m[1][0] = 0.f; +	m[1][1] = a; +	m[1][2] = 0.f; +	m[1][3] = 0.f; + +	m[2][0] = 0.f; +	m[2][1] = 0.f; +	m[2][2] = -((f + n) / (f - n)); +	m[2][3] = -1.f; + +	m[3][0] = 0.f; +	m[3][1] = 0.f; +	m[3][2] = -((2.f * f * n) / (f - n)); +	m[3][3] = 0.f; +} +LINMATH_H_FUNC void mat4x4_look_at(mat4x4 m, vec3 const eye, vec3 const center, vec3 const up) +{ +	/* Adapted from Android's OpenGL Matrix.java.                        */ +	/* See the OpenGL GLUT documentation for gluLookAt for a description */ +	/* of the algorithm. We implement it in a straightforward way:       */ + +	/* TODO: The negation of of can be spared by swapping the order of +	 *       operands in the following cross products in the right way. */ +	vec3 f; +	vec3_sub(f, center, eye);	 +	vec3_norm(f, f);	 +	 +	vec3 s; +	vec3_mul_cross(s, f, up); +	vec3_norm(s, s); + +	vec3 t; +	vec3_mul_cross(t, s, f); + +	m[0][0] =  s[0]; +	m[0][1] =  t[0]; +	m[0][2] = -f[0]; +	m[0][3] =   0.f; + +	m[1][0] =  s[1]; +	m[1][1] =  t[1]; +	m[1][2] = -f[1]; +	m[1][3] =   0.f; + +	m[2][0] =  s[2]; +	m[2][1] =  t[2]; +	m[2][2] = -f[2]; +	m[2][3] =   0.f; + +	m[3][0] =  0.f; +	m[3][1] =  0.f; +	m[3][2] =  0.f; +	m[3][3] =  1.f; + +	mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]); +} + +typedef float quat[4]; +#define quat_add vec4_add +#define quat_sub vec4_sub +#define quat_norm vec4_norm +#define quat_scale vec4_scale +#define quat_mul_inner vec4_mul_inner + +LINMATH_H_FUNC void quat_identity(quat q) +{ +	q[0] = q[1] = q[2] = 0.f; +	q[3] = 1.f; +} +LINMATH_H_FUNC void quat_mul(quat r, quat const p, quat const q) +{ +	vec3 w, tmp; + +	vec3_mul_cross(tmp, p, q); +	vec3_scale(w, p, q[3]); +	vec3_add(tmp, tmp, w); +	vec3_scale(w, q, p[3]); +	vec3_add(tmp, tmp, w); + +	vec3_dup(r, tmp); +	r[3] = p[3]*q[3] - vec3_mul_inner(p, q); +} +LINMATH_H_FUNC void quat_conj(quat r, quat const q) +{ +	int i; +	for(i=0; i<3; ++i) +		r[i] = -q[i]; +	r[3] = q[3]; +} +LINMATH_H_FUNC void quat_rotate(quat r, float angle, vec3 const axis) { +    vec3 axis_norm; +    vec3_norm(axis_norm, axis); +    float s = sinf(angle / 2); +    float c = cosf(angle / 2); +    vec3_scale(r, axis_norm, s); +    r[3] = c; +} +LINMATH_H_FUNC void quat_mul_vec3(vec3 r, quat const q, vec3 const v) +{ +/* + * Method by Fabian 'ryg' Giessen (of Farbrausch) +t = 2 * cross(q.xyz, v) +v' = v + q.w * t + cross(q.xyz, t) + */ +	vec3 t; +	vec3 q_xyz = {q[0], q[1], q[2]}; +	vec3 u = {q[0], q[1], q[2]}; + +	vec3_mul_cross(t, q_xyz, v); +	vec3_scale(t, t, 2); + +	vec3_mul_cross(u, q_xyz, t); +	vec3_scale(t, t, q[3]); + +	vec3_add(r, v, t); +	vec3_add(r, r, u); +} +LINMATH_H_FUNC void mat4x4_from_quat(mat4x4 M, quat const q) +{ +	float a = q[3]; +	float b = q[0]; +	float c = q[1]; +	float d = q[2]; +	float a2 = a*a; +	float b2 = b*b; +	float c2 = c*c; +	float d2 = d*d; +	 +	M[0][0] = a2 + b2 - c2 - d2; +	M[0][1] = 2.f*(b*c + a*d); +	M[0][2] = 2.f*(b*d - a*c); +	M[0][3] = 0.f; + +	M[1][0] = 2*(b*c - a*d); +	M[1][1] = a2 - b2 + c2 - d2; +	M[1][2] = 2.f*(c*d + a*b); +	M[1][3] = 0.f; + +	M[2][0] = 2.f*(b*d + a*c); +	M[2][1] = 2.f*(c*d - a*b); +	M[2][2] = a2 - b2 - c2 + d2; +	M[2][3] = 0.f; + +	M[3][0] = M[3][1] = M[3][2] = 0.f; +	M[3][3] = 1.f; +} + +LINMATH_H_FUNC void mat4x4o_mul_quat(mat4x4 R, mat4x4 const M, quat const q) +{ +/*  XXX: The way this is written only works for orthogonal matrices. */ +/* TODO: Take care of non-orthogonal case. */ +	quat_mul_vec3(R[0], q, M[0]); +	quat_mul_vec3(R[1], q, M[1]); +	quat_mul_vec3(R[2], q, M[2]); + +	R[3][0] = R[3][1] = R[3][2] = 0.f; +	R[0][3] = M[0][3]; +	R[1][3] = M[1][3]; +	R[2][3] = M[2][3]; +	R[3][3] = M[3][3];  // typically 1.0, but here we make it general +} +LINMATH_H_FUNC void quat_from_mat4x4(quat q, mat4x4 const M) +{ +	float r=0.f; +	int i; + +	int perm[] = { 0, 1, 2, 0, 1 }; +	int *p = perm; + +	for(i = 0; i<3; i++) { +		float m = M[i][i]; +		if( m < r ) +			continue; +		m = r; +		p = &perm[i]; +	} + +	r = sqrtf(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] ); + +	if(r < 1e-6) { +		q[0] = 1.f; +		q[1] = q[2] = q[3] = 0.f; +		return; +	} + +	q[0] = r/2.f; +	q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]])/(2.f*r); +	q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]])/(2.f*r); +	q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r); +} + +LINMATH_H_FUNC void mat4x4_arcball(mat4x4 R, mat4x4 const M, vec2 const _a, vec2 const _b, float s) +{ +	vec2 a; memcpy(a, _a, sizeof(a)); +	vec2 b; memcpy(b, _b, sizeof(b)); +	 +	float z_a = 0.; +	float z_b = 0.; + +	if(vec2_len(a) < 1.) { +		z_a = sqrtf(1. - vec2_mul_inner(a, a)); +	} else { +		vec2_norm(a, a); +	} + +	if(vec2_len(b) < 1.) { +		z_b = sqrtf(1. - vec2_mul_inner(b, b)); +	} else { +		vec2_norm(b, b); +	} +	 +	vec3 a_ = {a[0], a[1], z_a}; +	vec3 b_ = {b[0], b[1], z_b}; + +	vec3 c_; +	vec3_mul_cross(c_, a_, b_); + +	float const angle = acos(vec3_mul_inner(a_, b_)) * s; +	mat4x4_rotate(R, M, c_[0], c_[1], c_[2], angle); +} +#endif @@ -1,12 +1,90 @@ +#define STB_IMAGE_IMPLEMENTATION +  #include <stdio.h>  #include <vulkan/vulkan.h>  #include <SDL2/SDL.h>  #include <SDL2/SDL_vulkan.h>  #include <stdbool.h>  #include <string.h> +#include <libpng16/png.h> +#include "linmath.h" +#include "stb_image.h"  #define MAX_FRAMES_INFLIGHT 2 +typedef mat4x4 mat4; + +struct ubo { +	mat4 model; +	mat4 view; +	mat4 proj; +}; + +struct vertex { +	vec3 pos; +	vec3 color; +	vec2 texture_coords; +}; + +struct vertex vertices[] = { +	{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}}, +	{{ 0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}}, +	{{ 0.5f,  0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}}, +	{{-0.5f,  0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}}, + +	{{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}}, +	{{ 0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}}, +	{{ 0.5f,  0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}}, +	{{-0.5f,  0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}}, + +/* +	{{ 0.0f, -0.5f}, {0.445f, 0.09f, 0.727f}}, + +	{{-0.5f, -1.0f}, {0.445f, 0.09f, 0.727f}}, +	{{-1.0f, -0.5f}, {0.445f, 0.09f, 0.727f}}, + +	{{ 1.0f, -0.5f}, {0.445f, 0.09f, 0.727f}}, +	{{ 0.5f, -1.0f}, {0.445f, 0.09f, 0.727f}}, + +	{{ 0.0f,  1.0f}, {0.445f, 0.09f, 0.727f}}, +*/ +}; + +uint16_t indices[] = { +	0, 1, 2, 2, 3, 0, +	4, 5, 6, 6, 7, 4 +}; +// uint16_t indices[] = {1, 0, 2, 3, 0, 4, 2, 3, 5}; + +VkVertexInputBindingDescription get_vertex_description() { +	return (VkVertexInputBindingDescription) { +		.binding = 0, +		.stride = sizeof(struct vertex), +		.inputRate = VK_VERTEX_INPUT_RATE_VERTEX +	}; +} + +void get_attribute_description(VkVertexInputAttributeDescription out[3]) { +	out[0] = (VkVertexInputAttributeDescription) { +		.binding = 0, +		.location = 0, +		.format = VK_FORMAT_R32G32B32_SFLOAT, +		.offset = offsetof(struct vertex, pos) +	}; +	out[1] = (VkVertexInputAttributeDescription) { +		.binding = 0, +		.location = 1, +		.format = VK_FORMAT_R32G32B32_SFLOAT, +		.offset = offsetof(struct vertex, color) +	}; +	out[2] = (VkVertexInputAttributeDescription) { +		.binding = 0, +		.location = 2, +		.format = VK_FORMAT_R32G32_SFLOAT, +		.offset = offsetof(struct vertex, texture_coords) +	}; +} +  static SDL_Window *window = NULL;  static VkDebugUtilsMessengerEXT debug_messenger;  static VkInstance instance = VK_NULL_HANDLE; @@ -19,6 +97,7 @@ static VkSwapchainKHR swapchain;  static VkFormat swapchain_format;  static VkExtent2D swapchain_extent;  static VkRenderPass render_pass; +static VkDescriptorSetLayout desc_layout;  static VkPipelineLayout pipeline_layout;  static VkCommandPool command_pool;  static VkCommandBuffer command_buffers[MAX_FRAMES_INFLIGHT]; @@ -26,7 +105,23 @@ static VkPipeline graphics_pipeline;  static VkSemaphore image_avail[MAX_FRAMES_INFLIGHT];  static VkSemaphore render_finished[MAX_FRAMES_INFLIGHT];  static VkFence in_flight_fence[MAX_FRAMES_INFLIGHT]; +static VkBuffer uniform_buffers[MAX_FRAMES_INFLIGHT]; +static VkDeviceMemory uniform_memory[MAX_FRAMES_INFLIGHT]; +static void *mapped_buffers[MAX_FRAMES_INFLIGHT]; +static VkDescriptorPool desc_pool; +static VkDescriptorSet desc_sets[MAX_FRAMES_INFLIGHT];  static uint32_t current_frame = 0; +static VkBuffer vertex_buffer; +static VkDeviceMemory vertex_buffer_memory; +static VkBuffer index_buffer; +static VkDeviceMemory index_buffer_memroy; +static VkImage texture_image; +static VkDeviceMemory texture_image_memory; +static VkImageView texture_view; +static VkSampler texture_sampler; +static VkImage depth_image; +static VkDeviceMemory depth_memory; +static VkImageView depth_image_view;  static struct {  	size_t len;  	VkImage data[]; @@ -131,6 +226,9 @@ bool found_queue_indx(struct queue_indices inds) {  }  void cleanup_swapchain() { +	vkDestroyImageView(gpu, depth_image_view, NULL); +	vkDestroyImage(gpu, depth_image, NULL); +	vkFreeMemory(gpu, depth_memory, NULL);  	for (size_t i = 0; i < framebuffers->len; i++) {  		vkDestroyFramebuffer(gpu, framebuffers->data[i], NULL);  	} @@ -146,13 +244,37 @@ void cleanup() {  		vkDestroySemaphore(gpu, image_avail[i], NULL);  		vkDestroySemaphore(gpu, render_finished[i], NULL);  		vkDestroyFence(gpu, in_flight_fence[i], NULL); + +		vkDestroyBuffer(gpu, uniform_buffers[i], NULL); +		vkFreeMemory(gpu, uniform_memory[i], NULL);  	}  	cleanup_swapchain(); + +	vkDestroyBuffer(gpu, index_buffer, NULL); +	vkFreeMemory(gpu, index_buffer_memroy, NULL); + +	vkDestroySampler(gpu, texture_sampler, NULL); +	vkDestroyImageView(gpu, texture_view, NULL); +	vkDestroyImage(gpu, texture_image, NULL); +	vkFreeMemory(gpu, texture_image_memory, NULL); + +	vkDestroyDescriptorPool(gpu, desc_pool, NULL); +	vkDestroyDescriptorSetLayout(gpu, desc_layout, NULL); + +	vkDestroyBuffer(gpu, vertex_buffer, NULL); +	vkFreeMemory(gpu, vertex_buffer_memory, NULL); +  	vkDestroyCommandPool(gpu, command_pool, NULL); +  	vkDestroyPipeline(gpu, graphics_pipeline, NULL);  	vkDestroyPipelineLayout(gpu, pipeline_layout, NULL); +  	vkDestroyRenderPass(gpu, render_pass, NULL);  	vkDestroySurfaceKHR(instance, surface, NULL); + +	((PFN_vkDestroyDebugUtilsMessengerEXT) +		vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"))(instance, debug_messenger, NULL); +  	vkDestroyDevice(gpu, NULL);  	vkDestroyInstance(instance, NULL);  	SDL_DestroyWindow(window); @@ -264,6 +386,9 @@ bool is_device_ok(VkPhysicalDevice dev) {  	free(props); +	VkPhysicalDeviceFeatures supported_features; +	vkGetPhysicalDeviceFeatures(dev, &supported_features); +  	bool adequate_swapchain = false;  	if (swapchain) {  		struct swapchain_details details = query_swapchain(dev); @@ -271,7 +396,8 @@ bool is_device_ok(VkPhysicalDevice dev) {  		free_swapchain_details(details);  	} -	return found_queue_indx(find_queue_families(dev)) && swapchain && adequate_swapchain; +	return found_queue_indx(find_queue_families(dev)) && swapchain +		&& adequate_swapchain && supported_features.samplerAnisotropy;  }  void pick_physical_dev() { @@ -320,7 +446,9 @@ void create_logical_dev() {  		},  	}; -	VkPhysicalDeviceFeatures dev_features = { 0 }; +	VkPhysicalDeviceFeatures dev_features = { +		.samplerAnisotropy = VK_TRUE +	};  	const char * const ext = VK_KHR_SWAPCHAIN_EXTENSION_NAME; @@ -401,36 +529,44 @@ void create_swapchain() {  } +VkImageView create_image_view(VkImage image, VkFormat format, VkImageAspectFlags aspect_flags) { +	VkImageViewCreateInfo create_info = { +		.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, +		.image = image, +		.viewType = VK_IMAGE_VIEW_TYPE_2D, +		.format = format, +		.components = { +			.r = VK_COMPONENT_SWIZZLE_IDENTITY, +			.g = VK_COMPONENT_SWIZZLE_IDENTITY, +			.b = VK_COMPONENT_SWIZZLE_IDENTITY, +			.a = VK_COMPONENT_SWIZZLE_IDENTITY, +		}, +		.subresourceRange = { +			.aspectMask = aspect_flags, +			.baseMipLevel = 0, +			.levelCount = 1, +			.baseArrayLayer = 0, +			.layerCount = 1 +		} +	}; + +	VkImageView view; + +	VkResult res = vkCreateImageView(gpu, &create_info, NULL, &view); +	if (res != VK_SUCCESS) { +		fputs("failed to create image view", stderr); +		exit(-1); +	} + +	return view; +} +  void create_image_views() {  	swapchain_image_views = malloc(sizeof(*swapchain_image_views) + sizeof(*swapchain_image_views->data) * swapchain_images->len);  	swapchain_image_views->len = swapchain_images->len;  	for (size_t i = 0; i < swapchain_images->len; i++) { -		VkImageViewCreateInfo create_info = { -			.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, -			.image = swapchain_images->data[i], -			.viewType = VK_IMAGE_VIEW_TYPE_2D, -			.format = swapchain_format, -			.components = { -				.r = VK_COMPONENT_SWIZZLE_IDENTITY, -				.g = VK_COMPONENT_SWIZZLE_IDENTITY, -				.b = VK_COMPONENT_SWIZZLE_IDENTITY, -				.a = VK_COMPONENT_SWIZZLE_IDENTITY, -			}, -			.subresourceRange = { -				.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, -				.baseMipLevel = 0, -				.levelCount = 1, -				.baseArrayLayer = 0, -				.layerCount = 1 -			} -		}; - -		VkResult res = vkCreateImageView(gpu, &create_info, NULL, &swapchain_image_views->data[i]); -		if (res != VK_SUCCESS) { -			fputs("failed to create image view", stderr); -			exit(-1); -		} +		swapchain_image_views->data[i] = create_image_view(swapchain_images->data[i], swapchain_format, VK_IMAGE_ASPECT_COLOR_BIT);  	}  } @@ -447,7 +583,7 @@ struct code *readfile(const char *filename) {  	struct code *bytes = malloc(sizeof(*bytes) + sizeof(*bytes->data) * len);  	bytes->len = len; -	fread(bytes->data, sizeof(*bytes->data), len, fp); +	size_t read =  fread(bytes->data, sizeof(*bytes->data), len, fp);  	fclose(fp);  	return bytes; @@ -493,8 +629,16 @@ void create_graphics_pipeline() {  	VkPipelineShaderStageCreateInfo shader_stages[] = { vert_shader_info, frag_shader_info }; +	VkVertexInputBindingDescription desc = get_vertex_description(); +	VkVertexInputAttributeDescription attrs[3]; +	get_attribute_description(attrs); +  	VkPipelineVertexInputStateCreateInfo vertex_input_info = {  		.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, +		.vertexBindingDescriptionCount = 1, +		.pVertexBindingDescriptions = &desc, +		.vertexAttributeDescriptionCount = sizeof(attrs) / sizeof(*attrs), +		.pVertexAttributeDescriptions = attrs  	};  	VkPipelineInputAssemblyStateCreateInfo input_assembly = { @@ -541,7 +685,7 @@ void create_graphics_pipeline() {  		.polygonMode = VK_POLYGON_MODE_FILL,  		.lineWidth = 1.0f,  		.cullMode = VK_CULL_MODE_BACK_BIT, -		.frontFace = VK_FRONT_FACE_CLOCKWISE, +		.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,  		.depthBiasEnable = VK_FALSE,  	}; @@ -564,8 +708,21 @@ void create_graphics_pipeline() {  		.pAttachments = &color_state  	}; +	VkPipelineDepthStencilStateCreateInfo depth_stencil = { +		.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, +		.depthTestEnable = VK_TRUE, +		.depthWriteEnable = VK_TRUE, +		.depthCompareOp = VK_COMPARE_OP_LESS, +		.depthBoundsTestEnable = VK_FALSE, +		.minDepthBounds = 0.0f, +		.maxDepthBounds = 1.0, +		.stencilTestEnable = VK_FALSE, +	}; +  	VkPipelineLayoutCreateInfo pipeline_layout_create_info = {  		.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, +		.setLayoutCount = 1, +		.pSetLayouts = &desc_layout  	};  	VkResult res = vkCreatePipelineLayout(gpu, &pipeline_layout_create_info, NULL, &pipeline_layout); @@ -585,6 +742,7 @@ void create_graphics_pipeline() {  		.pMultisampleState = &multisampling,  		.pColorBlendState = &color_blending,  		.pDynamicState = &dynamic_state_info, +		.pDepthStencilState = &depth_stencil,  		.layout = pipeline_layout,  		.renderPass = render_pass,  		.subpass = 0, @@ -602,6 +760,135 @@ void create_graphics_pipeline() {  	vkDestroyShaderModule(gpu, vert_shader, NULL);  } +uint32_t find_memory_type(uint32_t type_filter, VkMemoryPropertyFlags props) { +	VkPhysicalDeviceMemoryProperties mem_props; +	vkGetPhysicalDeviceMemoryProperties(phy_gpu, &mem_props); + +	for (size_t i = 0; i < mem_props.memoryTypeCount; i++) +		if (type_filter & (1 << i) && (mem_props.memoryTypes[i].propertyFlags & props) == props) +			return i; + +	fputs("failed to find memory type", stderr); +	exit(-1); +} + +void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, +		VkMemoryPropertyFlags props, VkBuffer *buffer, VkDeviceMemory *buffer_memory) { +	VkBufferCreateInfo buffer_info = { +		.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, +		.size = size, +		.usage = usage, +		.sharingMode = VK_SHARING_MODE_EXCLUSIVE +	}; + +	VkResult res = vkCreateBuffer(gpu, &buffer_info, NULL, buffer); +	if (res != VK_SUCCESS) { +		fputs("failed to create vertex buffer", stderr); +		exit(-1); +	} + +	VkMemoryRequirements mem_reqs; +	vkGetBufferMemoryRequirements(gpu, *buffer, &mem_reqs); + +	VkMemoryAllocateInfo alloc_info = { +		.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, +		.allocationSize = mem_reqs.size, +		.memoryTypeIndex = find_memory_type(mem_reqs.memoryTypeBits, props) +	}; + +	res = vkAllocateMemory(gpu, &alloc_info, NULL, buffer_memory); +	if (res != VK_SUCCESS) { +		fputs("failed to allocate memory", stderr); +		exit(-1); +	} + +	vkBindBufferMemory(gpu, *buffer, *buffer_memory, 0); +} + +VkCommandBuffer being_single_command() { +	VkCommandBufferAllocateInfo alloc_info = { +		.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, +		.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, +		.commandPool = command_pool, +		.commandBufferCount = 1 +	}; + +	VkCommandBuffer cmd_buf; +	vkAllocateCommandBuffers(gpu, &alloc_info, &cmd_buf); + +	VkCommandBufferBeginInfo begin_info = { +		.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, +		.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT +	}; + +	vkBeginCommandBuffer(cmd_buf, &begin_info); + +	return cmd_buf; +} + +void end_single_command(VkCommandBuffer command_buffer) { +	vkEndCommandBuffer(command_buffer); + +	VkSubmitInfo submit_info = { +		.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, +		.commandBufferCount = 1, +		.pCommandBuffers = &command_buffer +	}; + +	vkQueueSubmit(gfx_queue, 1, &submit_info, VK_NULL_HANDLE); +	vkQueueWaitIdle(gfx_queue); + +	vkFreeCommandBuffers(gpu, command_pool, 1, &command_buffer); +} + +void copy_buffer_to_image(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) { +	VkCommandBuffer command_buffer = being_single_command(); + +	VkBufferImageCopy region = { +		.bufferRowLength = 0, +		.bufferOffset = 0, +		.bufferImageHeight = 0, +		.imageSubresource = { +			.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, +			.mipLevel = 0, +			.baseArrayLayer = 0, +			.layerCount = 1 +		}, +		.imageOffset = { 0, 0, 0 }, +		.imageExtent = { width, height, 1 } +	}; + +	vkCmdCopyBufferToImage(command_buffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + +	end_single_command(command_buffer); +} + +void copy_buffer(VkBuffer src, VkBuffer dst, VkDeviceSize size) { +	VkCommandBuffer cmd_buf = being_single_command(); +	vkCmdCopyBuffer(cmd_buf, src, dst, 1, &(VkBufferCopy) { .size = size }); +	end_single_command(cmd_buf); +} + +void create_vertex_buffer() { +	VkBuffer tmp_buffer; +	VkDeviceMemory tmp_mem; +	create_buffer(sizeof(vertices), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, +			VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &tmp_buffer, &tmp_mem); + +	void *data; +	vkMapMemory(gpu, tmp_mem, 0, sizeof(vertices), 0, &data); +	memcpy(data, vertices, sizeof(vertices)); +	vkUnmapMemory(gpu, tmp_mem); + +	create_buffer(sizeof(vertices), VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, +			VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &vertex_buffer, &vertex_buffer_memory); + +	copy_buffer(tmp_buffer, vertex_buffer, sizeof(vertices)); + +	vkDestroyBuffer(gpu, tmp_buffer, NULL); +	vkFreeMemory(gpu, tmp_mem, NULL); +} +  void create_render_pass() {  	VkAttachmentDescription color_attach = {  		.format = swapchain_format, @@ -619,25 +906,44 @@ void create_render_pass() {  		.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,  	}; +	VkAttachmentDescription depth_attach = { +		.format = VK_FORMAT_D32_SFLOAT, +		.samples = VK_SAMPLE_COUNT_1_BIT, +		.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, +		.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, +		.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, +		.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, +		.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, +		.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL +	}; + +	VkAttachmentReference depth_attach_ref = { +		.attachment = 1, +		.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL +	}; +  	VkSubpassDescription subpass = {  		.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,  		.colorAttachmentCount = 1, -		.pColorAttachments = &color_attach_ref +		.pColorAttachments = &color_attach_ref, +		.pDepthStencilAttachment = &depth_attach_ref  	};  	VkSubpassDependency dep = {  		.srcSubpass = VK_SUBPASS_EXTERNAL,  		.dstSubpass = 0, -		.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, -		.srcAccessMask = 0, -		.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, -		.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT +		.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, +		.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, +		.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, +		.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT  	}; +	VkAttachmentDescription attachs[] = { color_attach, depth_attach }; +  	VkRenderPassCreateInfo create_info = {  		.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, -		.attachmentCount = 1, -		.pAttachments = &color_attach, +		.attachmentCount = sizeof(attachs) / sizeof(*attachs), +		.pAttachments = attachs,  		.subpassCount = 1,  		.pSubpasses = &subpass,  		.dependencyCount = 1, @@ -657,13 +963,14 @@ void create_framebuffers() {  	for (size_t i = 0; i < swapchain_image_views->len; i++) {  		VkImageView attachs[] = { -			swapchain_image_views->data[i] +			swapchain_image_views->data[i], +			depth_image_view  		};  		VkFramebufferCreateInfo framebuffer_info = {  			.sType =VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,  			.renderPass = render_pass, -			.attachmentCount = 1, +			.attachmentCount = sizeof(attachs) / sizeof(*attachs),  			.pAttachments = attachs,  			.width = swapchain_extent.width,  			.height = swapchain_extent.height, @@ -720,7 +1027,10 @@ void record_command_buffer(VkCommandBuffer buffer, uint32_t image_index) {  		exit(-1);  	} -	VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; +	VkClearValue clear_color[] = { +		{ .color = {0.0f, 0.0f, 0.0f, 1.0f}}, +		{ .depthStencil = { 1.0f, 0 }} +	};  	VkRenderPassBeginInfo render_pass_info = {  		.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,  		.renderPass = render_pass, @@ -729,8 +1039,8 @@ void record_command_buffer(VkCommandBuffer buffer, uint32_t image_index) {  			.extent = swapchain_extent,  			.offset = {0, 0}  		}, -		.clearValueCount = 1, -		.pClearValues = &clear_color +		.clearValueCount = sizeof(clear_color) / sizeof(*clear_color), +		.pClearValues = clear_color  	};  	vkCmdBeginRenderPass(buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); @@ -752,7 +1062,16 @@ void record_command_buffer(VkCommandBuffer buffer, uint32_t image_index) {  	};  	vkCmdSetScissor(buffer, 0, 1, &scissor); -	vkCmdDraw(buffer, 3, 1, 0, 0); + +	VkBuffer vertex_buffers[] = { vertex_buffer }; +	VkDeviceSize offsets[] = {0}; +	vkCmdBindVertexBuffers(buffer, 0, 1, vertex_buffers, offsets); +	vkCmdBindIndexBuffer(buffer, index_buffer, 0, VK_INDEX_TYPE_UINT16); + +	vkCmdBindDescriptorSets(buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, +			pipeline_layout, 0, 1, &desc_sets[current_frame], 0, NULL); + +	vkCmdDrawIndexed(buffer, sizeof(indices) / sizeof(*indices), 1, 0, 0, 0);  	vkCmdEndRenderPass(buffer); @@ -780,6 +1099,316 @@ void create_sync_objects() {  		}  } +void create_index_buffer() { +	VkBuffer tmp_buffer; +	VkDeviceMemory tmp_mem; +	create_buffer(sizeof(indices), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, +			VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &tmp_buffer, &tmp_mem); + +	void *data; +	vkMapMemory(gpu, tmp_mem, 0, sizeof(indices), 0, &data); +	memcpy(data, indices, sizeof(indices)); +	vkUnmapMemory(gpu, tmp_mem); + +	create_buffer(sizeof(indices), VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, +			VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &index_buffer, &index_buffer_memroy); + +	copy_buffer(tmp_buffer, index_buffer, sizeof(indices)); + +	vkDestroyBuffer(gpu, tmp_buffer, NULL); +	vkFreeMemory(gpu, tmp_mem, NULL); +} + +void create_descriptor_layout() { +	VkDescriptorSetLayoutBinding layout_bind[] = { +		{ +			.binding = 0, +			.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, +			.descriptorCount = 1, +			.stageFlags = VK_SHADER_STAGE_VERTEX_BIT +		}, { +			.binding = 1, +			.descriptorCount = 1, +			.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, +			.pImmutableSamplers = NULL, +			.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT +		} +	}; + + + +	VkDescriptorSetLayoutCreateInfo desc_create_info = { +		.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, +		.bindingCount = sizeof(layout_bind) / sizeof(*layout_bind), +		.pBindings = layout_bind +	}; + +	VkResult res = vkCreateDescriptorSetLayout(gpu, &desc_create_info, NULL, &desc_layout); +	if (res != VK_SUCCESS) { +		fputs("failed to create descriptor set layout", stderr); +		exit(-1); +	} +} + +void create_uniform_buffers() { +	for (size_t i = 0; i < MAX_FRAMES_INFLIGHT; i++) { +		create_buffer(sizeof(struct ubo), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, +				VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, +				&uniform_buffers[i], &uniform_memory[i]); +		vkMapMemory(gpu, uniform_memory[i], 0, sizeof(struct ubo), 0, &mapped_buffers[i]); +	} +} + +void create_descriptor_pool() { +	VkDescriptorPoolSize pool_size[] = { +		{ +			.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, +			.descriptorCount = MAX_FRAMES_INFLIGHT +		}, { +			.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, +			.descriptorCount = MAX_FRAMES_INFLIGHT +		} +	}; + +	VkDescriptorPoolCreateInfo pool_info = { +		.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, +		.poolSizeCount = sizeof(pool_size) / sizeof(*pool_size), +		.pPoolSizes = pool_size, +		.maxSets = MAX_FRAMES_INFLIGHT +	}; + +	VkResult res = vkCreateDescriptorPool(gpu, &pool_info, NULL, &desc_pool); +	if (res != VK_SUCCESS) { +		fputs("failed to create descriptor pool", stderr); +		exit(-1); +	} +} + +void create_descriptor_sets() { +	VkDescriptorSetLayout layouts[MAX_FRAMES_INFLIGHT] = { +		desc_layout, +		desc_layout +	}; + +	VkDescriptorSetAllocateInfo alloc_info = { +		.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, +		.descriptorPool = desc_pool, +		.descriptorSetCount = MAX_FRAMES_INFLIGHT, +		.pSetLayouts = layouts +	}; + +	VkResult res = vkAllocateDescriptorSets(gpu, &alloc_info, desc_sets); +	if (res != VK_SUCCESS) { +		fputs("failed to allocate descriptor sets", stderr); +		exit(-1); +	} + +	for (size_t i = 0; i < MAX_FRAMES_INFLIGHT; i++) { +		VkDescriptorBufferInfo buffer_info = { +			.buffer = uniform_buffers[i], +			.offset = 0, +			.range = sizeof(struct ubo) +		}; + +		VkDescriptorImageInfo image_info = { +			.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, +			.imageView = texture_view, +			.sampler = texture_sampler +		}; + +		VkWriteDescriptorSet desc_write[] = { +			{ +				.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, +				.dstSet = desc_sets[i], +				.dstBinding = 0, +				.dstArrayElement = 0, +				.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, +				.descriptorCount = 1, +				.pBufferInfo = &buffer_info, +			}, { +				.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, +				.dstSet = desc_sets[i], +				.dstBinding = 1, +				.dstArrayElement = 0, +				.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, +				.descriptorCount = 1, +				.pImageInfo = &image_info, +			} +		}; + +		vkUpdateDescriptorSets(gpu, sizeof(desc_write) / sizeof(*desc_write), desc_write, 0, NULL); +	} +} + +void create_image(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, +		VkImageUsageFlags usage, VkMemoryPropertyFlags props, VkImage *img, VkDeviceMemory *memory) { +	VkImageCreateInfo image_info = { +		.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, +		.imageType = VK_IMAGE_TYPE_2D, +		.extent = { +			.width = width, +			.height = height, +			.depth = 1 +		}, +		.mipLevels = 1, +		.arrayLayers = 1, +		.format = format, +		.tiling = tiling, +		.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, +		.usage = usage, +		.sharingMode = VK_SHARING_MODE_EXCLUSIVE, +		.samples = VK_SAMPLE_COUNT_1_BIT +	}; + +	VkResult res = vkCreateImage(gpu, &image_info, NULL, img); +	if (res != VK_SUCCESS) { +		fputs("failed to create image", stderr); +		exit(-1); +	} + +	VkMemoryRequirements mem_reqs; +	vkGetImageMemoryRequirements(gpu, *img, &mem_reqs); + +	VkMemoryAllocateInfo alloc_info = { +		.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, +		.allocationSize = mem_reqs.size, +		.memoryTypeIndex = find_memory_type(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) +	}; + +	res = vkAllocateMemory(gpu, &alloc_info, NULL, memory); +	if (res != VK_SUCCESS) { +		fputs("failed to allocate memory", stderr); +		exit(-1); +	} + +	vkBindImageMemory(gpu, *img, *memory, 0); +} + +void transition_image_layout(VkImage image, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) { +	VkCommandBuffer command_buffer = being_single_command(); +	VkImageMemoryBarrier barrier = { +		.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, +		.oldLayout = old_layout, +		.newLayout = new_layout, +		.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, +		.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, +		.image = image, +		.subresourceRange = { +			.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, +			.baseMipLevel = 0, +			.levelCount = 1, +			.baseArrayLayer = 0, +			.layerCount = 1 +		}, +		.srcAccessMask = 0, +		.dstAccessMask = 0 +	}; + +	VkPipelineStageFlags src_flags, dst_flags; + +	if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { +		barrier.srcAccessMask = 0; +		barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + +		src_flags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; +		dst_flags = VK_PIPELINE_STAGE_TRANSFER_BIT; +	} else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL +			&& new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { +		barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; +		barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + +		src_flags = VK_PIPELINE_STAGE_TRANSFER_BIT; +		dst_flags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; +	} else { +		fputs("unsupported layout transition", stderr); +		exit(-1); +	} + +	vkCmdPipelineBarrier(command_buffer, src_flags, dst_flags, 0, 0, NULL, 0, NULL, 1, &barrier); + +	end_single_command(command_buffer); +} + +void create_texture_image() { +	int32_t width, height, channels; + +	stbi_uc *pixels = stbi_load("pfp.png", &width, &height, &channels, STBI_rgb_alpha); +	if (!pixels) { +		fputs("failed to open pfp.png", stderr); +		exit(-1); +	} + +	VkDeviceSize image_size = width * height * 4; + +	VkBuffer tmp_buffer; +	VkDeviceMemory tmp_mem; + +	create_buffer(image_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, +			VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &tmp_buffer, &tmp_mem); + +	void *data; +	vkMapMemory(gpu, tmp_mem, 0, image_size, 0, &data); +	memcpy(data, pixels, image_size); +	vkUnmapMemory(gpu, tmp_mem); + +	stbi_image_free(pixels); + +	create_image(width, height, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, +			VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &texture_image, &texture_image_memory); + +	transition_image_layout(texture_image, VK_FORMAT_R8G8B8A8_SRGB, +			VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + +	copy_buffer_to_image(tmp_buffer, texture_image, width, height); + +	transition_image_layout(texture_image, VK_FORMAT_R8G8B8A8_SRGB, +			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + +	vkDestroyBuffer(gpu, tmp_buffer, NULL); +	vkFreeMemory(gpu, tmp_mem, NULL); +} + +void create_texture_view() { +	texture_view = create_image_view(texture_image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT); +} + +void create_texture_sampler() { +	VkPhysicalDeviceProperties props; +	vkGetPhysicalDeviceProperties(phy_gpu, &props); +	VkSamplerCreateInfo sampler_info = { +		.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, +		.magFilter = VK_FILTER_LINEAR, +		.minFilter = VK_FILTER_LINEAR, +		.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT, +		.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT, +		.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT, +		.anisotropyEnable = VK_TRUE, +		.maxAnisotropy = props.limits.maxSamplerAnisotropy, +		.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK, +		.unnormalizedCoordinates = VK_FALSE, +		.compareEnable = VK_FALSE, +		.compareOp = VK_COMPARE_OP_ALWAYS, +		.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, +		.mipLodBias = 0.0f, +		.minLod = 0.0f, +		.maxLod = 0.0f +	}; + +	VkResult res = vkCreateSampler(gpu, &sampler_info, NULL, &texture_sampler); +	if (res != VK_SUCCESS) { +		fputs("failed to create image sampler", stderr); +		exit(-1); +	} +} + +void create_depth_resources() { +	VkFormat depth_format = VK_FORMAT_D32_SFLOAT; +	create_image(swapchain_extent.width, swapchain_extent.height, VK_FORMAT_D32_SFLOAT, VK_IMAGE_TILING_OPTIMAL, +			VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &depth_image, &depth_memory); + +	depth_image_view = create_image_view(depth_image, VK_FORMAT_D32_SFLOAT, VK_IMAGE_ASPECT_DEPTH_BIT); +} +  void recreate_swapchain() {  	int32_t width = 0, height = 0;  	SDL_GetWindowSize(window, &width, &height); @@ -795,6 +1424,7 @@ void recreate_swapchain() {  	create_swapchain();  	create_image_views(); +	create_depth_resources();  	create_framebuffers();  } @@ -831,13 +1461,41 @@ void init() {  	create_swapchain();  	create_image_views();  	create_render_pass(); +	create_descriptor_layout();  	create_graphics_pipeline(); -	create_framebuffers();  	create_command_pool(); +	create_depth_resources(); +	create_framebuffers(); +	create_texture_image(); +	create_texture_view(); +	create_texture_sampler(); +	create_vertex_buffer(); +	create_index_buffer(); +	create_uniform_buffers(); +	create_descriptor_pool(); +	create_descriptor_sets();  	create_command_buffers();  	create_sync_objects();  } +void update_uniform_buffer(uint32_t current_image) { +	static double rotate = 0.1; +	struct ubo ubo = {0}; +	mat4 id; +	mat4x4_identity(id); +	mat4x4_rotate(ubo.model, id, 0, 0, 1.0f, rotate * 90); +	mat4x4_translate_in_place(ubo.model, 0, 0, 1); + +	mat4x4_look_at(ubo.view, (vec3){ 2, 2, 2 }, (vec3){ 0, 0, 1}, (vec3){ 0, 0, 1 }); + +	mat4x4_perspective(ubo.proj, 45, swapchain_extent.width / (float) swapchain_extent.height, 0.1f, 10.0f); + +	ubo.proj[1][1] *= -1; + +	memcpy(mapped_buffers[current_frame], &ubo, sizeof(ubo)); +	rotate += 0.0001; +} +  void draw() {  	vkWaitForFences(gpu, 1, &in_flight_fence[current_frame], VK_TRUE, UINT64_MAX); @@ -845,9 +1503,9 @@ void draw() {  	VkResult res = vkAcquireNextImageKHR(gpu, swapchain, UINT64_MAX, image_avail[current_frame], VK_NULL_HANDLE, &image_index);  	switch (res) {  		case VK_SUCCESS: +		case VK_SUBOPTIMAL_KHR:  			break;  		case VK_ERROR_OUT_OF_DATE_KHR: -		case VK_SUBOPTIMAL_KHR:  			recreate_swapchain();  			return;  		default: @@ -873,6 +1531,8 @@ void draw() {  		.pCommandBuffers = &command_buffers[current_frame]  	}; +	update_uniform_buffer(current_frame); +  	res = vkQueueSubmit(gfx_queue, 1, &submit_info, in_flight_fence[current_frame]);  	if (res != VK_SUCCESS) {  		fputs("failed to submit draw command buffer", stderr); @@ -889,7 +1549,18 @@ void draw() {  		.pImageIndices = &image_index  	}; -	vkQueuePresentKHR(present_queue, &present_info); +	res = vkQueuePresentKHR(present_queue, &present_info); +	switch (res) { +		case VK_SUCCESS: +			break; +		case VK_SUBOPTIMAL_KHR: +		case VK_ERROR_OUT_OF_DATE_KHR: +			recreate_swapchain(); +			return; +		default: +			fputs("failed to acquire swapchain images", stderr); +			exit(-1); +	}  	current_frame = (current_frame + 1) % MAX_FRAMES_INFLIGHT;  }Binary files differ diff --git a/shader.frag b/shader.frag index c9e559f..2209f4e 100644 --- a/shader.frag +++ b/shader.frag @@ -1,8 +1,10 @@  #version 450 +layout(binding = 1) uniform sampler2D texture_sampler;  layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 frag_text_coords;  layout(location = 0) out vec4 outColor;  void main() { -	outColor = vec4(fragColor, 1.0); +	outColor = vec4(fragColor * texture(texture_sampler, frag_text_coords).rgb, 1.0);  } diff --git a/shader.vert b/shader.vert index 9e69113..7535193 100644 --- a/shader.vert +++ b/shader.vert @@ -1,20 +1,20 @@  #version 450 -layout(location = 0) out vec3 fragColor; +layout(binding = 0) uniform UniformBufferObject { +	mat4 model; +	mat4 view; +	mat4 proj; +} ubo; -vec2 positions[3] = vec2[]( -	vec2(0.0, -0.5), -	vec2(0.5, 0.5), -	vec2(-0.5, 0.5) -); +layout(location = 0) in vec3 in_position; +layout(location = 1) in vec3 in_color; +layout(location = 2) in vec2 in_text_coords; -vec3 colors[3] = vec3[]( -	vec3(1.0, 0.0, 0.0), -	vec3(0.0, 1.0, 0.0), -	vec3(0.0, 0.0, 1.0) -); +layout(location = 0) out vec3 frag_color; +layout(location = 1) out vec2 frag_text_coords;  void main() { -	gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); -	fragColor = colors[gl_VertexIndex]; +	gl_Position = ubo.proj * ubo.view * ubo.model * vec4(in_position, 1.0); +	frag_color = in_color; +	frag_text_coords = in_text_coords;  } | 
