summaryrefslogtreecommitdiff
path: root/libs/pwyazh
diff options
context:
space:
mode:
authorpryazha <pryadeiniv@mail.ru>2025-01-19 17:33:44 +0500
committerpryazha <pryadeiniv@mail.ru>2025-01-19 17:33:44 +0500
commitbd49bd525f4c6c6c15c4142bf42d1dd38be6fc16 (patch)
tree9e69f473c34b53e9e57d8af1873c39698bf5c80e /libs/pwyazh
initial commit
Diffstat (limited to 'libs/pwyazh')
-rwxr-xr-xlibs/pwyazh/build.sh8
-rwxr-xr-xlibs/pwyazh/examplebin0 -> 43488 bytes
-rw-r--r--libs/pwyazh/example.c187
-rw-r--r--libs/pwyazh/macros.h66
-rw-r--r--libs/pwyazh/mat4.h161
-rw-r--r--libs/pwyazh/memory.h41
-rw-r--r--libs/pwyazh/mesh.h76
-rw-r--r--libs/pwyazh/numeric.h74
-rw-r--r--libs/pwyazh/pwyazh.h23
-rw-r--r--libs/pwyazh/strings.h103
-rw-r--r--libs/pwyazh/types.h74
-rw-r--r--libs/pwyazh/v2f.h67
-rw-r--r--libs/pwyazh/v3f.h111
-rw-r--r--libs/pwyazh/v4f.h66
14 files changed, 1057 insertions, 0 deletions
diff --git a/libs/pwyazh/build.sh b/libs/pwyazh/build.sh
new file mode 100755
index 0000000..b8ab961
--- /dev/null
+++ b/libs/pwyazh/build.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+OPTS='-DENABLE_ASSERT=1'
+CFLAGS='-g -Wall -Wextra'
+LIBS='-lm'
+
+set -x
+
+clang -o example $CFLAGS $OPTS example.c $LIBS
diff --git a/libs/pwyazh/example b/libs/pwyazh/example
new file mode 100755
index 0000000..f574d46
--- /dev/null
+++ b/libs/pwyazh/example
Binary files differ
diff --git a/libs/pwyazh/example.c b/libs/pwyazh/example.c
new file mode 100644
index 0000000..c8939c3
--- /dev/null
+++ b/libs/pwyazh/example.c
@@ -0,0 +1,187 @@
+#include <stdio.h>
+
+#include "pwyazh.h"
+
+typedef struct Node {
+ struct Node *next;
+ struct Node *prev;
+ F32 value;
+} Node;
+
+void
+print_dll(Node *f)
+{
+ for (Node *c = f;
+ c;
+ c = c->next)
+ {
+ printf("%f%c", c->value, (c->next) ? ' ' : '\n');
+ }
+}
+
+void
+clear_dll(Node **f, Node **l)
+{
+ for (Node *c = (*f)->next;
+ c;
+ c = c->next)
+ {
+ MemoryZeroStruct(c->prev);
+ }
+ MemoryZeroStruct(*f);
+ MemoryZeroStruct(*l);
+ *f = *l = 0;
+}
+
+int
+main(void)
+{
+ V3F pos = v3f(1.0f, 2.0f, 1.0f);
+ pos = v3f_add(pos, v3f(-1.0f, 2.0f, 0.23f));
+ pos = v3f_scalef(pos, 10.0f);
+ printf("scaled: %f %f %f\n", pos.x, pos.y, pos.z);
+
+ F32 length = v3f_length(pos);
+ Assert(length > 0.0f);
+ printf("length: %f\n", length);
+
+ V3F positions[] = {
+ { -1.0f, 0.0f, 0.0f },
+ { 1.0f, 0.0f, 0.0f },
+ { 0.0f, 1.0f, 0.0f },
+ { 0.0f, 0.0f, -1.0f },
+ };
+ for (U32 pos_index = 0;
+ pos_index < ArrayCount(positions);
+ ++pos_index)
+ {
+ V3F *pos = positions+pos_index;
+ printf("%d: %f %f %f\n", pos_index,
+ pos->x, pos->y, pos->z);
+ U64 ptr_as_int = IntFromPtr(pos);
+ printf("ptr: %lx\n", ptr_as_int);
+ void *ptr = PtrFromInt(ptr_as_int);
+ V3F *as_pos = (V3F *)ptr;
+ printf("decode: %f %f %f\n",
+ as_pos->x, as_pos->y, as_pos->z);
+ }
+
+ printf("Offset of y: %lld\n", OffsetOfMember(V3F, y));
+
+ S32 min = Min(10, 2);
+ S32 max = Max(10, 2);
+ printf("min: %d\n", min);
+ printf("max: %d\n", max);
+
+ S32 source[100];
+ for (S32 index = 0;
+ index < 100;
+ ++index)
+ {
+ source[index] = index;
+ printf("%d%c", source[index], (index < 99) ? ' ' : '\n');
+ }
+
+ S32 dest[100];
+ MemoryCopyArray(dest, source);
+ printf("dest: ");
+ for (S32 index = 0;
+ index < 100;
+ ++index)
+ {
+ printf("%d%c", dest[index], (index < 99) ? ' ' : '\n');
+ }
+ printf("compare: %d\n", MemoryMatch(source, dest, sizeof(source)));
+
+ MemoryZeroArray(dest);
+ printf("dest: ");
+ for (S32 index = 0;
+ index < 100;
+ ++index)
+ {
+ printf("%d%c", dest[index], (index < 99) ? ' ' : '\n');
+ }
+ printf("compare: %d\n", MemoryMatch(source, dest, sizeof(source)));
+
+ V3F first = v3f_zero();
+ V3F second;
+ printf("struct compare: %d\n", MemoryMatch(&first, &second, sizeof(V3F)));
+ MemoryCopyStruct(&second, &first);
+ printf("struct compare: %d\n", MemoryMatch(&first, &second, sizeof(V3F)));
+
+ MAT4 mat = mat4_identity();
+ printf("det: %f\n", mat4_det(mat));
+
+ {
+ U32 node_count = 10;
+ Arena *arena = arena_alloc(Megabytes(64));
+ Node *nodes = arena_push_size(arena, node_count*sizeof(Node));
+ MemoryZero(nodes, node_count*sizeof(Node));
+ Node *f = 0;
+ Node *l = 0;
+ for (U32 node_index = 0;
+ node_index < node_count;
+ ++node_index)
+ {
+ nodes[node_index].value = node_index;
+ DLLPushBack(f, l, &nodes[node_index]);
+ }
+ print_dll(f);
+
+ for (Node *c = f;
+ c;
+ c = c->next)
+ {
+ if (c->value == 5.0f) {
+ DLLRemove(f, l, c);
+ }
+ }
+
+ DLLPushBack(f, l, &nodes[5]);
+
+ for (U32 node_index = 0;
+ node_index < node_count;
+ ++node_index)
+ {
+ Node *node = nodes+node_index;
+ printf("%u: prev: %llx ptr: %llx next: %llx %f\n",
+ node_index, IntFromPtr(node->prev),
+ IntFromPtr(node), IntFromPtr(node->next), node->value);
+ }
+
+ clear_dll(&f, &l);
+ for (U32 node_index = 0;
+ node_index < node_count;
+ ++node_index)
+ {
+ Node *node = nodes+node_index;
+ printf("%u: prev: %llx ptr: %llx next: %llx %f\n",
+ node_index, IntFromPtr(node->prev),
+ IntFromPtr(node), IntFromPtr(node->next), node->value);
+ }
+ print_dll(f);
+ arena_release(arena);
+ }
+
+ U64 temp_size = Kilobytes(1);
+ Arena *temp = arena_alloc(temp_size);
+ S32 test_count = temp_size/sizeof(S32);
+ S32 *test = arena_push_size(temp, test_count*sizeof(S32));
+ MemoryZero(test, test_count*sizeof(S32));
+ S32 i;
+ for (i = 0;
+ i < test_count;
+ ++i)
+ {
+ S32 *item = test+i;
+ *item = i;
+ printf("%d%c", *item, (i == test_count-1) ? '\n' : ' ');
+ }
+ arena_release(temp);
+
+ temp = arena_alloc(temp_size);
+ String8 str = str8_cstring((U8 *)"This is a c string");
+ printf("%s", str.str);
+ arena_release(temp);
+ return(0);
+}
diff --git a/libs/pwyazh/macros.h b/libs/pwyazh/macros.h
new file mode 100644
index 0000000..55927c1
--- /dev/null
+++ b/libs/pwyazh/macros.h
@@ -0,0 +1,66 @@
+#ifndef MACROS_H
+#define MACROS_H
+
+#if ENABLE_ASSERT
+#define Assert(s) if (!(s)) { __builtin_trap(); } /* *(int *)0 = 0; } */
+#else
+#define Assert(s)
+#endif
+
+#define ArrayCount(a) (sizeof(a)/sizeof(*(a)))
+
+#define IntFromPtr(p) (unsigned long long)((char *)(p)/* -(char *)0 */)
+#define PtrFromInt(n) (void *)(/* (char *)0+ */(n))
+
+#define Member(T, m) (((T *)0)->m)
+#define OffsetOfMember(T, m) (IntFromPtr(&Member(T, m)))
+
+#define Min(a, b) (((a) < (b)) ? (a) : (b))
+#define Max(a, b) (((a) > (b)) ? (a) : (b))
+
+#define ClampTop(a, b) Min(a, b)
+#define ClampBottom(a, b) Max(a, b)
+
+#include <string.h>
+
+#define MemoryZero(p, n) memset((p), 0, (n))
+#define MemoryZeroStruct(p) MemoryZero((p), sizeof(*(p)))
+#define MemoryZeroArray(p) MemoryZero((p), sizeof(p))
+
+#define MemoryCopy(d, s, n) memmove((d), (s), (n))
+#define MemoryCopyStruct(d, s) MemoryCopy((d), (s), Min(sizeof(*(d)), sizeof(*(s))))
+#define MemoryCopyArray(d, s) MemoryCopy((d), (s), Min(sizeof(d), sizeof(s)))
+
+#define MemoryMatch(a, b, n) (memcmp((a), (b), (n)) == 0)
+
+#define DEG2RAD pi_F32/180.0f
+#define RAD2DEG 182.0f/pi_F32
+
+/* NOTE(pryazha): Linked lists: */
+
+#define SLLPush(f, l, n) \
+((f) == 0 ? \
+((f) = (l) = (n), (n)->next = 0) : \
+((l)->next = (n), (l) = (n), (n)->next = 0))
+#define SLLPop(f, l) \
+((f) == (l) ? \
+((f) = (l) = 0) : \
+((f) = (f)->next))
+
+#define DLLPushBack_NP(f, l, n, next, prev) \
+((f) == 0 ? \
+((f) = (l) = (n), (n)->next = (n)->prev = 0) : \
+((n)->prev = (l), (l)->next = (n), (l) = (n), (n)->next = 0))
+#define DLLPushBack(f, l, n) DLLPushBack_NP(f, l, n, next, prev)
+#define DLLPushFront(f, l, n) DLLPushBack_NP(f, l, n, prev, next)
+#define DLLRemove(f, l, n) \
+((f) == (n) ? \
+((f) == (l) ? (f) = (l) = 0 : ((f) = (f)->next, (f)->prev = 0)) : \
+((l) == (n) ? ((l) = (l)->prev, (l)->next = 0) : \
+((n)->next->prev = (n)->prev, (n)->prev->next = (n)->next)))
+
+#define Kilobytes(n) n*1024
+#define Megabytes(n) Kilobytes(n)*1024
+#define Gigabytes(n) Megabytes(n)*1024
+
+#endif /* MACROS_H */
diff --git a/libs/pwyazh/mat4.h b/libs/pwyazh/mat4.h
new file mode 100644
index 0000000..4610fa8
--- /dev/null
+++ b/libs/pwyazh/mat4.h
@@ -0,0 +1,161 @@
+#ifndef MAT4_H
+#define MAT4_H
+
+#define Swap(t, a, b) { t temp = a; a = b; b = temp; }
+
+MAT4
+mat4_zero()
+{
+ MAT4 result = {
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f }
+ };
+ return(result);
+}
+
+MAT4
+mat4_identity()
+{
+ MAT4 result = {
+ { 1.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 1.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 1.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 1.0f }
+ };
+ return(result);
+}
+
+F32
+mat4_det(MAT4 mat)
+{
+ F32 a = mat.m0.x, b = mat.m0.y, c = mat.m0.z, d = mat.m0.w;
+ F32 e = mat.m1.x, f = mat.m1.y, g = mat.m1.z, h = mat.m1.w;
+ F32 i = mat.m2.x, j = mat.m2.y, k = mat.m2.z, l = mat.m2.w;
+ F32 m = mat.m3.x, n = mat.m3.y, o = mat.m3.z, p = mat.m3.w;
+
+ F32 aminor = (f*k*p)+(j*o*h)+(g*l*n)-(h*k*n)-(g*j*p)-(f*l*o);
+ F32 eminor = (b*k*p)+(j*o*d)+(c*l*n)-(n*k*d)-(o*l*b)-(j*c*p);
+ F32 iminor = (b*g*p)+(c*h*n)+(f*o*h)-(n*g*d)-(o*h*b)-(f*c*p);
+ F32 mminor = (b*g*l)+(c*h*j)+(f*k*d)-(j*g*d)-(f*c*l)-(k*h*b);
+
+ return(a*aminor+e*eminor-i*iminor+m*mminor);
+}
+
+MAT4
+mat4_transpose(MAT4 mat)
+{
+ MAT4 result = mat;
+
+ Swap(F32, result.m0.y, result.m1.x);
+ Swap(F32, result.m0.z, result.m2.x);
+ Swap(F32, result.m0.w, result.m3.x);
+
+ Swap(F32, result.m1.z, result.m2.y);
+ Swap(F32, result.m1.w, result.m3.y);
+
+ Swap(F32, result.m2.w, result.m3.z);
+
+ return(result);
+}
+
+MAT4
+mat4_mul(MAT4 left, MAT4 right)
+{
+ F32 l00 = left.m0.x, l01 = left.m0.y, l02 = left.m0.z, l03 = left.m0.w;
+ F32 l10 = left.m1.x, l11 = left.m1.y, l12 = left.m1.z, l13 = left.m1.w;
+ F32 l20 = left.m2.x, l21 = left.m2.y, l22 = left.m2.z, l23 = left.m2.w;
+ F32 l30 = left.m3.x, l31 = left.m3.y, l32 = left.m3.z, l33 = left.m3.w;
+
+ F32 r00 = right.m0.x, r01 = right.m0.y, r02 = right.m0.z, r03 = right.m0.w;
+ F32 r10 = right.m1.x, r11 = right.m1.y, r12 = right.m1.z, r13 = right.m1.w;
+ F32 r20 = right.m2.x, r21 = right.m2.y, r22 = right.m2.z, r23 = right.m2.w;
+ F32 r30 = right.m3.x, r31 = right.m3.y, r32 = right.m3.z, r33 = right.m3.w;
+
+ MAT4 result;
+
+ result.m0.x = l00*r00+l10*r01+l20*r02+l30*r03;
+ result.m0.y = l01*r00+l11*r01+l21*r02+l31*r03;
+ result.m0.z = l02*r00+l12*r01+l22*r02+l32*r03;
+ result.m0.w = l03*r00+l13*r01+l23*r02+l33*r03;
+
+ result.m1.x = l00*r10+l10*r11+l20*r12+l30*r13;
+ result.m1.y = l01*r10+l11*r11+l21*r12+l31*r13;
+ result.m1.z = l02*r10+l12*r11+l22*r12+l32*r13;
+ result.m1.w = l03*r10+l13*r11+l23*r12+l33*r13;
+
+ result.m2.x = l00*r20+l10*r21+l20*r22+l30*r23;
+ result.m2.y = l01*r20+l11*r21+l21*r22+l31*r23;
+ result.m2.z = l02*r20+l12*r21+l22*r22+l32*r23;
+ result.m2.w = l03*r20+l13*r21+l23*r22+l33*r23;
+
+ result.m3.x = l00*r30+l10*r31+l20*r32+l30*r33;
+ result.m3.y = l01*r30+l11*r31+l21*r32+l31*r33;
+ result.m3.z = l02*r30+l12*r31+l22*r32+l32*r33;
+ result.m3.w = l03*r30+l13*r31+l23*r32+l33*r33;
+
+ return(result);
+}
+
+MAT4
+mat4_make_translate(V3F vec)
+{
+ MAT4 result = mat4_identity();
+ result.m3.x = vec.x;
+ result.m3.y = vec.y;
+ result.m3.z = vec.z;
+ return(result);
+}
+
+MAT4
+mat4_translate(MAT4 mat, V3F vec)
+{
+ MAT4 translate = mat4_make_translate(vec);
+ MAT4 result = mat4_mul(translate, mat);
+ return(result);
+}
+
+MAT4
+mat4_make_scale(V3F scale)
+{
+ MAT4 result = mat4_identity();
+ result.m0.x = scale.x;
+ result.m1.y = scale.y;
+ result.m2.z = scale.z;
+ return(result);
+}
+
+MAT4
+mat4_scale(MAT4 mat, V3F scale)
+{
+ MAT4 mat_scale = mat4_make_scale(scale);
+ MAT4 result = mat4_mul(mat_scale, mat);
+ return(result);
+}
+
+V4F
+mat4_v4f_mul(MAT4 m, V4F v)
+{
+ V4F result;
+ result.x = m.m0.x*v.x+m.m1.x*v.y+m.m2.x*v.z+m.m3.x*v.w;
+ result.y = m.m0.y*v.x+m.m1.y*v.y+m.m2.y*v.z+m.m3.y*v.w;
+ result.z = m.m0.z*v.x+m.m1.z*v.y+m.m2.z*v.z+m.m3.z*v.w;
+ result.w = m.m0.w*v.x+m.m1.w*v.y+m.m2.w*v.z+m.m3.w*v.w;
+ return(result);
+}
+
+void
+mat4_print(MAT4 a)
+{
+ printf("%.4f %.4f %.4f %.4f\n",
+ a.m0.x, a.m1.x, a.m2.x, a.m3.x);
+ printf("%.4f %.4f %.4f %.4f\n",
+ a.m0.y, a.m1.y, a.m2.y, a.m3.y);
+ printf("%.4f %.4f %.4f %.4f\n",
+ a.m0.z, a.m1.z, a.m2.z, a.m3.z);
+ printf("%.4f %.4f %.4f %.4f\n\n",
+ a.m0.w, a.m1.w, a.m2.w, a.m3.w);
+}
+
+#endif /* MAT4_H */
diff --git a/libs/pwyazh/memory.h b/libs/pwyazh/memory.h
new file mode 100644
index 0000000..6f741b7
--- /dev/null
+++ b/libs/pwyazh/memory.h
@@ -0,0 +1,41 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+#include <stdlib.h>
+
+Arena *
+arena_alloc(U64 capacity)
+{
+ Arena *result = 0;
+ result = malloc(sizeof(Arena));
+ Assert(result);
+ result->memory = malloc(capacity);
+ Assert(result->memory);
+ result->capacity = capacity;
+ result->used = 0;
+ return(result);
+}
+
+void
+arena_release(Arena *arena)
+{
+ free(arena->memory);
+ arena->memory = 0;
+ arena->capacity = 0;
+ arena->used = 0;
+ free(arena);
+}
+
+void *
+arena_push_size(Arena *arena, U64 size)
+{
+ Assert(arena->used+size <= arena->capacity);
+ void *result = arena->memory+arena->used;
+ arena->used += size;
+ return(result);
+}
+
+#define ArenaPushStruct(arena, element) arena_push_size(arena, sizeof(*(element))
+#define ArenaPushArray(arena, array) arena_push_size(arena, sizeof(array))
+
+#endif /* MEMORY_H */
diff --git a/libs/pwyazh/mesh.h b/libs/pwyazh/mesh.h
new file mode 100644
index 0000000..9443a13
--- /dev/null
+++ b/libs/pwyazh/mesh.h
@@ -0,0 +1,76 @@
+#ifndef MESH_H
+#define MESH_H
+
+Vertex
+vertex(V3F pos, V3F normal, V2F tex_coords)
+{
+ Vertex result;
+ result.pos = pos;
+ result.normal = normal;
+ result.tex_coords = tex_coords;
+ return(result);
+}
+
+Mesh *
+mesh_init(Arena *arena,
+ Vertex *vertices, U32 vertex_count,
+ U32 *indices, U32 index_count)
+{
+ Mesh *mesh = 0;
+ U32 vbo, ebo;
+
+ if (!vertices)
+ {
+ printf("[ERROR]: Vertices is null\n");
+ return(mesh);
+ }
+ if (!indices)
+ {
+ printf("[ERROR]: Indices is null\n");
+ return(mesh);
+ }
+
+ Assert(arena);
+ mesh = arena_push_size(arena, sizeof(Mesh));
+
+ mesh->vertices = vertices;
+ mesh->vertex_count = vertex_count;
+
+ mesh->indices = indices;
+ mesh->index_count = index_count;
+
+ glGenVertexArrays(1, &mesh->vao);
+ glBindVertexArray(mesh->vao);
+
+ glGenBuffers(1, &vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+ glBufferData(GL_ARRAY_BUFFER, vertex_count*sizeof(Vertex), vertices, GL_STATIC_DRAW);
+
+ glGenBuffers(1, &ebo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_count*sizeof(U32), indices, GL_STATIC_DRAW);
+
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
+ (void *)(OffsetOfMember(Vertex, pos)));
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
+ (void *)(OffsetOfMember(Vertex, normal)));
+ glEnableVertexAttribArray(2);
+ glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
+ (void *)(OffsetOfMember(Vertex, tex_coords)));
+
+ glBindVertexArray(0);
+
+ return(mesh);
+}
+
+void
+mesh_draw(Mesh *mesh)
+{
+ glBindVertexArray(mesh->vao);
+ glDrawElements(GL_TRIANGLES, mesh->index_count, GL_UNSIGNED_INT, 0);
+ glBindVertexArray(0);
+}
+
+#endif /* MESH_H */ \ No newline at end of file
diff --git a/libs/pwyazh/numeric.h b/libs/pwyazh/numeric.h
new file mode 100644
index 0000000..b117084
--- /dev/null
+++ b/libs/pwyazh/numeric.h
@@ -0,0 +1,74 @@
+#ifndef NUMERIC_H
+#define NUMERIC_H
+
+/* NOTE(pryazha): Numeric functions */
+
+#include <math.h>
+
+F32
+f32_abs(F32 value)
+{
+ union {
+ F32 f;
+ U32 u;
+ } result;
+ result.f = value;
+ result.u &= 0x7fffffff;
+ return(result.f);
+}
+
+F64
+f64_abs(F64 value)
+{
+ union {
+ F64 f;
+ U64 u;
+ } result;
+ result.f = value;
+ result.u &= 0x7fffffffffffffff;
+ return(result.f);
+}
+
+F32
+f32_sqrt(F32 value)
+{
+ F32 result = sqrtf(value);
+ return(result);
+}
+
+F32
+f32_sin(F32 value)
+{
+ F32 result = sinf(value);
+ return(result);
+}
+
+F32
+f32_cos(F32 value)
+{
+ F32 result = cosf(value);
+ return(result);
+}
+
+F32
+f32_acos(F32 value)
+{
+ F32 result = acosf(value);
+ return(result);
+}
+
+F32
+f32_tan(F32 value)
+{
+ F32 result = tanf(value);
+ return(result);
+}
+
+F32
+f32_atan(F32 value)
+{
+ F32 result = atanf(value);
+ return(result);
+}
+
+#endif /* NUMERIC_H */
diff --git a/libs/pwyazh/pwyazh.h b/libs/pwyazh/pwyazh.h
new file mode 100644
index 0000000..0eede02
--- /dev/null
+++ b/libs/pwyazh/pwyazh.h
@@ -0,0 +1,23 @@
+#ifndef PWYAZH_H
+#define PWYAZH_H
+
+#include "types.h"
+
+#include "macros.h"
+
+#include "memory.h"
+
+#include "numeric.h"
+
+#include <stdio.h>
+
+#include "v2f.h"
+#include "v3f.h"
+#include "v4f.h"
+#include "mat4.h"
+
+#include "strings.h"
+
+#include "mesh.h"
+
+#endif /* PWYAZH_H */
diff --git a/libs/pwyazh/strings.h b/libs/pwyazh/strings.h
new file mode 100644
index 0000000..43ee7c8
--- /dev/null
+++ b/libs/pwyazh/strings.h
@@ -0,0 +1,103 @@
+#ifndef STRINGS_H
+#define STRINGS_H
+
+#define str8_lit(s) str8((U8 *)(s), sizeof(s)-1)
+
+String8
+str8(U8 *str, U64 size)
+{
+ String8 result = { str, size };
+ return(result);
+}
+
+B32
+str8_char_is_slash(U8 c)
+{
+ return((c == '/') || (c == '\\'));
+}
+
+U8
+str8_char_uppercase(U8 c)
+{
+ if (c >= 'a' && c <= 'z') {
+ c += 'A'-'a';
+ }
+ return(c);
+}
+
+U8
+str8_char_lowercase(U8 c)
+{
+ if (c >= 'A' && c <= 'Z') {
+ c -= 'A'-'a';
+ }
+ return(c);
+}
+
+String8
+str8_range(U8 *first, U8 *second)
+{
+ String8 result = { first, (U64)(second-first) };
+ return(result);
+}
+
+String8
+str8_cstring(U8 *cstr)
+{
+ U8 *ptr = cstr;
+ for (; *ptr != 0; ++ptr);
+ String8 result = str8_range(cstr, ptr);
+ return(result);
+}
+
+String8
+str8_prefix(String8 str, U64 size)
+{
+ U64 clamped = ClampTop(size, str.size);
+ String8 result = { str.str, clamped };
+ return(result);
+}
+
+String8
+str8_chop(String8 str, U64 amount)
+{
+ U64 clamped = ClampTop(amount, str.size);
+ U64 remaining = str.size-clamped;
+ String8 result = { str.str, remaining };
+ return(result);
+}
+
+String8
+str8_posfix(String8 str, U64 size)
+{
+ U64 clamped = ClampTop(size, str.size);
+ U64 skip = str.size-clamped;
+ String8 result = { str.str+skip, clamped };
+ return(result);
+}
+
+String8
+str8_skip(String8 str, U64 amount)
+{
+ U64 clamped = ClampTop(amount, str.size);
+ String8 result = { str.str+clamped, str.size-clamped };
+ return(result);
+}
+
+String8
+str8_substr_pos(String8 str, U64 start, U64 end)
+{
+ U64 start_clamped = ClampTop(start, str.size);
+ U64 end_clamped = ClampTop(end, str.size);
+ String8 result = { str.str+start_clamped, end_clamped-start_clamped };
+ return(result);
+}
+
+String8
+str8_substr_size(String8 str, U64 start, U64 size)
+{
+ String8 result = str8_substr_pos(str, start, start+size);
+ return(result);
+}
+
+#endif /* STRINGS_H */
diff --git a/libs/pwyazh/types.h b/libs/pwyazh/types.h
new file mode 100644
index 0000000..1e16449
--- /dev/null
+++ b/libs/pwyazh/types.h
@@ -0,0 +1,74 @@
+#ifndef TYPES_H
+#define TYPES_H
+
+/* NOTE(pryazha): Basic types */
+
+#include <stdint.h>
+typedef int8_t S8;
+typedef int16_t S16;
+typedef int32_t S32;
+typedef int64_t S64;
+typedef uint8_t U8;
+typedef uint16_t U16;
+typedef uint32_t U32;
+typedef uint64_t U64;
+typedef S32 B32;
+typedef float F32;
+typedef double F64;
+
+typedef struct {
+ F32 x, y;
+} V2F;
+
+typedef struct {
+ F32 x, y, z;
+} V3F;
+
+typedef struct {
+ F32 x, y, z, w;
+} V4F;
+
+/* NOTE(pryazha): column-major order */
+typedef struct {
+ V4F m0, m1, m2, m3;
+} MAT4;
+
+typedef struct {
+ U8 *memory;
+ U64 capacity;
+ U64 used;
+} Arena;
+
+/* NOTE(pryazha): String types */
+typedef struct {
+ U8 *str;
+ U64 size;
+} String8;
+
+typedef struct {
+ struct String8Node *next;
+ String8 string;
+} String8Node;
+
+typedef struct {
+ String8Node *first;
+ String8Node *last;
+} String8List;
+
+typedef struct {
+ V3F pos;
+ V3F normal;
+ V2F tex_coords;
+} Vertex;
+
+typedef struct {
+ U32 vao;
+ Vertex *vertices;
+ U32 vertex_count;
+ U32 *indices;
+ U32 index_count;
+} Mesh;
+
+static F32 pi_F32 = 3.14159265359f;
+
+#endif /* TYPES_H */
diff --git a/libs/pwyazh/v2f.h b/libs/pwyazh/v2f.h
new file mode 100644
index 0000000..bc09b45
--- /dev/null
+++ b/libs/pwyazh/v2f.h
@@ -0,0 +1,67 @@
+#ifndef V2F_H
+#define V2F_H
+
+V2F
+v2f(F32 x, F32 y)
+{
+ V2F result = { x, y };
+ return(result);
+}
+
+V2F
+v2f_zero()
+{
+ V2F result = { 0.0f, 0.0f };
+ return(result);
+}
+
+V2F
+v2f_add(V2F a, V2F b)
+{
+ V2F result = { a.x+b.x, a.y+b.y };
+ return(result);
+}
+
+V2F
+v2f_sub(V2F a, V2F b)
+{
+ V2F result = { a.x-b.x, a.y-b.y };
+ return(result);
+}
+
+V2F
+v2f_scalef(V2F a, F32 scale)
+{
+ V2F result = { a.x*scale, a.y*scale };
+ return(result);
+}
+
+V2F
+v2f_scalev(V2F a, V2F scale)
+{
+ V2F result = { a.x*scale.x, a.y*scale.y };
+ return(result);
+}
+
+
+F32
+v2f_length2(V2F a)
+{
+ F32 result = a.x*a.x+a.y*a.y;
+ return(result);
+}
+
+F32
+v2f_length(V2F a)
+{
+ F32 result = f32_sqrt(v2f_length2(a));
+ return(result);
+}
+
+void
+v2f_print(V2F a)
+{
+ printf("[%4.4f\n%4.4f]\n\n", a.x, a.y);
+}
+
+#endif /* V2F_H */
diff --git a/libs/pwyazh/v3f.h b/libs/pwyazh/v3f.h
new file mode 100644
index 0000000..ba2e140
--- /dev/null
+++ b/libs/pwyazh/v3f.h
@@ -0,0 +1,111 @@
+#ifndef V3F_H
+#define V3F_H
+
+V3F
+v3f(F32 x, F32 y, F32 z)
+{
+ V3F result = { x, y, z };
+ return(result);
+}
+
+V3F
+v3f_zero()
+{
+ V3F result = { 0.0f, 0.0f, 0.0f };
+ return(result);
+}
+
+V3F
+v3f_one()
+{
+ V3F result = { 1.0f, 1.0f, 1.0f };
+ return(result);
+}
+
+V3F
+v3f_negate(V3F a)
+{
+ V3F result = { -a.x, -a.y, -a.z };
+ return(result);
+}
+
+V3F
+v3f_add(V3F a, V3F b)
+{
+ V3F result = { a.x+b.x, a.y+b.y, a.z+b.z };
+ return(result);
+}
+
+V3F
+v3f_sub(V3F a, V3F b)
+{
+ V3F result = { a.x-b.x, a.y-b.y, a.z-b.z };
+ return(result);
+}
+
+V3F
+v3f_scalef(V3F a, F32 scale)
+{
+ V3F result = { a.x*scale, a.y*scale, a.z*scale };
+ return(result);
+}
+
+V3F
+v3f_scalev(V3F a, V3F scale)
+{
+ V3F result = { a.x*scale.x, a.y*scale.y, a.z*scale.z };
+ return(result);
+}
+
+F32
+v3f_length2(V3F a)
+{
+ F32 result = a.x*a.x+a.y*a.y+a.z*a.z;
+ return(result);
+}
+
+F32
+v3f_length(V3F a)
+{
+ F32 result = f32_sqrt(v3f_length2(a));
+ return(result);
+}
+
+V3F
+v3f_norm(V3F a)
+{
+ F32 length = v3f_length(a);
+ V3F result = v3f_zero();
+ if (length) {
+ result = v3f(a.x/length, a.y/length, a.z/length);
+ }
+ return(result);
+}
+
+V3F
+v3f_dot(V3F a, V3F b)
+{
+ V3F result;
+ result.x = a.x*b.x;
+ result.y = a.y*b.y;
+ result.z = a.z*b.z;
+ return(result);
+}
+
+V3F
+v3f_cross(V3F left, V3F right)
+{
+ V3F result;
+ result.x = (left.y*right.z-right.y*left.z);
+ result.y = (right.x*left.z-left.x*right.z);
+ result.z = (left.x*right.y-right.x*left.y);
+ return(result);
+}
+
+void
+v3f_print(V3F a)
+{
+ printf("[%4.4f\n%4.4f\n%4.4f]\n\n", a.x, a.y, a.z);
+}
+
+#endif /* V3F_H */
diff --git a/libs/pwyazh/v4f.h b/libs/pwyazh/v4f.h
new file mode 100644
index 0000000..12cdb21
--- /dev/null
+++ b/libs/pwyazh/v4f.h
@@ -0,0 +1,66 @@
+#ifndef V4F_H
+#define V4F_H
+
+V4F
+v4f(F32 x, F32 y, F32 z, F32 w)
+{
+ V4F result = { x, y, z, w };
+ return(result);
+}
+
+V4F
+v4f_zero()
+{
+ V4F result = { 0.0f, 0.0f, 0.0f, 0.0f };
+ return(result);
+}
+
+V4F
+v4f_add(V4F a, V4F b)
+{
+ V4F result = { a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w };
+ return(result);
+}
+
+V4F
+v4f_sub(V4F a, V4F b)
+{
+ V4F result = { a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w };
+ return(result);
+}
+
+V4F
+v4f_scalef(V4F a, F32 scale)
+{
+ V4F result = { a.x*scale, a.y*scale, a.z*scale, a.w*scale };
+ return(result);
+}
+
+V4F
+v4f_scalev(V4F a, V4F scale)
+{
+ V4F result = { a.x*scale.x, a.y*scale.y, a.z*scale.z, a.w*scale.w };
+ return(result);
+}
+
+F32
+v4f_length2(V4F a)
+{
+ F32 result = a.x*a.x+a.y*a.y+a.z*a.z+a.w*a.w;
+ return(result);
+}
+
+F32
+v4f_length(V4F a)
+{
+ F32 result = f32_sqrt(v4f_length2(a));
+ return(result);
+}
+
+void
+v4f_print(V4F a)
+{
+ printf("[%4.4f\n%4.4f\n%4.4f\n%4.4f]\n\n", a.x, a.y, a.z, a.w);
+}
+
+#endif /* V4F_H */