diff --git a/.gitignore b/.gitignore index 184698d..cddbd36 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ thirdparty +build temp +.cache main *.o diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..48851f6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,98 @@ +cmake_minimum_required(VERSION 4.0) +project(galaxy-engine C CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_C_STANDARD 99) + +# creates compile_commands.json +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Googletest (aka gtest) +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) +FetchContent_MakeAvailable(googletest) + +FetchContent_Declare( + bgfx + URL https://github.com/bkaradzic/bgfx.cmake/releases/download/v1.129.8866-492/bgfx.cmake.v1.129.8866-492.zip +) +FetchContent_Declare( + glfw + URL https://github.com/glfw/glfw/releases/download/3.4/glfw-3.4.zip +) +FetchContent_MakeAvailable(glfw bgfx) + + +set(SOURCES + src/galaxy.cpp + src/gwindow.cpp + src/grenderer.cpp + src/logger.cpp + src/gshader.cpp + src/vertex.cpp + src/todo.cpp +) + +# Includes bgfx/src for #include inside shaders +set(BGFX_SHADER_INCLUDE_PATH "${BGFX_DIR}/src" CACHE STRING "bgfx include path") +set(GALAXY_SHADER_BIN_DIR "${CMAKE_BINARY_DIR}/generated/shaders" CACHE STRING "Shader install location") + +set(SHADER_SOURCES + src/shaders/v_simple.sc + src/shaders/f_simple.sc +) + +bgfx_compile_shaders( + TYPE VERTEX + SHADERS src/shaders/v_simple.sc + VARYING_DEF ${CMAKE_SOURCE_DIR}/src/shaders/varying.def.sc + OUTPUT_DIR ${CMAKE_BINARY_DIR}/generated/shaders +) + +bgfx_compile_shaders( + TYPE FRAGMENT + SHADERS src/shaders/f_simple.sc + VARYING_DEF ${CMAKE_SOURCE_DIR}/src/shaders/varying.def.sc + OUTPUT_DIR ${CMAKE_BINARY_DIR}/generated/shaders +) + +configure_file(include/env-vars.h.in ${CMAKE_BINARY_DIR}/generated/include/env-vars.h) + +set(INCLUDE_DIRS + ${BGFX_DIR}/include + ${BX_DIR}/include + ${CMAKE_BINARY_DIR}/generated/include # env-vars.h +) + +add_library(galaxy-engine-lib ${SOURCES} ${SHADER_SOURCES}) +add_executable(galaxy-engine src/main.cpp) + +target_include_directories(galaxy-engine PRIVATE include ${INCLUDE_DIRS}) +target_include_directories(galaxy-engine-lib PRIVATE include ${INCLUDE_DIRS}) +target_link_libraries(galaxy-engine galaxy-engine-lib bgfx glfw) + + + +# Testing +enable_testing() + +set(TESTING_SOURCES + test/todo.cpp + ${SOURCES} +) + +add_executable(tests ${TESTING_SOURCES}) + +target_link_libraries( + tests + GTest::gtest_main + bgfx + glfw +) + +target_include_directories(tests PRIVATE include ${INCLUDE_DIRS}) +include(GoogleTest) +gtest_discover_tests(tests) diff --git a/include/env-vars.h.in b/include/env-vars.h.in new file mode 100644 index 0000000..8178e5d --- /dev/null +++ b/include/env-vars.h.in @@ -0,0 +1,3 @@ +#pragma once + +#define GALAXY_SHADER_BIN_DIR "@GALAXY_SHADER_BIN_DIR@" diff --git a/include/galaxy.h b/include/galaxy.h new file mode 100644 index 0000000..a058249 --- /dev/null +++ b/include/galaxy.h @@ -0,0 +1,23 @@ +#pragma once + +#include "gshader.h" +#include "grenderer.h" +#include "gwindow.h" +#include "logger.h" + +class Galaxy { +public: + Galaxy(); + ~Galaxy(); + Galaxy(GWindow *w, GRenderer *r, Logger *l) + : window(w), renderer(r), logger(l) {}; + void init(); + void run(); + +private: + Logger *logger; + GWindow *window; + GRenderer *renderer; +}; + +static void glfw_errorCallback(int error, const char *description); diff --git a/include/grenderer.h b/include/grenderer.h new file mode 100644 index 0000000..1c3b54a --- /dev/null +++ b/include/grenderer.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "gwindow.h" +#include "logger.h" +#include "vertex.h" + +class GRenderer { +public: + GRenderer(GWindow *w, Logger *l); + ~GRenderer(); + void init(); + void update(); + +private: + Logger *logger; + GWindow *window; + + bgfx::ShaderHandle vsh; + bgfx::ShaderHandle fsh; + bgfx::ProgramHandle program; + + bgfx::VertexBufferHandle vbh; + bgfx::IndexBufferHandle ibh; + std::vector *vertexes; + std::vector *tri_list; + + bgfx::VertexLayout layout; + + void bgfx_init(); + void shader_init(); + bgfx::ShaderHandle load_shader(const char *name); +}; diff --git a/include/gshader.h b/include/gshader.h new file mode 100644 index 0000000..2c018fe --- /dev/null +++ b/include/gshader.h @@ -0,0 +1,16 @@ +#pragma once +#include "bgfx/bgfx.h" + +#include "logger.h" + +class GShader { +public: + GShader(Logger *l) : logger(l) {}; + ~GShader() {}; + void init(); + + bgfx::ShaderHandle loadShader(const char *name); + +private: + Logger *logger; +}; diff --git a/include/gwindow.h b/include/gwindow.h new file mode 100644 index 0000000..0302541 --- /dev/null +++ b/include/gwindow.h @@ -0,0 +1,23 @@ +#pragma once + +#include "GLFW/glfw3.h" + +#include "logger.h" + +class GWindow { +public: + GWindow(int w, int h, Logger *l) : width(w), height(h), logger(l) {}; + ~GWindow(); + void init(); + void processInput(); + + GLFWwindow *getWindow() { return window; }; + int getWidth() const { return width; } + int getHeight() const { return height; } + +private: + int width; + int height; + Logger *logger; + GLFWwindow *window; +}; diff --git a/include/logger.h b/include/logger.h new file mode 100644 index 0000000..470fe7d --- /dev/null +++ b/include/logger.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +// TODO add log levels => for ex. display only info and errors +#define LOG_INFO(x) this->logger->info(x); +#define LOG_DEBUG(x) this->logger->debug(x); +#define LOG_ERROR(x) this->logger->error(x); +#define LOG_WARN(x) this->logger->warn(x); + +class Logger { +public: + Logger(); + Logger(std::ostream *l); + Logger(const Logger &old_logger); + void info(const std::string msg); + void debug(const std::string msg); + void error(const std::string msg); + void warn(const std::string msg); + +private: + std::ostream *outputDest; +}; diff --git a/include/vertex.h b/include/vertex.h new file mode 100644 index 0000000..3771e20 --- /dev/null +++ b/include/vertex.h @@ -0,0 +1,24 @@ +#pragma once + +#include "bgfx/bgfx.h" +#include + +class PosColVertex { +public: + PosColVertex(float x, float y, float z, uint32_t abgr) + : x(x), y(y), z(z), abgr(abgr) { + this->init(); + }; + ~PosColVertex() {}; + void init(); + bgfx::VertexLayout getLayout() { return this->layout; }; + +private: + float x; + float y; + float z; + + uint32_t abgr; + + bgfx::VertexLayout layout; +}; diff --git a/src/galaxy.cpp b/src/galaxy.cpp new file mode 100644 index 0000000..94faf55 --- /dev/null +++ b/src/galaxy.cpp @@ -0,0 +1,46 @@ +#include "logger.h" +#include "galaxy.h" + +const int W_WIDTH = 800; +const int W_HEIGHT = 600; + +Galaxy::Galaxy() { + Logger *logger = new Logger(&std::cout); + this->logger = logger; + LOG_INFO("Starting the engine..."); + + GWindow *window = new GWindow(W_WIDTH, W_HEIGHT, logger); + GRenderer *renderer = new GRenderer(window, logger); + + this->window = window; + this->renderer = renderer; + + LOG_DEBUG("Done creating new things."); +} + +Galaxy::~Galaxy() { + LOG_INFO("Shutting down the engine..."); + + delete this->renderer; + delete this->window; + delete this->logger; +} + +void Galaxy::init() { + LOG_DEBUG("Initializing the engine..."); + this->window->init(); + this->renderer->init(); +} + +void Galaxy::run() { + LOG_DEBUG("Running the main loop..."); + + unsigned int counter = 0; + while (!glfwWindowShouldClose(this->window->getWindow())) { + this->window->processInput(); + this->renderer->update(); + + glfwPollEvents(); + counter++; + } +} diff --git a/src/grenderer.cpp b/src/grenderer.cpp new file mode 100644 index 0000000..1d3669b --- /dev/null +++ b/src/grenderer.cpp @@ -0,0 +1,227 @@ +#define BX_CONFIG_DEBUG 0 +#include "bgfx/bgfx.h" +#include "bgfx/platform.h" +#include "bx/math.h" +#include +#include +#include +#include + +#include "GLFW/glfw3.h" +#define GLFW_EXPOSE_NATIVE_X11 +#include "GLFW/glfw3native.h" + +#include "env-vars.h" +#include "grenderer.h" +#include "logger.h" + +static PosColVertex st_vertexes[] = +{ + {-1.0f, 1.0f, 1.0f, 0xff000000 }, + { 1.0f, 1.0f, 1.0f, 0xff0000ff }, + {-1.0f, -1.0f, 1.0f, 0xff00ff00 }, + { 1.0f, -1.0f, 1.0f, 0xff00ffff }, + {-1.0f, 1.0f, -1.0f, 0xffff0000 }, + { 1.0f, 1.0f, -1.0f, 0xffff00ff }, + {-1.0f, -1.0f, -1.0f, 0xffffff00 }, + { 1.0f, -1.0f, -1.0f, 0xffffffff }, +}; + +static const uint16_t st_tri_list[] = +{ + 0, 1, 2, + 1, 3, 2, + 4, 6, 5, + 5, 6, 7, + 0, 2, 4, + 4, 2, 6, + 1, 5, 3, + 5, 7, 3, + 0, 4, 1, + 4, 5, 1, + 2, 3, 6, + 6, 3, 7, +}; + + +GRenderer::GRenderer(GWindow *w, Logger *l) : window(w), logger(l) { + // TODO this is obviously static data + static std::vector vertexes = {{0.5f, 0.5f, 0.0f, 0xff0000ff}, + {0.5f, -0.5f, 0.0f, 0xff0000ff}, + {-0.5f, -0.5f, 0.0f, 0xff00ff00}, + {-0.5f, 0.5f, 0.0f, 0xff00ff00}}; + static std::vector tri_list = {0, 1, 3, 1, 2, 3}; + + this->vertexes = &vertexes; + this->tri_list = &tri_list; +} + +GRenderer::~GRenderer() { + LOG_DEBUG("Shutting down renderer..."); + bgfx::shutdown(); +} + +void GRenderer::init() { + LOG_DEBUG("Initializing the GRenderer..."); + this->bgfx_init(); + this->shader_init(); +} + +void GRenderer::bgfx_init() { + // Call bgfx::renderFrame before bgfx::init to signal to bgfx not to create a + // render thread. Most graphics APIs must be used on the same thread that + // created the window. + bgfx::renderFrame(); + + bgfx::PlatformData pd; + pd.ndt = glfwGetX11Display(); + pd.nwh = (void *)(uintptr_t)glfwGetX11Window(this->window->getWindow()); + + bgfx::Init init; + init.type = bgfx::RendererType::Count; + init.resolution.width = this->window->getWidth(); + init.resolution.height = this->window->getHeight(); + init.resolution.reset = BGFX_RESET_VSYNC; + init.platformData = pd; + + if (bgfx::init(init) != true) { + LOG_ERROR("Failed to initialize bgfx."); + glfwTerminate(); + throw std::runtime_error("Failed to initialize bgfx."); + } + + /* + bgfx::setDebug(BGFX_DEBUG_TEXT); + bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x443355FF, 1.0f, + 0); + bgfx::setViewRect(0, 0, 0, this->window->getWidth(), + this->window->getHeight()); + + bgfx::touch(0); + */ + + // Todo move this to some fancy class + static bgfx::VertexLayout layout; + this->layout = layout; + + this->layout.begin() + .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) + .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) + .end(); +} + +void GRenderer::shader_init() { + LOG_DEBUG("Loading shaders..."); + + LOG_DEBUG("Galaxy shader bin: " GALAXY_SHADER_BIN_DIR); + + const char *path_v = GALAXY_SHADER_BIN_DIR "/glsl/v_simple.sc.bin"; + const char *path_f = GALAXY_SHADER_BIN_DIR "/glsl/f_simple.sc.bin"; + + this->vsh = this->load_shader(path_v); + this->fsh = this->load_shader(path_f); + + this->vbh = bgfx::createVertexBuffer( + // bgfx::makeRef(this->vertexes, sizeof(*this->vertexes)), this->layout); + bgfx::makeRef(&st_vertexes, sizeof(st_vertexes)), this->layout); + + this->ibh = bgfx::createIndexBuffer( + // bgfx::makeRef(this->tri_list, sizeof(*this->tri_list))); + bgfx::makeRef(&st_tri_list, sizeof(st_tri_list))); + + this->program = bgfx::createProgram(this->vsh, this->fsh, true); + + // Reset window + bgfx::reset(this->window->getWidth(), this->window->getHeight(), BGFX_RESET_VSYNC); + + // Enable debug text. + bgfx::setDebug(BGFX_DEBUG_TEXT /*| BGFX_DEBUG_STATS*/); + + // Set view rectangle for 0th view + bgfx::setViewRect(0, 0, 0, uint16_t(this->window->getWidth()), uint16_t(this->window->getHeight())); + + // Clear the view rect + bgfx::setViewClear(0, + BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, + 0x443355FF, 1.0f, 0); +} + +bgfx::ShaderHandle GRenderer::load_shader(const char *name) { + char *data = new char[4098]; + std::ifstream file; + size_t file_size; + + file.open(name); + if (file.is_open()) { + // Get file size + file.seekg(0, std::ios::end); + file_size = file.tellg(); + + file.seekg(0, std::ios::beg); + file.read(data, file_size); + + file.close(); + } else { + delete[] data; + throw std::runtime_error(std::string("Failed to open shader file: ") + + std::string(name)); + } + + // create bgfx::Memory object and create shader from it + const bgfx::Memory *mem = bgfx::copy(data, file_size + 1); + mem->data[mem->size - 1] = '\0'; + bgfx::ShaderHandle handle = bgfx::createShader(mem); + bgfx::setName(handle, name); + + delete[] data; + return handle; +} + +void GRenderer::update() { + LOG_DEBUG("Starting rendening update loop..."); + + const bx::Vec3 at = {0.0f, 0.0f, 0.0f}; + const bx::Vec3 eye = {0.0f, 0.0f, 10.0f}; + + // Set view and projection matrix for view 0. + float view[16]; + bx::mtxLookAt(view, eye, at); + + float proj[16]; + bx::mtxProj(proj, 60.0f, + float(this->window->getWidth()) / + float(this->window->getHeight()), + 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth); + + bgfx::setViewTransform(0, view, proj); + + // Set view 0 default viewport. + bgfx::setViewRect(0, 0, 0, this->window->getWidth(), + this->window->getHeight()); + + bgfx::touch(0); + + float mtx[16]; + bx::mtxRotateY(mtx, 0.0f); + + // position x,y,z + mtx[12] = 0.0f; + mtx[13] = 0.0f; + mtx[14] = 0.0f; + + // Set model matrix for rendering. + bgfx::setTransform(mtx); + + // Set vertex and index buffer. + bgfx::setVertexBuffer(0, this->vbh); + bgfx::setIndexBuffer(this->ibh); + + // Set render states. + bgfx::setState(BGFX_STATE_DEFAULT); + + // Submit primitive for rendering to view 0. + bgfx::submit(0, this->program); + + LOG_DEBUG("Rendering..."); + bgfx::frame(); +} diff --git a/src/gshader.cpp b/src/gshader.cpp new file mode 100644 index 0000000..e01cfc1 --- /dev/null +++ b/src/gshader.cpp @@ -0,0 +1,10 @@ +#include +#include + +#include "bgfx/bgfx.h" + +#include "logger.h" +#include "gshader.h" + +void GShader::init() { +}; diff --git a/src/gwindow.cpp b/src/gwindow.cpp new file mode 100644 index 0000000..e62d3f6 --- /dev/null +++ b/src/gwindow.cpp @@ -0,0 +1,40 @@ +#include "GLFW/glfw3.h" + +#include "gwindow.h" + +// TODO change this to utilize Logger +static void glfw_errorCallback(int error, const char *description) { + fprintf(stderr, "GLFW error, %d: %s\n", error, description); +} + +void GWindow::init() { + LOG_DEBUG("Initializing the GWindow..."); + glfwSetErrorCallback(glfw_errorCallback); + + glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11); + if (!glfwInit()) { + LOG_ERROR("Failed to initialize GLFW."); // TODO move to caller + throw std::runtime_error("Failed to initialize GLFW."); + } + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + + this->window = + glfwCreateWindow(this->width, this->height, "Galaxy-engine", NULL, NULL); + + if (this->window == NULL) { + LOG_ERROR("Failed to create GLFW window."); // TODO move to caller + glfwTerminate(); + throw std::runtime_error("Failed to create GLFW window."); + } +} + +GWindow::~GWindow() { + LOG_DEBUG("Shutting down glfw window..."); + glfwTerminate(); +} + +void GWindow::processInput() { + if (glfwGetKey(this->getWindow(), GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(this->getWindow(), true); +} diff --git a/src/logger.cpp b/src/logger.cpp new file mode 100644 index 0000000..ded25d7 --- /dev/null +++ b/src/logger.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include "logger.h" + +#define TERMINAL_COLOR_PRE(col) "\033[" #col "m" +#define TERMINAL_COLOR_END "\033[0m" + +Logger::Logger() : outputDest(&std::cout) {} +Logger::Logger(std::ostream *oDest) : outputDest(oDest) {} +Logger::Logger(const Logger &old_logger) { + this->outputDest = old_logger.outputDest; +} + +void Logger::info(const std::string msg) { + *(this->outputDest) << TERMINAL_COLOR_PRE(36) << "[INFO]\t" + << TERMINAL_COLOR_END << msg << std::endl; +} + +void Logger::debug(const std::string msg) { + *(this->outputDest) << TERMINAL_COLOR_PRE(35) << "[DEBUG]\t" + << TERMINAL_COLOR_END << msg << std::endl; +} + +void Logger::error(const std::string msg) { + *(this->outputDest) << TERMINAL_COLOR_PRE(31) << "[ERROR]\t" + << TERMINAL_COLOR_END << msg << std::endl; +} + +void Logger::warn(const std::string msg) { + *(this->outputDest) << TERMINAL_COLOR_PRE(33) << "[WARN]\t" + << TERMINAL_COLOR_END << msg << std::endl; +} diff --git a/src/main.cpp b/src/main.cpp index b332dc9..13226f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,94 +1,8 @@ -#include +#include "galaxy.h" -#define BX_CONFIG_DEBUG 1 -#include "bx/bx.h" -#include "bgfx/bgfx.h" -#include "bgfx/platform.h" - -#include "GLFW/glfw3.h" - -#define GLFW_EXPOSE_NATIVE_X11 -#include "GLFW/glfw3native.h" - -const int W_WIDTH = 800; -const int W_HEIGHT = 600; - - -static void glfw_errorCallback(int error, const char *description) -{ - fprintf(stderr, "GLFW error, %d: %s\n", error, description); +int main(int argc, char *args[]) { + Galaxy engine = Galaxy(); + engine.init(); + engine.run(); + return 0; } - - -void processInput(GLFWwindow *window) -{ - if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) - glfwSetWindowShouldClose(window, true); -} - -int main (int argc, char* args[]) -{ - std::cout << "Starting the engine..." << std::endl; - glfwSetErrorCallback(glfw_errorCallback); - - glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11); - if (!glfwInit()) - { - std::cout << "Failed to initialize GLFW" << std::endl; - return -1; - } - - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - - GLFWwindow* window = glfwCreateWindow(W_WIDTH, W_HEIGHT, "Galaxy-engine", NULL, NULL); - if (window == NULL) - { - std::cout << "Failed to create GLFW window" << std::endl; - glfwTerminate(); - return -1; - } - - // Call bgfx::renderFrame before bgfx::init to signal to bgfx not to create a render thread. - // Most graphics APIs must be used on the same thread that created the window. - bgfx::renderFrame(); - - - bgfx::PlatformData pd; - pd.ndt = glfwGetX11Display(); - pd.nwh = (void *)(uintptr_t) glfwGetX11Window(window); - - bgfx::Init init; - init.type = bgfx::RendererType::Count; - init.resolution.width = W_WIDTH; - init.resolution.height = W_HEIGHT; - init.resolution.reset = BGFX_RESET_VSYNC; - init.platformData = pd; - - if (bgfx::init(init) != true) - { - std::cout << "Failed to initialize bgfx" << std::endl; - glfwTerminate(); - return -1; - } - - bgfx::setDebug(BGFX_DEBUG_TEXT); - bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x443355FF, 1.0f, 0); - bgfx::setViewRect(0, 0, 0, W_WIDTH, W_HEIGHT); - - std::cout << "Initialization done." << std::endl; - - while(!glfwWindowShouldClose(window)) - { - processInput(window); - - bgfx::touch(0); - bgfx::frame(); - glfwPollEvents(); - } - - - bgfx::shutdown(); - glfwTerminate(); - return 0; -} - diff --git a/src/shaders/f_simple.sc b/src/shaders/f_simple.sc new file mode 100644 index 0000000..caf3e81 --- /dev/null +++ b/src/shaders/f_simple.sc @@ -0,0 +1,8 @@ +$input v_color0 + +#include + +void main() +{ + gl_FragColor = v_color0; +} diff --git a/src/shaders/v_simple.sc b/src/shaders/v_simple.sc new file mode 100644 index 0000000..56b8736 --- /dev/null +++ b/src/shaders/v_simple.sc @@ -0,0 +1,10 @@ +$input a_position, a_color0 +$output v_color0 + +#include + +void main() +{ + gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0)); + v_color0 = a_color0; +} diff --git a/src/shaders/varying.def.sc b/src/shaders/varying.def.sc new file mode 100644 index 0000000..74d0395 --- /dev/null +++ b/src/shaders/varying.def.sc @@ -0,0 +1,4 @@ +vec4 v_color0 : COLOR0; + +vec3 a_position : POSITION; +vec4 a_color0 : COLOR0; diff --git a/src/todo.cpp b/src/todo.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/vertex.cpp b/src/vertex.cpp new file mode 100644 index 0000000..16d4158 --- /dev/null +++ b/src/vertex.cpp @@ -0,0 +1,10 @@ +#include "bgfx/bgfx.h" + +#include "vertex.h" + +void PosColVertex::init() { + this->layout.begin() + .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) + .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) + .end(); +} diff --git a/test/todo.cpp b/test/todo.cpp new file mode 100644 index 0000000..e69de29