init
This commit is contained in:
commit
f2d87fdd00
30 changed files with 2830 additions and 0 deletions
2
.clangd
Normal file
2
.clangd
Normal file
|
@ -0,0 +1,2 @@
|
|||
CompileFlags:
|
||||
Add: [-xc, -DGLFW_INCLUDE_VULKAN]
|
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
use flake
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
.direnv
|
||||
result
|
||||
target
|
||||
compile_commands.json
|
||||
.cache
|
73
Makefile
Normal file
73
Makefile
Normal file
|
@ -0,0 +1,73 @@
|
|||
CC = clang
|
||||
CFLAGS = -std=c99 -Wall -Wextra -Wpedantic
|
||||
CFLAGS += -fstrict-aliasing
|
||||
CFLAGS += $(shell pkg-config --cflags glfw3 vulkan)
|
||||
LDFLAGS = $(shell pkg-config --libs glfw3 vulkan)
|
||||
|
||||
ifdef DEBUG
|
||||
CFLAGS += -DDEBUG -g
|
||||
else
|
||||
CFLAGS += -O3
|
||||
endif
|
||||
|
||||
GLSLC = glslc
|
||||
GLSLFLAGS =
|
||||
|
||||
NAME = ptk
|
||||
|
||||
CFLAGS += -DPTK_ENGINE_NAME=\"ptk\"
|
||||
CFLAGS += -DPTK_VERSION_MAJOR=0
|
||||
CFLAGS += -DPTK_VERSION_MINOR=1
|
||||
CFLAGS += -DPTK_VERSION_PATCH=0
|
||||
|
||||
INCLUDE = include
|
||||
SRC = src
|
||||
CFLAGS += -I$(INCLUDE) -I$(SRC)
|
||||
|
||||
BIN = target
|
||||
|
||||
H = $(shell find $(SRC) -type f -name "*.h")
|
||||
H += $(shell find $(INCLUDE) -type f -name "*.h")
|
||||
|
||||
PROG = $(shell find $(SRC) -type f -name "*.c")
|
||||
OBJ = $(addprefix $(BIN)/, $(PROG:.c=.o))
|
||||
|
||||
SHADER = shaders
|
||||
|
||||
SHADER_SRC = $(shell find $(SHADER) -type f -name "*.glsl")
|
||||
SHADER_OBJ = $(addprefix $(BIN)/, $(SHADER_SRC:.glsl=.spv))
|
||||
|
||||
.PHONY: all test clean
|
||||
|
||||
all: dirs shaders
|
||||
$(MAKE) $(NAME)
|
||||
|
||||
dirs:
|
||||
mkdir -p $(BIN)
|
||||
|
||||
$(NAME): $(OBJ)
|
||||
$(CC) $^ $(CFLAGS) $(LDFLAGS) -shared -o $(BIN)/lib$@.so
|
||||
|
||||
$(BIN)/%.o: %.c $(H)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
shaders: $(SHADER_OBJ)
|
||||
|
||||
$(BIN)/%.vert.spv: %.vert.glsl
|
||||
@mkdir -p $(@D)
|
||||
$(GLSLC) $(GLSLFLAGS) -fshader-stage=vert $< -o $@
|
||||
|
||||
$(BIN)/%.frag.spv: %.frag.glsl
|
||||
@mkdir -p $(@D)
|
||||
$(GLSLC) $(GLSLFLAGS) -fshader-stage=frag $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(BIN)
|
||||
|
||||
test:
|
||||
@CC="$(CC)" \
|
||||
CFLAGS="$(CFLAGS)" \
|
||||
BIN="$(BIN)" \
|
||||
INCLUDE="$(INCLUDE)" \
|
||||
$(MAKE) -f test/Makefile
|
3
doc/resources/c.md
Normal file
3
doc/resources/c.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Vulkan related resources used in writing this project
|
||||
|
||||
<https://stackoverflow.com/questions/2565039/how-are-multi-dimensional-arrays-formatted-in-memory>
|
6
doc/resources/vulkan.md
Normal file
6
doc/resources/vulkan.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Vulkan related resources used in writing this project
|
||||
|
||||
<https://docs.vulkan.org/guide/latest/index.html>
|
||||
<https://vulkan-tutorial.com/Vertex_buffers/Vertex_buffer_creation>
|
||||
<https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html>
|
||||
<https://www.youtube.com/watch?v=rXSdDE7NWmA>
|
26
flake.lock
Normal file
26
flake.lock
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1722421184,
|
||||
"narHash": "sha256-/DJBI6trCeVnasdjUo9pbnodCLZcFqnVZiLUfqLH4jA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9f918d616c5321ad374ae6cb5ea89c9e04bf3e58",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-unstable",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
52
flake.nix
Normal file
52
flake.nix
Normal file
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
description = "poz toolkit";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs = {self, nixpkgs, ...}: let
|
||||
name = "ptk";
|
||||
|
||||
systems = ["x86_64-linux" "aarch64-linux"];
|
||||
forEachSystem = nixpkgs.lib.genAttrs systems;
|
||||
pkgsForEach = nixpkgs.legacyPackages;
|
||||
in {
|
||||
devShells = forEachSystem (
|
||||
system: let
|
||||
pkgs = pkgsForEach.${system};
|
||||
shell = pkgs.mkShell {
|
||||
name = "ptk";
|
||||
|
||||
packages = with pkgs; [
|
||||
bear
|
||||
gdb
|
||||
vulkan-tools
|
||||
shaderc
|
||||
spirv-tools
|
||||
mesa-demos
|
||||
];
|
||||
|
||||
inputsFrom = [ self.packages.${system}.default ];
|
||||
|
||||
# https://discourse.nixos.org/t/setting-up-vulkan-for-development/11715/3
|
||||
LD_LIBRARY_PATH = with pkgs; "${glfw}/lib:${vulkan-loader}/lib:${vulkan-validation-layers}/lib:./target";
|
||||
VULKAN_SDK = with pkgs; "${vulkan-headers}";
|
||||
VK_LAYER_PATH = with pkgs; "${vulkan-validation-layers}/share/vulkan/explicit_layer.d";
|
||||
};
|
||||
in {
|
||||
"${name}" = shell;
|
||||
default = shell;
|
||||
}
|
||||
);
|
||||
packages = forEachSystem (
|
||||
system: let
|
||||
pkgs = pkgsForEach.${system};
|
||||
package = pkgs.callPackage ./nix/default.nix {};
|
||||
in {
|
||||
"${name}" = package;
|
||||
default = package;
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
69
include/ptk.h
Normal file
69
include/ptk.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#ifndef _PTK_PTK_H
|
||||
#define _PTK_PTK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cglm/types.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t major;
|
||||
uint32_t minor;
|
||||
uint32_t patch;
|
||||
} PtkVersion;
|
||||
|
||||
bool ptk_init(size_t width, size_t height, const char *title, PtkVersion application_version);
|
||||
|
||||
typedef struct PtkComponent *PtkHandle;
|
||||
#define PTK_NULL_HANDLE (void *)0
|
||||
|
||||
typedef enum {
|
||||
PTK_COMPONENT_TYPE_BOX = 0,
|
||||
PTK_COMPONENT_TYPE_TRIANGLE = 1,
|
||||
PTK_COMPONENT_TYPE_RECT = 2,
|
||||
PTK_COMPONENT_TYPE_ELLIPSE = 3,
|
||||
} PtkComponentType;
|
||||
|
||||
typedef struct PtkComponent {
|
||||
PtkComponentType type;
|
||||
} PtkComponent;
|
||||
|
||||
typedef struct PtkBox {
|
||||
PtkComponentType type;
|
||||
size_t child_count;
|
||||
PtkHandle *children;
|
||||
} PtkBox;
|
||||
|
||||
typedef struct PtkTriangle {
|
||||
PtkComponentType type;
|
||||
vec2 vertices[3];
|
||||
vec3 color;
|
||||
} PtkTriangle;
|
||||
|
||||
typedef struct PtkRect {
|
||||
PtkComponentType type;
|
||||
vec2 top_left;
|
||||
vec2 size;
|
||||
vec3 color;
|
||||
} PtkRect;
|
||||
|
||||
typedef struct PtkEllipse {
|
||||
PtkComponentType type;
|
||||
vec2 center;
|
||||
vec2 radii;
|
||||
vec3 color;
|
||||
} PtkEllipse;
|
||||
|
||||
PtkHandle ptk_box(size_t child_count, PtkHandle *children);
|
||||
PtkHandle ptk_triangle(vec2 vertices[3], vec3 color);
|
||||
PtkHandle ptk_rect(vec2 top_left, vec2 size, vec3 color);
|
||||
PtkHandle ptk_square(vec2 top_left, float size, vec3 color);
|
||||
PtkHandle ptk_ellipse(vec2 center, vec2 radii, vec3 color);
|
||||
PtkHandle ptk_circle(vec2 center, float radius, vec3 color);
|
||||
|
||||
#define PTK_BOX(...) ptk_box(sizeof((PtkHandle []){ __VA_ARGS__ }) / sizeof(PtkHandle), (PtkHandle []) { __VA_ARGS__ })
|
||||
|
||||
int ptk_run(PtkHandle root);
|
||||
|
||||
#endif // _PTK_PTK_H
|
35
include/ptk_log.h
Normal file
35
include/ptk_log.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef _PTK_PTK_LOG_H
|
||||
#define _PTK_PTK_LOG_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef enum {
|
||||
PTK_LOG_LEVEL_OFF = 0,
|
||||
PTK_LOG_LEVEL_ERR = 1,
|
||||
PTK_LOG_LEVEL_WARN = 2,
|
||||
PTK_LOG_LEVEL_INFO = 3,
|
||||
PTK_LOG_LEVEL_DEBUG = 4,
|
||||
PTK_LOG_LEVEL_TRACE = 5,
|
||||
PTK_LOG_LEVEL_ALL = INT_MAX,
|
||||
} PtkLogLevel;
|
||||
|
||||
void ptk_log_init(PtkLogLevel level);
|
||||
|
||||
void ptk_log(const char *file, int line, PtkLogLevel level, const char *fmt, ...);
|
||||
|
||||
void ptk_err (const char *file, int line, const char *fmt, ...);
|
||||
void ptk_warn (const char *file, int line, const char *fmt, ...);
|
||||
void ptk_info (const char *file, int line, const char *fmt, ...);
|
||||
void ptk_debug(const char *file, int line, const char *fmt, ...);
|
||||
void ptk_trace(const char *file, int line, const char *fmt, ...);
|
||||
|
||||
#define PTK_LOG(level, ...) ptk_log(__FILE__, __LINE__, level, __VA_ARGS__)
|
||||
|
||||
#define PTK_ERR(...) ptk_err(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define PTK_WARN(...) ptk_warn(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define PTK_INFO(...) ptk_info(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define PTK_DEBUG(...) ptk_debug(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define PTK_TRACE(...) ptk_trace(__FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
#endif // _PTK_PTK_LOG_H
|
46
nix/default.nix
Normal file
46
nix/default.nix
Normal file
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
lib,
|
||||
stdenv,
|
||||
cglm,
|
||||
clang,
|
||||
glfw,
|
||||
pkg-config,
|
||||
vulkan-headers,
|
||||
vulkan-loader,
|
||||
vulkan-validation-layers,
|
||||
...
|
||||
}: let
|
||||
pname = "ptk";
|
||||
in stdenv.mkDerivation {
|
||||
inherit pname;
|
||||
version = "0.1.0";
|
||||
|
||||
src = ../.;
|
||||
|
||||
buildInputs = [
|
||||
cglm
|
||||
glfw
|
||||
vulkan-headers
|
||||
vulkan-loader
|
||||
vulkan-validation-layers
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
clang
|
||||
pkg-config
|
||||
];
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
install -Dm755 target/lib${pname}.so -t $out/lib
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://git.jacekpoz.pl/jacekpoz/${pname}";
|
||||
description = "poz toolkit";
|
||||
license = licenses.eupl12;
|
||||
};
|
||||
}
|
12
shaders/shader.frag.glsl
Normal file
12
shaders/shader.frag.glsl
Normal file
|
@ -0,0 +1,12 @@
|
|||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
layout(location = 0) in vec3 fragColor;
|
||||
layout(location = 1) in vec2 position;
|
||||
|
||||
void main() {
|
||||
if (length(position) > 0.5) {
|
||||
discard;
|
||||
}
|
||||
outColor = vec4(fragColor, 1.0);
|
||||
}
|
17
shaders/shader.vert.glsl
Normal file
17
shaders/shader.vert.glsl
Normal file
|
@ -0,0 +1,17 @@
|
|||
#version 450
|
||||
|
||||
layout(binding = 0) uniform UniformBufferObject {
|
||||
vec2 windowSize;
|
||||
} ubo;
|
||||
|
||||
layout(location = 0) in vec2 inPosition;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
layout(location = 1) out vec2 outPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(((inPosition / ubo.windowSize) - 0.5) * 2.0, 0.0, 1.0);
|
||||
fragColor = inColor;
|
||||
outPosition = inPosition;
|
||||
}
|
199
src/ptk.c
Normal file
199
src/ptk.c
Normal file
|
@ -0,0 +1,199 @@
|
|||
#include <ptk.h>
|
||||
#include <ptk_log.h>
|
||||
#include <ptk_vec.h>
|
||||
#include <ptk_option.h>
|
||||
|
||||
#include <ptk_vk/components.h>
|
||||
#include <ptk_vk/draw.h>
|
||||
#include <ptk_vk/init.h>
|
||||
#include <ptk_vk/utils.h>
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#ifndef GLFW_INCLUDE_VULKAN
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#endif
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <cglm/cglm.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static GLFWwindow *g_window = NULL;
|
||||
|
||||
void framebuffer_resize_callback(GLFWwindow *window, int width, int height) {
|
||||
(void)window; (void)width; (void)height;
|
||||
g_framebuffer_resized = true;
|
||||
}
|
||||
|
||||
PTK_OPTION_DEFINE(PtkLogLevel);
|
||||
|
||||
PTK_OPTION(PtkLogLevel) get_log_level(void) {
|
||||
const char *log_level = getenv("PTK_LOG_LEVEL");
|
||||
if (log_level == NULL) {
|
||||
PTK_INFO("$PTK_LOG_LEVEL not set");
|
||||
PTK_INFO("using default log level");
|
||||
return PTK_OPTION_NONE(PtkLogLevel);
|
||||
}
|
||||
|
||||
size_t log_level_len = strlen(log_level);
|
||||
|
||||
char *lowercase = malloc(log_level_len * sizeof(char));
|
||||
|
||||
for (size_t i = 0; i < log_level_len; ++i) {
|
||||
lowercase[i] = tolower(log_level[i]);
|
||||
}
|
||||
|
||||
PTK_OPTION(PtkLogLevel) ret = PTK_OPTION_NONE(PtkLogLevel);
|
||||
|
||||
if (strncmp(lowercase, "off", sizeof("off")) == 0) {
|
||||
ret = PTK_OPTION_SOME(PtkLogLevel, PTK_LOG_LEVEL_OFF);
|
||||
} else if (strncmp(lowercase, "err", sizeof("err")) == 0) {
|
||||
ret = PTK_OPTION_SOME(PtkLogLevel, PTK_LOG_LEVEL_ERR);
|
||||
} else if (strncmp(lowercase, "warn", sizeof("warn")) == 0) {
|
||||
ret = PTK_OPTION_SOME(PtkLogLevel, PTK_LOG_LEVEL_WARN);
|
||||
} else if (strncmp(lowercase, "info", sizeof("info")) == 0) {
|
||||
ret = PTK_OPTION_SOME(PtkLogLevel, PTK_LOG_LEVEL_INFO);
|
||||
} else if (strncmp(lowercase, "debug", sizeof("debug")) == 0) {
|
||||
ret = PTK_OPTION_SOME(PtkLogLevel, PTK_LOG_LEVEL_DEBUG);
|
||||
} else if (strncmp(lowercase, "trace", sizeof("trace")) == 0) {
|
||||
ret = PTK_OPTION_SOME(PtkLogLevel, PTK_LOG_LEVEL_TRACE);
|
||||
} else if (strncmp(lowercase, "all", sizeof("all")) == 0) {
|
||||
ret = PTK_OPTION_SOME(PtkLogLevel, PTK_LOG_LEVEL_ALL);
|
||||
} else {
|
||||
PTK_WARN("unknown log level from $PTK_LOG_LEVEL");
|
||||
PTK_WARN("using default log level");
|
||||
}
|
||||
|
||||
free(lowercase);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ptk_init(size_t width, size_t height, const char *title, PtkVersion application_version) {
|
||||
PTK_OPTION(PtkLogLevel) log_level = get_log_level();
|
||||
if (log_level.exists) {
|
||||
ptk_log_init(log_level.value);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
PTK_WARN("running in debug mode!");
|
||||
PTK_WARN("expect decreased performance");
|
||||
#endif
|
||||
|
||||
if (!glfwInit()) {
|
||||
PTK_ERR("failed initializing GLFW");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!glfwVulkanSupported()) {
|
||||
PTK_ERR("vulkan loader or ICD haven't been found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
|
||||
g_window = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
|
||||
if (g_window == NULL) {
|
||||
PTK_ERR("failed creating GLFW window");
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwSetFramebufferSizeCallback(g_window, framebuffer_resize_callback);
|
||||
|
||||
vk_components_init();
|
||||
|
||||
if (!vk_init(g_window, title, application_version)) {
|
||||
PTK_ERR("failed initializing vulkan");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PtkHandle ptk_box(size_t child_count, PtkHandle *children) {
|
||||
PtkBox *ret = malloc(sizeof(PtkBox));
|
||||
ret->type = PTK_COMPONENT_TYPE_BOX;
|
||||
ret->child_count = child_count;
|
||||
ret->children = children;
|
||||
|
||||
return (PtkHandle)ret;
|
||||
}
|
||||
|
||||
PtkHandle ptk_triangle(vec2 vertices[3], vec3 color) {
|
||||
PtkTriangle *ret = malloc(sizeof(PtkTriangle));
|
||||
ret->type = PTK_COMPONENT_TYPE_TRIANGLE;
|
||||
memcpy(ret->vertices, vertices, sizeof(vec2) * 3);
|
||||
memcpy(ret->color, color, sizeof(vec3));
|
||||
|
||||
return (PtkHandle)ret;
|
||||
}
|
||||
|
||||
PtkHandle ptk_rect(vec2 top_left, vec2 size, vec3 color) {
|
||||
PtkRect *ret = malloc(sizeof(PtkRect));
|
||||
ret->type = PTK_COMPONENT_TYPE_RECT;
|
||||
memcpy(ret->top_left, top_left, sizeof(vec2));
|
||||
memcpy(ret->size, size, sizeof(vec2));
|
||||
memcpy(ret->color, color, sizeof(vec3));
|
||||
|
||||
return (PtkHandle)ret;
|
||||
}
|
||||
|
||||
PtkHandle ptk_square(vec2 top_left, float size, vec3 color) {
|
||||
return ptk_rect(top_left, (vec2){size, size}, color);
|
||||
}
|
||||
|
||||
PtkHandle ptk_ellipse(vec2 center, vec2 radii, vec3 color) {
|
||||
PtkEllipse *ret = malloc(sizeof(PtkEllipse));
|
||||
ret->type = PTK_COMPONENT_TYPE_ELLIPSE;
|
||||
memcpy(ret->center, center, sizeof(vec2));
|
||||
memcpy(ret->radii, radii, sizeof(vec2));
|
||||
memcpy(ret->color, color, sizeof(vec3));
|
||||
|
||||
return (PtkHandle)ret;
|
||||
}
|
||||
|
||||
PtkHandle ptk_circle(vec2 center, float radius, vec3 color) {
|
||||
return ptk_ellipse(center, (vec2){radius, radius}, color);
|
||||
}
|
||||
|
||||
void init_components(PtkHandle root) {
|
||||
switch (root->type) {
|
||||
case PTK_COMPONENT_TYPE_TRIANGLE: {
|
||||
vk_triangle((PtkTriangle *)root);
|
||||
} break;
|
||||
case PTK_COMPONENT_TYPE_RECT: {
|
||||
vk_rect((PtkRect *)root);
|
||||
} break;
|
||||
case PTK_COMPONENT_TYPE_ELLIPSE: {
|
||||
vk_ellipse((PtkEllipse *)root);
|
||||
} break;
|
||||
case PTK_COMPONENT_TYPE_BOX: {
|
||||
PtkBox *box = (PtkBox *)root;
|
||||
for (size_t i = 0; i < box->child_count; ++i) {
|
||||
init_components(box->children[i]);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
int ptk_run(PtkHandle root) {
|
||||
init_components(root);
|
||||
|
||||
while (!glfwWindowShouldClose(g_window)) {
|
||||
glfwPollEvents();
|
||||
if (!vk_draw_frame()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vkDeviceWaitIdle(g_dev);
|
||||
|
||||
vk_cleanup();
|
||||
vk_components_cleanup();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
53
src/ptk_log.c
Normal file
53
src/ptk_log.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include <ptk_log.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define FG(r, g, b) "\033[38;2;" #r ";" #g ";" #b "m"
|
||||
#define BG(r, g, b) "\033[48;2;" #r ";" #g ";" #b "m"
|
||||
#define RESET "\033[0m"
|
||||
|
||||
static const char *log_level_to_str(PtkLogLevel level) {
|
||||
const char *ret;
|
||||
switch (level) {
|
||||
case PTK_LOG_LEVEL_ERR: ret = FG(235, 28, 35) " ERR" RESET; break;
|
||||
case PTK_LOG_LEVEL_WARN: ret = FG(255, 191, 23) " WARN" RESET; break;
|
||||
case PTK_LOG_LEVEL_INFO: ret = FG( 23, 155, 98) " INFO" RESET; break;
|
||||
case PTK_LOG_LEVEL_DEBUG: ret = FG( 51, 102, 204) "DEBUG" RESET; break;
|
||||
case PTK_LOG_LEVEL_TRACE: ret = FG(108, 112, 134) "TRACE" RESET; break;
|
||||
default: ret = "?????";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static PtkLogLevel log_level = PTK_LOG_LEVEL_DEBUG;
|
||||
#else
|
||||
static PtkLogLevel log_level = PTK_LOG_LEVEL_WARN;
|
||||
#endif
|
||||
|
||||
void ptk_log_init(PtkLogLevel level) {
|
||||
log_level = level;
|
||||
}
|
||||
|
||||
void _ptk_log(const char *file, int line, PtkLogLevel level, const char *fmt, va_list args) {
|
||||
if (log_level < level) { return; }
|
||||
|
||||
fprintf(stderr, "[%s | %s:%d] ", log_level_to_str(level), file, line);
|
||||
|
||||
vfprintf(stderr, fmt, args);
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void ptk_log(const char *file, int line, PtkLogLevel level, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
_ptk_log(file, line, level, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void ptk_err (const char *file, int line, const char *fmt, ...) { va_list args; va_start(args, fmt); _ptk_log(file, line, PTK_LOG_LEVEL_ERR, fmt, args); va_end(args); }
|
||||
void ptk_warn (const char *file, int line, const char *fmt, ...) { va_list args; va_start(args, fmt); _ptk_log(file, line, PTK_LOG_LEVEL_WARN, fmt, args); va_end(args); }
|
||||
void ptk_info (const char *file, int line, const char *fmt, ...) { va_list args; va_start(args, fmt); _ptk_log(file, line, PTK_LOG_LEVEL_INFO, fmt, args); va_end(args); }
|
||||
void ptk_debug(const char *file, int line, const char *fmt, ...) { va_list args; va_start(args, fmt); _ptk_log(file, line, PTK_LOG_LEVEL_DEBUG, fmt, args); va_end(args); }
|
||||
void ptk_trace(const char *file, int line, const char *fmt, ...) { va_list args; va_start(args, fmt); _ptk_log(file, line, PTK_LOG_LEVEL_TRACE, fmt, args); va_end(args); }
|
26
src/ptk_option.h
Normal file
26
src/ptk_option.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef _PTK_PTK_OPTION_H
|
||||
#define _PTK_PTK_OPTION_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define PTK_OPTION(T) struct PtkOption_##T
|
||||
|
||||
#define PTK_OPTION_DEFINE(T) \
|
||||
PTK_OPTION(T) {\
|
||||
T value;\
|
||||
bool exists;\
|
||||
}
|
||||
|
||||
#define PTK_OPTION_SOME(T, _value) \
|
||||
(PTK_OPTION(T)){\
|
||||
.value = _value,\
|
||||
.exists = true,\
|
||||
}
|
||||
|
||||
#define PTK_OPTION_NONE(T) \
|
||||
(PTK_OPTION(T)){\
|
||||
.value = (T){0},\
|
||||
.exists = false,\
|
||||
}
|
||||
|
||||
#endif // _PTK_PTK_OPTION_H
|
77
src/ptk_vec.c
Normal file
77
src/ptk_vec.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include <ptk_vec.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
bool _grow_PtkVec(void **data, uint32_t *allocated, size_t element_size) {
|
||||
errno = 0;
|
||||
void *tmp = realloc(*data, (*allocated * 2) * element_size);
|
||||
|
||||
if (errno == ENOMEM || tmp == NULL) {
|
||||
free(*data);
|
||||
return false;
|
||||
}
|
||||
*data = tmp;
|
||||
|
||||
*allocated *= 2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _add_PtkVec(void **data, uint32_t *size, uint32_t *allocated, void *elements, size_t element_count, size_t element_size) {
|
||||
size_t elements_added = 0;
|
||||
|
||||
for (size_t i = 0; i < element_count; ++i) {
|
||||
if (*size == *allocated) {
|
||||
if (!_grow_PtkVec(data, allocated, element_size)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *element = ((uint8_t *)elements) + (i * element_size);
|
||||
|
||||
uint8_t *target = ((uint8_t *)*data) + (*size * element_size);
|
||||
memcpy(target, element, element_size);
|
||||
elements_added += 1;
|
||||
*size += 1;
|
||||
}
|
||||
|
||||
return elements_added == element_count;
|
||||
}
|
||||
|
||||
bool _remove_PtkVec(void *data, uint32_t *size, void *elements, size_t element_count, size_t element_size) {
|
||||
size_t elements_found = 0;
|
||||
|
||||
for (size_t i = 0; i < element_count; ++i) {
|
||||
uint8_t *element = ((uint8_t *)elements) + (i * element_size);
|
||||
|
||||
for (size_t j = 0; j < *size; ++j) {
|
||||
uint8_t *item = ((uint8_t *)data) + (j * element_size);
|
||||
|
||||
if (memcmp(element, item, element_size) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
elements_found += 1;
|
||||
// from the loop we know that j is always smaller than size
|
||||
// we can safely ignore the return value of this function
|
||||
_remove_at_PtkVec(data, size, j, element_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return elements_found == element_count;
|
||||
}
|
||||
|
||||
bool _remove_at_PtkVec(void *data, uint32_t *size, size_t index, size_t element_size) {
|
||||
if (index >= *size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *item = ((uint8_t *)data) + (index * element_size);
|
||||
memmove(item, item + element_size, (*size - 1 - index) * element_size);
|
||||
*size -= 1;
|
||||
|
||||
return true;
|
||||
}
|
61
src/ptk_vec.h
Normal file
61
src/ptk_vec.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#ifndef _PTK_PTK_VEC_H
|
||||
#define _PTK_PTK_VEC_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PTK_VEC(T) struct PtkVec_##T
|
||||
|
||||
#define PTK_VEC_ADD(T, vec, elem) _add_PtkVec((void **)&vec.data, &vec.size, &vec.allocated, &elem, 1, sizeof(T))
|
||||
|
||||
#define PTK_VEC_ADD_ALL(T, vec, ...) _add_PtkVec((void **)&vec.data, &vec.size, &vec.allocated, (T []) __VA_ARGS__, sizeof((T []) __VA_ARGS__) / sizeof(T), sizeof(T))
|
||||
|
||||
#define PTK_VEC_REMOVE(T, vec, elem) _remove_PtkVec((void *)vec.data, &vec.size, &elem, 1, sizeof(T))
|
||||
|
||||
#define PTK_VEC_REMOVE_ALL(T, vec, ...) _remove_PtkVec((void *)vec.data, &vec.size, (T []) __VA_ARGS__, sizeof((T []) __VA_ARGS__) / sizeof(T), sizeof(T))
|
||||
|
||||
#define PTK_VEC_REMOVE_AT(T, vec, index) _remove_at_PtkVec((void *)vec.data, &vec.size, index, sizeof(T))
|
||||
|
||||
bool _grow_PtkVec(void **data, uint32_t *allocated, size_t element_size);
|
||||
bool _add_PtkVec(void **data, uint32_t *size, uint32_t *allocated, void *elements, size_t element_count, size_t element_size);
|
||||
bool _remove_PtkVec(void *data, uint32_t *size, void *elements, size_t element_count, size_t element_size);
|
||||
bool _remove_at_PtkVec(void *data, uint32_t *size, size_t index, size_t element_size);
|
||||
|
||||
#define PTK_VEC_DEFINE(T) \
|
||||
PTK_VEC(T) {\
|
||||
T *data;\
|
||||
uint32_t allocated;\
|
||||
uint32_t size;\
|
||||
}\
|
||||
|
||||
#define PTK_VEC_NEW(T, _size) \
|
||||
(PTK_VEC(T)){\
|
||||
.data = (T *)malloc(_size * sizeof(T)),\
|
||||
.size = 0,\
|
||||
.allocated = _size,\
|
||||
}
|
||||
|
||||
#define PTK_VEC_STATIC_INIT(T, ...) \
|
||||
(PTK_VEC(T)){\
|
||||
.data = (T []) __VA_ARGS__ ,\
|
||||
.size = sizeof((T []) __VA_ARGS__) / sizeof(T),\
|
||||
.allocated = sizeof((T []) __VA_ARGS__) / sizeof(T),\
|
||||
}
|
||||
|
||||
#define PTK_VEC_FREE(vec) \
|
||||
free(vec.data)
|
||||
|
||||
#define PTK_VEC_FILLED(vec) \
|
||||
vec.size = vec.allocated;
|
||||
|
||||
PTK_VEC_DEFINE(char);
|
||||
|
||||
#define PTK_STRING PTK_VEC(char)
|
||||
|
||||
#define PTK_STRING_NEW(size) PTK_VEC_NEW(char, size)
|
||||
|
||||
#define PTK_STRING_FREE(str) PTK_VEC_FREE(str)
|
||||
|
||||
#endif // _PTK_PTK_VEC_H
|
73
src/ptk_vk/components.c
Normal file
73
src/ptk_vk/components.c
Normal file
|
@ -0,0 +1,73 @@
|
|||
#include <ptk.h>
|
||||
#include <ptk_vk/components.h>
|
||||
#include <ptk_vk/init.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
PTK_VEC_DEFINE(PtkHandle);
|
||||
|
||||
PTK_VEC(PtkHandle) m_components;
|
||||
|
||||
PTK_VEC(Vertex) g_vertices;
|
||||
|
||||
void vk_components_init(void) {
|
||||
m_components = PTK_VEC_NEW(PtkHandle, 1);
|
||||
|
||||
g_vertices = PTK_VEC_NEW(Vertex, 1);
|
||||
}
|
||||
|
||||
void _vk_triangle(PtkTriangle *triangle) {
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
Vertex v;
|
||||
memcpy(v.pos, triangle->vertices[i], sizeof(vec2));
|
||||
memcpy(v.color, triangle->color, sizeof(vec3));
|
||||
|
||||
PTK_VEC_ADD(Vertex, g_vertices, v);
|
||||
}
|
||||
}
|
||||
|
||||
void vk_triangle(PtkTriangle *triangle) {
|
||||
PTK_VEC_ADD(PtkHandle, m_components, triangle);
|
||||
_vk_triangle(triangle);
|
||||
vk_transfer_vertex_data();
|
||||
}
|
||||
|
||||
void vk_rect(PtkRect *rect) {
|
||||
PTK_VEC_ADD(PtkHandle, m_components, rect);
|
||||
vec2 t1_positions[3];
|
||||
// top left
|
||||
memcpy(t1_positions[0], &(vec2){ rect->top_left[0], rect->top_left[1] }, sizeof(vec2));
|
||||
// bottom left
|
||||
memcpy(t1_positions[1], &(vec2){ rect->top_left[0] + rect->size[0], rect->top_left[1] }, sizeof(vec2));
|
||||
// top right
|
||||
memcpy(t1_positions[2], &(vec2){ rect->top_left[0], rect->top_left[1] + rect->size[1] }, sizeof(vec2));
|
||||
PtkTriangle *t1 = (PtkTriangle *)ptk_triangle((vec2 *)t1_positions, rect->color);
|
||||
|
||||
_vk_triangle(t1);
|
||||
|
||||
vec2 t2_positions[3];
|
||||
// bottom left
|
||||
memcpy(t2_positions[0], &(vec2){ rect->top_left[0] + rect->size[0], rect->top_left[1] }, sizeof(vec2));
|
||||
// top right
|
||||
memcpy(t2_positions[1], &(vec2){ rect->top_left[0], rect->top_left[1] + rect->size[1] }, sizeof(vec2));
|
||||
// bottom right
|
||||
memcpy(t2_positions[2], &(vec2){ rect->top_left[0] + rect->size[0], rect->top_left[1] + rect->size[1] }, sizeof(vec2));
|
||||
PtkTriangle *t2 = (PtkTriangle *)ptk_triangle((vec2 *)t2_positions, rect->color);
|
||||
|
||||
_vk_triangle(t2);
|
||||
vk_transfer_vertex_data();
|
||||
}
|
||||
|
||||
void vk_ellipse(PtkEllipse *ellipse) {
|
||||
PTK_VEC_ADD(PtkHandle, m_components, ellipse);
|
||||
|
||||
}
|
||||
|
||||
void vk_components_cleanup(void) {
|
||||
for (size_t i = 0; i < m_components.size; ++i) {
|
||||
free(m_components.data[i]);
|
||||
}
|
||||
|
||||
PTK_VEC_FREE(m_components);
|
||||
PTK_VEC_FREE(g_vertices);
|
||||
}
|
24
src/ptk_vk/components.h
Normal file
24
src/ptk_vk/components.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef _PTK_PTK_VK_COMPONENTS_H
|
||||
#define _PTK_PTK_VK_COMPONENTS_H
|
||||
|
||||
#include <ptk.h>
|
||||
#include <ptk_vec.h>
|
||||
|
||||
typedef struct {
|
||||
vec2 pos;
|
||||
vec3 color;
|
||||
} Vertex;
|
||||
|
||||
PTK_VEC_DEFINE(Vertex);
|
||||
|
||||
extern PTK_VEC(Vertex) g_vertices;
|
||||
|
||||
void vk_components_init(void);
|
||||
|
||||
void vk_triangle(PtkTriangle *triangle);
|
||||
void vk_rect(PtkRect *rect);
|
||||
void vk_ellipse(PtkEllipse *ellipse);
|
||||
|
||||
void vk_components_cleanup(void);
|
||||
|
||||
#endif // _PTK_PTK_VK_COMPONENTS_H
|
92
src/ptk_vk/draw.c
Normal file
92
src/ptk_vk/draw.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
#include <ptk_vk/draw.h>
|
||||
|
||||
#include <ptk_vk/init.h>
|
||||
#include <ptk_vk/utils.h>
|
||||
|
||||
#include <ptk_log.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
bool g_framebuffer_resized = false;
|
||||
uint32_t g_current_frame = 0;
|
||||
|
||||
bool vk_draw_frame(void) {
|
||||
vkWaitForFences(g_dev, 1, &g_in_flight_fences.data[g_current_frame], VK_TRUE, UINT64_MAX);
|
||||
|
||||
uint32_t image_index;
|
||||
VkResult res = vkAcquireNextImageKHR(
|
||||
g_dev,
|
||||
g_swapchain,
|
||||
UINT64_MAX,
|
||||
g_image_available_semaphores.data[g_current_frame],
|
||||
VK_NULL_HANDLE,
|
||||
&image_index
|
||||
);
|
||||
|
||||
if (res == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
if (!vk_recreate_swapchain()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR) {
|
||||
PTK_ERR("%s", vk_result_string(res));
|
||||
return false;
|
||||
}
|
||||
|
||||
vk_update_uniform_buffer(g_current_frame);
|
||||
|
||||
vkResetFences(g_dev, 1, &g_in_flight_fences.data[g_current_frame]);
|
||||
|
||||
vkResetCommandBuffer(g_command_buffers.data[g_current_frame], 0);
|
||||
if (!vk_record_command_buffer(g_command_buffers.data[g_current_frame], image_index)) {
|
||||
PTK_ERR("failed recording command buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkSemaphore signal_semaphores[] = {g_render_finished_semaphores.data[g_current_frame]};
|
||||
|
||||
VK_TRY(false,
|
||||
vkQueueSubmit(
|
||||
g_graphics_queue,
|
||||
1,
|
||||
&(VkSubmitInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.pNext = NULL,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &g_image_available_semaphores.data[g_current_frame],
|
||||
.pWaitDstStageMask = &(VkPipelineStageFlags){VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT},
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &g_command_buffers.data[g_current_frame],
|
||||
.signalSemaphoreCount = 1,
|
||||
.pSignalSemaphores = signal_semaphores,
|
||||
},
|
||||
g_in_flight_fences.data[g_current_frame]
|
||||
)
|
||||
);
|
||||
|
||||
res = vkQueuePresentKHR(g_present_queue, &(VkPresentInfoKHR){
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.pNext = NULL,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = signal_semaphores,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &g_swapchain,
|
||||
.pImageIndices = &image_index,
|
||||
.pResults = NULL,
|
||||
});
|
||||
|
||||
if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR || g_framebuffer_resized) {
|
||||
g_framebuffer_resized = false;
|
||||
if (!vk_recreate_swapchain()) {
|
||||
return false;
|
||||
}
|
||||
PTK_TRACE("recreated swapchain");
|
||||
} else if (res != VK_SUCCESS) {
|
||||
PTK_ERR("%s", vk_result_string(res));
|
||||
return false;
|
||||
}
|
||||
|
||||
g_current_frame = (g_current_frame + 1) % g_max_frames_in_flight;
|
||||
|
||||
return true;
|
||||
}
|
12
src/ptk_vk/draw.h
Normal file
12
src/ptk_vk/draw.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef _PTK_PTK_VK_DRAW_H
|
||||
#define _PTK_PTK_VK_DRAW_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern bool g_framebuffer_resized;
|
||||
extern uint32_t g_current_frame;
|
||||
|
||||
bool vk_draw_frame(void);
|
||||
|
||||
#endif // _PTK_PTK_VK_DRAW_H
|
1553
src/ptk_vk/init.c
Normal file
1553
src/ptk_vk/init.c
Normal file
File diff suppressed because it is too large
Load diff
41
src/ptk_vk/init.h
Normal file
41
src/ptk_vk/init.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef _PTK_PTK_VK_INIT_H
|
||||
#define _PTK_PTK_VK_INIT_H
|
||||
|
||||
#ifndef GLFW_INCLUDE_VULKAN
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#endif
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <ptk.h>
|
||||
#include <ptk_vec.h>
|
||||
|
||||
PTK_VEC_DEFINE(VkCommandBuffer);
|
||||
PTK_VEC_DEFINE(VkSemaphore);
|
||||
PTK_VEC_DEFINE(VkFence);
|
||||
|
||||
extern VkDevice g_dev;
|
||||
extern VkSwapchainKHR g_swapchain;
|
||||
|
||||
extern VkQueue g_graphics_queue;
|
||||
extern VkQueue g_present_queue;
|
||||
|
||||
extern const size_t g_max_frames_in_flight;
|
||||
|
||||
extern PTK_VEC(VkCommandBuffer) g_command_buffers;
|
||||
|
||||
extern PTK_VEC(VkSemaphore) g_image_available_semaphores;
|
||||
extern PTK_VEC(VkSemaphore) g_render_finished_semaphores;
|
||||
extern PTK_VEC(VkFence) g_in_flight_fences;
|
||||
|
||||
bool vk_init(GLFWwindow *window, const char *title, const PtkVersion version);
|
||||
|
||||
bool vk_transfer_vertex_data(void);
|
||||
|
||||
bool vk_record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index);
|
||||
|
||||
bool vk_recreate_swapchain(void);
|
||||
|
||||
bool vk_update_uniform_buffer(size_t current_frame);
|
||||
|
||||
void vk_cleanup(void);
|
||||
|
||||
#endif // _PTK_PTK_VK_INIT_H
|
58
src/ptk_vk/utils.c
Normal file
58
src/ptk_vk/utils.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include <ptk_vk/utils.h>
|
||||
|
||||
const char *vk_result_string(VkResult res) {
|
||||
const char *str;
|
||||
|
||||
switch (res) {
|
||||
case VK_SUCCESS: str = "VK_SUCCESS"; break;
|
||||
case VK_NOT_READY: str = "VK_NOT_READY"; break;
|
||||
case VK_TIMEOUT: str = "VK_TIMEOUT"; break;
|
||||
case VK_EVENT_SET: str = "VK_EVENT_SET"; break;
|
||||
case VK_EVENT_RESET: str = "VK_EVENT_RESET"; break;
|
||||
case VK_INCOMPLETE: str = "VK_INCOMPLETE"; break;
|
||||
case VK_ERROR_OUT_OF_HOST_MEMORY: str = "VK_ERROR_OUT_OF_HOST_MEMORY"; break;
|
||||
case VK_ERROR_OUT_OF_DEVICE_MEMORY: str = "VK_ERROR_OUT_OF_DEVICE_MEMORY"; break;
|
||||
case VK_ERROR_INITIALIZATION_FAILED: str = "VK_ERROR_INITIALIZATION_FAILED"; break;
|
||||
case VK_ERROR_DEVICE_LOST: str = "VK_ERROR_DEVICE_LOST"; break;
|
||||
case VK_ERROR_MEMORY_MAP_FAILED: str = "VK_ERROR_MEMORY_MAP_FAILED"; break;
|
||||
case VK_ERROR_LAYER_NOT_PRESENT: str = "VK_ERROR_LAYER_NOT_PRESENT"; break;
|
||||
case VK_ERROR_EXTENSION_NOT_PRESENT: str = "VK_ERROR_EXTENSION_NOT_PRESENT"; break;
|
||||
case VK_ERROR_FEATURE_NOT_PRESENT: str = "VK_ERROR_FEATURE_NOT_PRESENT"; break;
|
||||
case VK_ERROR_INCOMPATIBLE_DRIVER: str = "VK_ERROR_INCOMPATIBLE_DRIVER"; break;
|
||||
case VK_ERROR_TOO_MANY_OBJECTS: str = "VK_ERROR_TOO_MANY_OBJECTS"; break;
|
||||
case VK_ERROR_FORMAT_NOT_SUPPORTED: str = "VK_ERROR_FORMAT_NOT_SUPPORTED"; break;
|
||||
case VK_ERROR_FRAGMENTED_POOL: str = "VK_ERROR_FRAGMENTED_POOL"; break;
|
||||
case VK_ERROR_UNKNOWN: str = "VK_ERROR_UNKNOWN"; break;
|
||||
case VK_ERROR_OUT_OF_POOL_MEMORY: str = "VK_ERROR_OUT_OF_POOL_MEMORY"; break;
|
||||
case VK_ERROR_INVALID_EXTERNAL_HANDLE: str = "VK_ERROR_INVALID_EXTERNAL_HANDLE"; break;
|
||||
case VK_ERROR_FRAGMENTATION: str = "VK_ERROR_FRAGMENTATION"; break;
|
||||
case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: str = "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"; break;
|
||||
case VK_PIPELINE_COMPILE_REQUIRED: str = "VK_PIPELINE_COMPILE_REQUIRED"; break;
|
||||
case VK_ERROR_SURFACE_LOST_KHR: str = "VK_ERROR_SURFACE_LOST_KHR"; break;
|
||||
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: str = "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; break;
|
||||
case VK_SUBOPTIMAL_KHR: str = "VK_SUBOPTIMAL_KHR"; break;
|
||||
case VK_ERROR_OUT_OF_DATE_KHR: str = "VK_ERROR_OUT_OF_DATE_KHR"; break;
|
||||
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: str = "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; break;
|
||||
case VK_ERROR_VALIDATION_FAILED_EXT: str = "VK_ERROR_VALIDATION_FAILED_EXT"; break;
|
||||
case VK_ERROR_INVALID_SHADER_NV: str = "VK_ERROR_INVALID_SHADER_NV"; break;
|
||||
case VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR: str = "VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR"; break;
|
||||
case VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR: str = "VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR"; break;
|
||||
case VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR: str = "VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR"; break;
|
||||
case VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR: str = "VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR"; break;
|
||||
case VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR: str = "VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR"; break;
|
||||
case VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR: str = "VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR"; break;
|
||||
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: str = "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; break;
|
||||
case VK_ERROR_NOT_PERMITTED_KHR: str = "VK_ERROR_NOT_PERMITTED_KHR"; break;
|
||||
case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: str = "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; break;
|
||||
case VK_THREAD_IDLE_KHR: str = "VK_THREAD_IDLE_KHR"; break;
|
||||
case VK_THREAD_DONE_KHR: str = "VK_THREAD_DONE_KHR"; break;
|
||||
case VK_OPERATION_DEFERRED_KHR: str = "VK_OPERATION_DEFERRED_KHR"; break;
|
||||
case VK_OPERATION_NOT_DEFERRED_KHR: str = "VK_OPERATION_NOT_DEFERRED_KHR"; break;
|
||||
case VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR: str = "VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR"; break;
|
||||
case VK_ERROR_COMPRESSION_EXHAUSTED_EXT: str = "VK_ERROR_COMPRESSION_EXHAUSTED_EXT"; break;
|
||||
case VK_INCOMPATIBLE_SHADER_BINARY_EXT: str = "VK_INCOMPATIBLE_SHADER_BINARY_EXT"; break;
|
||||
case VK_RESULT_MAX_ENUM: str = "VK_RESULT_MAX_ENUM"; break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
17
src/ptk_vk/utils.h
Normal file
17
src/ptk_vk/utils.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef _PTK_PTK_VK_UTILS_H
|
||||
#define _PTK_PTK_VK_UTILS_H
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <ptk_log.h>
|
||||
|
||||
const char *vk_result_string(VkResult res);
|
||||
|
||||
#define VK_TRY(return_value, ...) do {\
|
||||
VkResult res = __VA_ARGS__;\
|
||||
if (res != VK_SUCCESS) {\
|
||||
PTK_ERR("%s", vk_result_string(res));\
|
||||
return return_value;\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#endif // _PTK_PTK_VK_UTILS_H
|
25
test/Makefile
Normal file
25
test/Makefile
Normal file
|
@ -0,0 +1,25 @@
|
|||
INCLUDE += test
|
||||
CFLAGS += $(addprefix -I, $(INCLUDE))
|
||||
LDFLAGS = -L$(BIN) -lptk
|
||||
|
||||
TEST = test
|
||||
|
||||
TESTS = $(shell find $(TEST) -type f -name "*.c")
|
||||
|
||||
OBJ = $(addprefix $(BIN)/, $(TESTS:.c=))
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all: dirs_test $(OBJ)
|
||||
@echo
|
||||
@echo "---------- STARTING TESTS ----------"
|
||||
@echo
|
||||
@$(foreach test,$(OBJ),./$(test);)
|
||||
@echo "---------- FINISHED TESTS ----------"
|
||||
@echo
|
||||
|
||||
dirs_test:
|
||||
mkdir -p $(BIN)/test
|
||||
|
||||
$(BIN)/test/%: $(TEST)/%.c
|
||||
$(CC) $< $(LDFLAGS) $(CFLAGS) -o $@
|
16
test/init.c
Normal file
16
test/init.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include <test.h>
|
||||
#include <ptk.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
TEST_START()
|
||||
TEST("link to the library", {
|
||||
bool init_result = ptk_init(800, 600, "test", (PtkVersion){ .major = 0, .minor = 1, .patch = 0 });
|
||||
TEST_ASSERT(init_result, "ptk_init() failed");
|
||||
int run_result = ptk_run(PTK_BOX(
|
||||
ptk_triangle((vec2 []){{400.0f, 50.f}, {700.0f, 500.0f}, {100.0f, 500.0f}}, (vec3){0.0f, 1.0f, 0.0f}),
|
||||
ptk_rect((vec2){200.0f, 200.0f}, (vec2){300.0f, 300.0f}, (vec3){1.0f, 0.0f, 0.0f}),
|
||||
));
|
||||
TEST_ASSERT(run_result == 0, "ptk_run() failed");
|
||||
});
|
||||
TEST_FINISH()
|
50
test/test.h
Normal file
50
test/test.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define FG(r, g, b) "\033[38;2;" #r ";" #g ";" #b "m"
|
||||
#define BG(r, g, b) "\033[48;2;" #r ";" #g ";" #b "m"
|
||||
#define RESET "\033[0m"
|
||||
|
||||
#define TEST_START() \
|
||||
int main(void) {\
|
||||
uint64_t tests_failed = 0;\
|
||||
uint64_t tests_total = 0;\
|
||||
printf("----- STARTING TEST FILE " __FILE__ " -----\n");
|
||||
|
||||
#define TEST_FINISH() \
|
||||
printf("----- FINISHED TEST FILE " __FILE__ " -----\n");\
|
||||
printf("PASSED TESTS: %s" FG(0, 0, 0) "%ld/%ld" RESET "\n",\
|
||||
(tests_failed != 0 ? BG(255, 0, 0) : BG(0, 255, 0)),\
|
||||
(tests_total - tests_failed), tests_total);\
|
||||
printf("\n");\
|
||||
return tests_failed;\
|
||||
}
|
||||
|
||||
#define TEST_ASSERT(condition, message) \
|
||||
do {\
|
||||
asserts_total += 1;\
|
||||
if (!(condition)) {\
|
||||
asserts_failed += 1;\
|
||||
printf(" " BG(255, 0, 0) FG(0, 0, 0) #condition ": " message " (" __FILE__ ":%d)" RESET "\n", __LINE__);\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define TEST(name, ...) \
|
||||
do {\
|
||||
uint64_t asserts_failed = 0;\
|
||||
uint64_t asserts_total = 0;\
|
||||
tests_total += 1;\
|
||||
printf(" RUNNING TEST `" name "`\n");\
|
||||
do {\
|
||||
__VA_ARGS__;\
|
||||
} while(0);\
|
||||
printf(" PASSED ASSERTS: %s" FG(0, 0, 0) "%ld/%ld" RESET "\n",\
|
||||
(asserts_failed != 0 ? BG(255, 0, 0) : BG(0, 255, 0)),\
|
||||
(asserts_total - asserts_failed), asserts_total);\
|
||||
if (asserts_failed > 0) {\
|
||||
tests_failed += 1;\
|
||||
}\
|
||||
} while (0)
|
106
test/vec.c
Normal file
106
test/vec.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
#include <test.h>
|
||||
#include <ptk_vec.h>
|
||||
|
||||
PTK_VEC_DEFINE(uint32_t);
|
||||
|
||||
TEST_START()
|
||||
TEST("create vec", {
|
||||
size_t size = 5;
|
||||
PTK_VEC(uint32_t) vec = PTK_VEC_NEW(uint32_t, size);
|
||||
|
||||
TEST_ASSERT(vec.allocated == size, "incorrect vec allocation");
|
||||
TEST_ASSERT(vec.size == 0, "vec isn't empty after allocation");
|
||||
});
|
||||
|
||||
TEST("add elements without growing", {
|
||||
size_t size = 5;
|
||||
PTK_VEC(uint32_t) vec = PTK_VEC_NEW(uint32_t, size);
|
||||
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){21});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){37});
|
||||
|
||||
TEST_ASSERT(vec.size == 2, "size doesn't match number of elements added");
|
||||
TEST_ASSERT(vec.allocated == size, "needlessly grew vec");
|
||||
|
||||
TEST_ASSERT(vec.data[0] == 21, "first element doesn't match");
|
||||
TEST_ASSERT(vec.data[1] == 37, "second element doesn't match");
|
||||
});
|
||||
|
||||
TEST("add elements and grow", {
|
||||
size_t size = 1;
|
||||
PTK_VEC(uint32_t) vec = PTK_VEC_NEW(uint32_t, size);
|
||||
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){21});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){37});
|
||||
|
||||
TEST_ASSERT(vec.allocated == size * 2, "(1st grow) didn't grow size by a factor of 2");
|
||||
TEST_ASSERT(vec.data[1] == 37, "(1st grow) element added in grown space doesn't match");
|
||||
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){2137});
|
||||
|
||||
TEST_ASSERT(vec.allocated == size * 4, "(2nd grow) didn't grow size by a factor of 2");
|
||||
TEST_ASSERT(vec.data[2] == 2137, "(2nd grow) element added in grown space doesn't match");
|
||||
});
|
||||
|
||||
TEST("add multiple elements", {
|
||||
size_t size = 1;
|
||||
PTK_VEC(uint32_t) vec = PTK_VEC_NEW(uint32_t, size);
|
||||
|
||||
PTK_VEC_ADD_ALL(uint32_t, vec, { 21, 37, 2137, 31, 27, 7312 });
|
||||
TEST_ASSERT(vec.size == 6, "size doesn't match number of elements added");
|
||||
|
||||
TEST_ASSERT(vec.data[0] == 21, "first element doesn't match");
|
||||
TEST_ASSERT(vec.data[5] == 7312, "last element doesn't match");
|
||||
});
|
||||
|
||||
TEST("remove elements", {
|
||||
size_t size = 1;
|
||||
PTK_VEC(uint32_t) vec = PTK_VEC_NEW(uint32_t, size);
|
||||
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){21});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){37});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){2137});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){31});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){27});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){7312});
|
||||
|
||||
PTK_VEC_REMOVE(uint32_t, vec, (uint32_t){2137});
|
||||
TEST_ASSERT(vec.size == 5, "size doesn't match after removing");
|
||||
TEST_ASSERT(vec.data[2] == 31, "remaining elements not moved to the left");
|
||||
TEST_ASSERT(vec.data[4] == 7312, "last element moved improperly (check for off-by-ones)");
|
||||
});
|
||||
|
||||
TEST("remove multiple elements", {
|
||||
size_t size = 1;
|
||||
PTK_VEC(uint32_t) vec = PTK_VEC_NEW(uint32_t, size);
|
||||
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){21});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){37});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){2137});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){31});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){27});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){7312});
|
||||
|
||||
PTK_VEC_REMOVE_ALL(uint32_t, vec, { 2137, 37, 27 });
|
||||
TEST_ASSERT(vec.size == 3, "size doesn't match after removing");
|
||||
TEST_ASSERT(vec.data[1] == 31, "remaining elements not moved to the left");
|
||||
TEST_ASSERT(vec.data[2] == 7312, "last element moved improperly (check for off-by-ones)");
|
||||
});
|
||||
|
||||
TEST("remove elements at index", {
|
||||
size_t size = 1;
|
||||
PTK_VEC(uint32_t) vec = PTK_VEC_NEW(uint32_t, size);
|
||||
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){21});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){37});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){2137});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){31});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){27});
|
||||
PTK_VEC_ADD(uint32_t, vec, (uint32_t){7312});
|
||||
|
||||
PTK_VEC_REMOVE_AT(uint32_t, vec, 2);
|
||||
TEST_ASSERT(vec.size == 5, "size doesn't match after removing");
|
||||
TEST_ASSERT(vec.data[2] == 31, "remaining elements not moved to the left");
|
||||
TEST_ASSERT(vec.data[4] == 7312, "last element moved improperly (check for off-by-ones)");
|
||||
});
|
||||
TEST_FINISH()
|
Loading…
Reference in a new issue