From 6073e7d3f64997338e8c86a663c0cad28c4dd082 Mon Sep 17 00:00:00 2001 From: Mario1159 Date: Fri, 28 Jul 2023 21:56:18 -0400 Subject: [PATCH] Initial commit --- .gitignore | 1 + .gitmodules | 6 + CMakeLists.txt | 67 ++++++++++ cmake/bgfx_shaders.cmake | 57 +++++++++ examples/0_hello_world/CMakeLists.txt | 6 + examples/0_hello_world/main.cpp | 25 ++++ examples/1_double_pendulum/CMakeLists.txt | 5 + examples/1_double_pendulum/main.cpp | 30 +++++ examples/CMakeLists.txt | 2 + src/core/app.cpp | 34 +++++ src/core/app.hpp | 31 +++++ src/core/event.cpp | 13 ++ src/core/event.hpp | 33 +++++ src/ec/comp/sprite_component.cpp | 21 ++++ src/ec/comp/sprite_component.hpp | 24 ++++ src/ec/component.hpp | 16 +++ src/ec/entity.hpp | 44 +++++++ src/gfx/renderer.cpp | 146 ++++++++++++++++++++++ src/gfx/renderer.hpp | 70 +++++++++++ src/gfx/shader/mesh/mesh.fsh | 5 + src/gfx/shader/mesh/mesh.vsh | 9 ++ src/gfx/shader/varying.def.sc | 10 ++ src/gfx/texture.hpp | 9 ++ src/gfx/vertex.hpp | 49 ++++++++ src/util/color.cpp | 9 ++ src/util/color.hpp | 54 ++++++++ src/util/n_ary_tree.hpp | 47 +++++++ src/util/n_ary_tree.tpp | 99 +++++++++++++++ src/util/vector.hpp | 62 +++++++++ src/weasel.hpp | 5 + src/win/system_events.cpp | 14 +++ src/win/system_events.hpp | 31 +++++ src/win/window.cpp | 33 +++++ src/win/window.hpp | 37 ++++++ vendor/CrossWindow | 1 + vendor/bgfx.cmake | 1 + 36 files changed, 1106 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 cmake/bgfx_shaders.cmake create mode 100644 examples/0_hello_world/CMakeLists.txt create mode 100644 examples/0_hello_world/main.cpp create mode 100644 examples/1_double_pendulum/CMakeLists.txt create mode 100644 examples/1_double_pendulum/main.cpp create mode 100644 examples/CMakeLists.txt create mode 100644 src/core/app.cpp create mode 100644 src/core/app.hpp create mode 100644 src/core/event.cpp create mode 100644 src/core/event.hpp create mode 100644 src/ec/comp/sprite_component.cpp create mode 100644 src/ec/comp/sprite_component.hpp create mode 100644 src/ec/component.hpp create mode 100644 src/ec/entity.hpp create mode 100644 src/gfx/renderer.cpp create mode 100644 src/gfx/renderer.hpp create mode 100644 src/gfx/shader/mesh/mesh.fsh create mode 100644 src/gfx/shader/mesh/mesh.vsh create mode 100644 src/gfx/shader/varying.def.sc create mode 100644 src/gfx/texture.hpp create mode 100644 src/gfx/vertex.hpp create mode 100644 src/util/color.cpp create mode 100644 src/util/color.hpp create mode 100644 src/util/n_ary_tree.hpp create mode 100644 src/util/n_ary_tree.tpp create mode 100644 src/util/vector.hpp create mode 100644 src/weasel.hpp create mode 100644 src/win/system_events.cpp create mode 100644 src/win/system_events.hpp create mode 100644 src/win/window.cpp create mode 100644 src/win/window.hpp create mode 160000 vendor/CrossWindow create mode 160000 vendor/bgfx.cmake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..267ef27 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "vendor/bgfx.cmake"] + path = vendor/bgfx.cmake + url = https://github.com/bkaradzic/bgfx.cmake +[submodule "vendor/CrossWindow"] + path = vendor/CrossWindow + url = https://github.com/alaingalvan/CrossWindow diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..80c7a39 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,67 @@ +cmake_minimum_required(VERSION 3.14) + +project(weasel) + +include(cmake/bgfx_shaders.cmake) + +set(SOURCE_FILES + weasel.hpp + core/app.hpp + core/app.cpp + core/event.hpp + core/event.cpp + ec/entity.hpp + ec/component.hpp + ec/comp/sprite_component.hpp + ec/comp/sprite_component.cpp + gfx/renderer.hpp + gfx/renderer.cpp + gfx/texture.hpp + gfx/vertex.hpp + util/color.hpp + util/color.cpp + util/n_ary_tree.hpp + util/n_ary_tree.tpp + util/vector.hpp + win/system_events.hpp + win/system_events.cpp + win/window.hpp + win/window.cpp +) + +list(TRANSFORM SOURCE_FILES PREPEND src/) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +add_subdirectory(vendor/CrossWindow) +add_subdirectory(vendor/bgfx.cmake) + +add_shader_cmd( + FILE ${CMAKE_CURRENT_SOURCE_DIR}/src/gfx/shader/mesh/mesh.vsh + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/shader/mesh.vsh.bin + TYPE VERTEX) + +add_shader_cmd( + FILE ${CMAKE_CURRENT_SOURCE_DIR}/src/gfx/shader/mesh/mesh.fsh + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/shader/mesh.fsh.bin + TYPE FRAGMENT) + +add_custom_target(compile_shaders ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/shader/mesh.vsh.bin ${CMAKE_CURRENT_BINARY_DIR}/shader/mesh.fsh.bin) + +add_library(weasel ${SOURCE_FILES}) + +target_include_directories(weasel PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) + +target_compile_features(weasel PUBLIC cxx_std_17) + +target_link_libraries(weasel CrossWindow bgfx bx) + + +if(WIN32) + target_link_libraries(weasel + Dwmapi) +endif() + +target_compile_definitions(CrossWindow PRIVATE _WIN32_WINNT=0x0A00) + +add_subdirectory(examples) \ No newline at end of file diff --git a/cmake/bgfx_shaders.cmake b/cmake/bgfx_shaders.cmake new file mode 100644 index 0000000..f9fa5cc --- /dev/null +++ b/cmake/bgfx_shaders.cmake @@ -0,0 +1,57 @@ +# Configure a command to compile a single shader +# add_shader_cmd( +# FILE file +# OUTPUT output +# TYPE type +#) +function (add_shader_cmd) + cmake_parse_arguments(SHADER "" "FILE;OUTPUT;TYPE;LANG" "" ${ARGN}) + message(${SHADER_FILE} ${SHADER_OUTPUT} ${SHADER_TYPE} ${SHADER_LANG}) + + set(BGFX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/vendor/bgfx.cmake/bgfx) + set(VARYING_DEF "C:/Users/romer/Documents/Projects/weasel/src/gfx/shader/varying.def.sc") + + message("checking platform") + if(WIN32) + set(SHADERC_PLATFORM_ARG WINDOWS) + message("platform = " ${SHADERC_PLATFORM_ARG}) + elseif(APPLE) + set(SHADERC_PLATFORM_ARG OSX) + elseif(UNIX) + set(SHADERC_PLATFORM_ARG LINUX) + endif() + + # shaderc_parse( + # FILE filename + # OUTPUT filename + # FRAGMENT|VERTEX|COMPUTE + # ANDROID|ASM_JS|IOS|LINUX|NACL|OSX|WINDOWS + # [PROFILE profile] + # [O 0|1|2|3] + # [VARYINGDEF filename] + # [BIN2C filename] + # [INCLUDES include;include] + # [DEFINES include;include] + # [DEPENDS] + # [PREPROCESS] + # [RAW] + # [VERBOSE] + # [DEBUG] + # [DISASM] + # [WERROR] + # ) + shaderc_parse(SHADERC_ARGS + FILE ${SHADER_FILE} + OUTPUT ${SHADER_OUTPUT} + ${SHADER_TYPE} + ${SHADERC_PLATFORM_ARG} + PROFILE ${SHADER_LANG} + VARYINGDEF ${VARYING_DEF} + INCLUDES ${BGFX_PATH}/src + ) + + list( APPEND SHADER_COMPILE_CMD shaderc ${SHADERC_ARGS} ) + add_custom_command( + OUTPUT ${SHADER_OUTPUT} + COMMAND ${SHADER_COMPILE_CMD}) +endfunction() \ No newline at end of file diff --git a/examples/0_hello_world/CMakeLists.txt b/examples/0_hello_world/CMakeLists.txt new file mode 100644 index 0000000..1f51c32 --- /dev/null +++ b/examples/0_hello_world/CMakeLists.txt @@ -0,0 +1,6 @@ +project(example_0_hello_world) + +add_executable(${PROJECT_NAME} main.cpp) + +target_link_libraries(${PROJECT_NAME} weasel) +#target_link_directories(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/src) \ No newline at end of file diff --git a/examples/0_hello_world/main.cpp b/examples/0_hello_world/main.cpp new file mode 100644 index 0000000..23c8a1a --- /dev/null +++ b/examples/0_hello_world/main.cpp @@ -0,0 +1,25 @@ +#include + +class hello_world : public wsl::app { + public: + void init() override { + wsl::entity::entity e; + hierarchy.root.add_child(e); + hierarchy.root.add_child(e); + hierarchy.root.add_child(e); + hierarchy.root.child_at(0).add_child(e); + + renderer.draw_test_triangle(); + window.internal_window.get()->setSize(640,480); + } + + void update() override { + renderer.draw(); + } +}; + +int main() { + hello_world app; + app.start("Hello World", 640, 480); + return 0; +} \ No newline at end of file diff --git a/examples/1_double_pendulum/CMakeLists.txt b/examples/1_double_pendulum/CMakeLists.txt new file mode 100644 index 0000000..6bb96d0 --- /dev/null +++ b/examples/1_double_pendulum/CMakeLists.txt @@ -0,0 +1,5 @@ +project(example_1_double_pendulum) + +add_executable(${PROJECT_NAME} main.cpp) + +target_link_libraries(${PROJECT_NAME} weasel) \ No newline at end of file diff --git a/examples/1_double_pendulum/main.cpp b/examples/1_double_pendulum/main.cpp new file mode 100644 index 0000000..ca8fa7c --- /dev/null +++ b/examples/1_double_pendulum/main.cpp @@ -0,0 +1,30 @@ +#include + +class double_pendulum : public wsl::app { + public: + void init() override { + wsl::entity::entity e; + hierarchy.root.add_child(e); + hierarchy.root.add_child(e); + hierarchy.root.add_child(e); + hierarchy.root.child_at(0).add_child(e); + + renderer.queue_triangle( + wsl::vec2f{320.0f, 480.0f}, + wsl::vec2f{0.0f, 0.0f}, + wsl::vec2f{640.0f, 0.0f}, + wsl::color::red + ); + window.internal_window.get()->setSize(640,480); + } + + void update() override { + renderer.draw(); + } +}; + +int main() { + double_pendulum app; + app.start("Double Pendulum", 640, 480); + return 0; +} \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..1e19954 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(0_hello_world) +add_subdirectory(1_double_pendulum) \ No newline at end of file diff --git a/src/core/app.cpp b/src/core/app.cpp new file mode 100644 index 0000000..b943f25 --- /dev/null +++ b/src/core/app.cpp @@ -0,0 +1,34 @@ +#include "core/app.hpp" + +wsl::app::app() : renderer(&window), hierarchy(wsl::entity::entity{}) {} + +void wsl::app::start(const char* title, unsigned int width, + unsigned int height) { + if (window.init(title, width, height) && renderer.init(wsl::gfx::api::opengl)) { + is_running = true; + window.events.quit.add_listener([&]() { + window.close(); + is_running = false; + }); + init(); + init_entities(); + while (is_running) { + renderer.clear(color::solid{0x00, 0x00, 0x00}); + window.events.update(); + update(); + update_entities(); + renderer.update(); + } + } else + std::cout << "error opening window" << std::endl; +} + +void wsl::app::init_entities() { + for (wsl::n_ary_tree::node& leaf : hierarchy) { + std::cout << &leaf << ": " << leaf.value.uid << std::endl; + } +} + +void wsl::app::update_entities() { + +} \ No newline at end of file diff --git a/src/core/app.hpp b/src/core/app.hpp new file mode 100644 index 0000000..fb72efb --- /dev/null +++ b/src/core/app.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "gfx/renderer.hpp" +#include "win/window.hpp" +#include "util/n_ary_tree.hpp" +#include "ec/entity.hpp" + +namespace wsl { + +class app { + public: + app(); + window window; + gfx::renderer renderer; + + void start(const char* title, unsigned int width, unsigned int height); + + wsl::n_ary_tree hierarchy; + protected: + virtual void init() = 0; + virtual void update() = 0; + void init_entities(); + void update_entities(); + + private: + bool is_running; +}; + +} // namespace wsl \ No newline at end of file diff --git a/src/core/event.cpp b/src/core/event.cpp new file mode 100644 index 0000000..2793964 --- /dev/null +++ b/src/core/event.cpp @@ -0,0 +1,13 @@ +#include "core/event.hpp" + +void wsl::event::event::add_listener(std::function callback_fn) { + listeners.push_back(callback_fn); +} + +void wsl::event::event::update() { + if (dispatch_condition()) dispatch(); +} + +void wsl::event::event::dispatch() { + for (std::function fn : listeners) fn(); +} \ No newline at end of file diff --git a/src/core/event.hpp b/src/core/event.hpp new file mode 100644 index 0000000..a6fface --- /dev/null +++ b/src/core/event.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +namespace wsl { + +namespace event { + +class event { + public: + void add_listener(std::function callback_fn); + + /** + * @brief Check if event meet the requirement to notify the listening + * functions + */ + void update(); + + protected: + virtual bool dispatch_condition() = 0; + + private: + std::vector> listeners; + /** + * @brief Fire up the event and invoke the listening functions + */ + void dispatch(); +}; + +} // namespace event + +} // namespace wsl \ No newline at end of file diff --git a/src/ec/comp/sprite_component.cpp b/src/ec/comp/sprite_component.cpp new file mode 100644 index 0000000..15c589b --- /dev/null +++ b/src/ec/comp/sprite_component.cpp @@ -0,0 +1,21 @@ +#include +#include + +#include +#include +#include +#include + +#include "util/color.hpp" +#include "util/vector.hpp" +#include "win/window.hpp" + +#include "sprite_component.hpp" + +void wsl::entity::comp::sprite::init() { + //renderer.draw_sprite() +} + +void wsl::entity::comp::sprite::update(double delta_time) {} + +void wsl::entity::comp::sprite::render() {} \ No newline at end of file diff --git a/src/ec/comp/sprite_component.hpp b/src/ec/comp/sprite_component.hpp new file mode 100644 index 0000000..9f103ad --- /dev/null +++ b/src/ec/comp/sprite_component.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "ec/component.hpp" +#include "gfx/renderer.hpp" + +namespace wsl { + +namespace entity { + +namespace comp { + +class sprite : component { + public: + gfx::renderer renderer; + void init(); + + void update(double delta_time); + void render(); +}; + +} // namespace comp +} // namespace entity + +} // namespace wsl \ No newline at end of file diff --git a/src/ec/component.hpp b/src/ec/component.hpp new file mode 100644 index 0000000..b28323d --- /dev/null +++ b/src/ec/component.hpp @@ -0,0 +1,16 @@ +#pragma once + +namespace wsl { + +namespace entity { + +class component { + public: + virtual void init() = 0; + virtual void update(double delta_time) = 0; + virtual void render() = 0; +}; + +} // namespace entity + +} // namespace wsl \ No newline at end of file diff --git a/src/ec/entity.hpp b/src/ec/entity.hpp new file mode 100644 index 0000000..4ad9035 --- /dev/null +++ b/src/ec/entity.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +#include "ec/component.hpp" + +namespace wsl { + +namespace entity { + +class entity { + public: + const unsigned long uid = get_new_uid(); + static unsigned long get_new_uid() { return last_uid++; } + + template + void add_component(Args... args) { + components.push_back(std::make_shared(args...)); + } + + void init() { + for (std::shared_ptr component : components) + component->init(); + } + + void update(double delta_time) { + for (std::shared_ptr component : components) + component->update(delta_time); + } + + void render() { + for (std::shared_ptr component : components) + component->render(); + } + + private: + inline static unsigned long last_uid = 0; + std::vector> components; +}; + +} // namespace entity + +} // namespace wsl \ No newline at end of file diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp new file mode 100644 index 0000000..7504f8e --- /dev/null +++ b/src/gfx/renderer.cpp @@ -0,0 +1,146 @@ +#include "renderer.hpp" + +bool wsl::gfx::renderer::init(api graphics_api) { + bgfx::Init bgfx_init; + bgfx_init.platformData.nwh = window->internal_window->getHwnd(); + this->graphics_api = graphics_api; + bgfx_init.type = bgfx_renderer_type(graphics_api); + xwin::UVec2 window_size = window->internal_window->getWindowSize(); + // bgfx_init.resolution.width = window_size.x; + // bgfx_init.resolution.height = window_size.y; + bgfx_init.resolution.width = 640; + bgfx_init.resolution.height = 480; + bgfx_init.resolution.reset = BGFX_RESET_VSYNC; + return bgfx::init(bgfx_init); +} + +void wsl::gfx::renderer::clear(color::solid clear_color) { + bgfx::touch(0); + bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, clear_color, + 1.0f, 0); + vec2u size = window->size(); + bgfx::setViewRect(0, 0, 0, size.x, size.y); +} + +void wsl::gfx::renderer::update() { bgfx::frame(); } + +void wsl::gfx::renderer::draw() { + std::cout << "draw call" << std::endl; + + vec2u size = window->size(); + float view[16], proj[16]; + bx::mtxIdentity(view); + bx::mtxOrtho(proj, 0.0f, size.x, 0.0f, size.y, -1.0f, 1.0f, 0.0f, false); + bgfx::setViewTransform(0, view, proj); + + bgfx::setVertexBuffer(0, vbo, 0, 8); + bgfx::setIndexBuffer(ibo, 0, 3); + bgfx::setState(BGFX_STATE_DEFAULT); + bgfx::submit(0, program, 0, BGFX_DISCARD_ALL); +} + +void wsl::gfx::renderer::queue_triangle(vec2f point_1, vec2f point_2, + vec2f point_3, + color::solid fill_color) { + bgfx::VertexLayout vertex_layout; + + triangle = new gfx::vsh::triangle( + vec3f{320.0f, 480.0f, 0.0f}, (vec4f)(color::transparent)fill_color, + vec3f{0.0f, 0.0f, 0.0f}, (vec4f)(color::transparent)fill_color, + vec3f{640.0f, 0.0f, 0.0f}, (vec4f)(color::transparent)fill_color); + + vertex_layout.begin(bgfx_renderer_type(graphics_api)); + vertex_layout.add(bgfx::Attrib::Enum::Position, 3, + bgfx::AttribType::Enum::Float); + vertex_layout.add(bgfx::Attrib::Enum::Color0, 4, + bgfx::AttribType::Enum::Float); + vertex_layout.end(); + + vbo = create_vertex_buffer(triangle->vertices, triangle->size(), vertex_layout); + ibo = create_index_buffer(indices, sizeof(indices)); + + program = + bgfx::createProgram(load_shader("C:/Users/romer/Documents/Projects/" + "weasel/build/shader/mesh.vsh.bin"), + load_shader("C:/Users/romer/Documents/Projects/" + "weasel/build/shader/mesh.fsh.bin"), + false); +} + +void wsl::gfx::renderer::queue_triangle(vec2f point_1, vec2f point_2, + vec2f point_3, + color::solid color_1, color::solid color_2, + color::solid color_3) { + bgfx::VertexLayout vertex_layout; + + triangle = new gfx::vsh::triangle( + vec3f{320.0f, 480.0f, 0.0f}, (vec4f)(color::transparent)color_1, + vec3f{0.0f, 0.0f, 0.0f}, (vec4f)(color::transparent)color_2, + vec3f{640.0f, 0.0f, 0.0f}, (vec4f)(color::transparent)color_3); + + vertex_layout.begin(bgfx_renderer_type(graphics_api)); + vertex_layout.add(bgfx::Attrib::Enum::Position, 3, + bgfx::AttribType::Enum::Float); + vertex_layout.add(bgfx::Attrib::Enum::Color0, 4, + bgfx::AttribType::Enum::Float); + vertex_layout.end(); + + vbo = create_vertex_buffer(triangle->vertices, triangle->size(), vertex_layout); + ibo = create_index_buffer(indices, sizeof(indices)); + + program = + bgfx::createProgram(load_shader("C:/Users/romer/Documents/Projects/" + "weasel/build/shader/mesh.vsh.bin"), + load_shader("C:/Users/romer/Documents/Projects/" + "weasel/build/shader/mesh.fsh.bin"), + false); +} + +bgfx::ShaderHandle wsl::gfx::renderer::load_shader(const std::string& path) { + std::ifstream ifs(path); + std::stringstream buffer; + buffer << ifs.rdbuf(); + ifs.close(); + std::cout << buffer.str() << std::endl; + return bgfx::createShader( + bgfx::copy(buffer.str().c_str(), buffer.str().size())); +} + +bgfx::RendererType::Enum wsl::gfx::renderer::bgfx_renderer_type(api wsl_api) { + switch (graphics_api) { + case api::automatic: + return bgfx::RendererType::Enum::Count; + break; + case api::d3d11: + return bgfx::RendererType::Enum::Direct3D11; + break; + case api::d3d12: + return bgfx::RendererType::Enum::Direct3D12; + break; + case api::metal: + return bgfx::RendererType::Enum::Metal; + break; + case api::opengl: + return bgfx::RendererType::Enum::OpenGL; + break; + case api::opengles: + return bgfx::RendererType::Enum::OpenGLES; + break; + case api::vulkan: + return bgfx::RendererType::Enum::Vulkan; + break; + default: + return bgfx::RendererType::Enum::Noop; + break; + } +} + +bgfx::IndexBufferHandle wsl::gfx::renderer::create_index_buffer( + const void* indices, std::size_t size) { + return bgfx::createIndexBuffer(bgfx::makeRef(indices, size)); +} + +bgfx::VertexBufferHandle wsl::gfx::renderer::create_vertex_buffer( + const void* vertices, std::size_t size, bgfx::VertexLayout layout) { + return bgfx::createVertexBuffer(bgfx::makeRef(vertices, size), layout); +} \ No newline at end of file diff --git a/src/gfx/renderer.hpp b/src/gfx/renderer.hpp new file mode 100644 index 0000000..1c380ac --- /dev/null +++ b/src/gfx/renderer.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include "gfx/vertex.hpp" +#include "util/color.hpp" +#include "util/vector.hpp" +#include "win/window.hpp" + +namespace wsl { + +namespace gfx { + +enum api { + automatic, + d3d11, + d3d12, + metal, + opengl, + opengles, + vulkan, +}; + +class renderer { + public: + renderer(window* window) : window(window) {} + window* window; + + bool init(api graphics_api = api::automatic); + void clear(color::solid clear_color); + void update(); + // void draw(bgfx::ProgramHandle program, bgfx::VertexBufferHandle vbo, + // bgfx::IndexBufferHandle ibo); + void draw(); + void draw_test_triangle(); + bgfx::ShaderHandle load_shader(const std::string& path); + + void queue_triangle(vec2f point_1, vec2f point_2, vec2f point_3, + color::solid color); + + bgfx::IndexBufferHandle create_index_buffer(const void* indices, + std::size_t size); + bgfx::VertexBufferHandle create_vertex_buffer(const void* vertices, + std::size_t size, + bgfx::VertexLayout layout); + + private: + bgfx::RendererType::Enum bgfx_renderer_type(api wsl_api); + api graphics_api; + + bgfx::VertexBufferHandle vbo; + bgfx::IndexBufferHandle ibo; + bgfx::ProgramHandle program; + + gfx::vsh::triangle* triangle; + /* + + */ + unsigned short indices[3] = {0, 1, 2}; +}; + +} // namespace gfx + +} // namespace wsl \ No newline at end of file diff --git a/src/gfx/shader/mesh/mesh.fsh b/src/gfx/shader/mesh/mesh.fsh new file mode 100644 index 0000000..651db01 --- /dev/null +++ b/src/gfx/shader/mesh/mesh.fsh @@ -0,0 +1,5 @@ +$input v_color0, v_texcoord0 +#include +void main() { + gl_FragColor = v_color0; +} \ No newline at end of file diff --git a/src/gfx/shader/mesh/mesh.vsh b/src/gfx/shader/mesh/mesh.vsh new file mode 100644 index 0000000..b7fa3df --- /dev/null +++ b/src/gfx/shader/mesh/mesh.vsh @@ -0,0 +1,9 @@ +$input a_position, a_color0 +$output v_color0, v_texcoord0 + +#include + +void main() { + gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0)); + v_color0 = a_color0; +} \ No newline at end of file diff --git a/src/gfx/shader/varying.def.sc b/src/gfx/shader/varying.def.sc new file mode 100644 index 0000000..dab116a --- /dev/null +++ b/src/gfx/shader/varying.def.sc @@ -0,0 +1,10 @@ +vec4 v_color0 : COLOR0 = vec4(1.0, 0.0, 0.0, 1.0); +vec4 v_color1 : COLOR1 = vec4(0.0, 1.0, 0.0, 1.0); +vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0); +vec3 v_normal : TEXCOORD1 = vec3(0.0, 1.0, 0.0); + +vec3 a_position : POSITION; +vec3 a_normal : NORMAL0; +vec4 a_color0 : COLOR0; +vec4 a_color1 : COLOR1; +vec2 a_texcoord0 : TEXCOORD0; diff --git a/src/gfx/texture.hpp b/src/gfx/texture.hpp new file mode 100644 index 0000000..9bafe42 --- /dev/null +++ b/src/gfx/texture.hpp @@ -0,0 +1,9 @@ +#include + +namespace wsl { + class texture { + void create_texture_from_file(const std::string& path); + private: + bgfx::TextureHandle internal_texture; + }; +} \ No newline at end of file diff --git a/src/gfx/vertex.hpp b/src/gfx/vertex.hpp new file mode 100644 index 0000000..d4f00d7 --- /dev/null +++ b/src/gfx/vertex.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#include "util/vector.hpp" + +namespace wsl { + +namespace gfx { + +namespace vsh { + +struct vertex {}; + +namespace vertex_types { + +struct shape2d : vertex { + vec3f position; + vec4f color; +}; + +} // namespace vertex_types + +template +struct shape { + T* vertices; + constexpr std::size_t size() { + std::cout << sizeof(T) * N; + return sizeof(T) * N; + }; +}; + +struct triangle : shape { + triangle(vec3f point_1, vec4f color_1, vec3f point_2, vec4f color_2, + vec3f point_3, vec4f color_3) { + vertices = new vertex_types::shape2d[3]{ + vertex_types::shape2d{{}, point_1, color_1}, + vertex_types::shape2d{{}, point_2, color_2}, + vertex_types::shape2d{{}, point_3, color_3}}; + } + ~triangle() { delete vertices; } +}; + +} // namespace vsh + +} // namespace gfx + +} // namespace wsl \ No newline at end of file diff --git a/src/util/color.cpp b/src/util/color.cpp new file mode 100644 index 0000000..f1e595a --- /dev/null +++ b/src/util/color.cpp @@ -0,0 +1,9 @@ +#include "util/color.hpp" + +wsl::color::solid::operator wsl::color::transparent() const { + return transparent{red, green, blue, 0xFF}; +} + +wsl::color::solid::operator unsigned() const { + return static_cast(*this); +} diff --git a/src/util/color.hpp b/src/util/color.hpp new file mode 100644 index 0000000..2415e20 --- /dev/null +++ b/src/util/color.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include "util/vector.hpp" + +namespace wsl { + +namespace color { + +struct transparent; + +struct solid { + unsigned char red; + unsigned char green; + unsigned char blue; + + operator vec3() { + return vec3{static_cast(red) / 255.0f, + static_cast(green) / 255.0f, + static_cast(blue) / 255.0f}; + }; + + operator transparent() const; + operator unsigned() const; +}; + +struct transparent { + unsigned char red; + unsigned char green; + unsigned char blue; + unsigned char alpha; + + operator vec4() { + return vec4{static_cast(red) / 255.0f, + static_cast(green) / 255.0f, + static_cast(blue) / 255.0f, + static_cast(alpha) / 255.0f}; + }; + + operator solid() const { return solid{red, green, blue}; } + operator unsigned() const { + return ((red << 8 | green) << 8 | blue) << 8 | alpha; + } +}; + +static solid white{0xFF, 0xFF, 0xFF}; +static solid black{0x00, 0x00, 0x00}; + +static solid red{0xFF, 0x00, 0x00}; +static solid green{0x00, 0xFF, 0x00}; +static solid blue{0x00, 0x00, 0xFF}; + +} // namespace color + +} // namespace wsl \ No newline at end of file diff --git a/src/util/n_ary_tree.hpp b/src/util/n_ary_tree.hpp new file mode 100644 index 0000000..b604e4b --- /dev/null +++ b/src/util/n_ary_tree.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include + +namespace wsl { + +template +class n_ary_tree { + public: + class node { + public: + node(node* parent, T value); + + node* parent; + T value; + + node& add_child(T value); + int children_count(); + node& child_at(int index); + unsigned index_of(node& child); + + private: + std::list children; + }; + + class iterator { + public: + iterator(n_ary_tree::node* node) : node_ptr(node) {} + iterator operator++(); + node& operator*(); + node* operator->(); + bool operator==(const iterator& other); + bool operator!=(const iterator& other); + + private: + n_ary_tree::node* node_ptr; + }; + n_ary_tree(T root_value); + node root; + + iterator begin(); + iterator end(); +}; + +} // namespace wsl + +#include "util/n_ary_tree.tpp" \ No newline at end of file diff --git a/src/util/n_ary_tree.tpp b/src/util/n_ary_tree.tpp new file mode 100644 index 0000000..5d46397 --- /dev/null +++ b/src/util/n_ary_tree.tpp @@ -0,0 +1,99 @@ +#pragma once + +template +wsl::n_ary_tree::node::node(n_ary_tree::node* parent, T value) + : parent(parent), value(value) {} + +template +typename wsl::n_ary_tree::node& wsl::n_ary_tree::node::add_child(T value) { + children.push_back(node(this, value)); + return children.back(); +} + +template +int wsl::n_ary_tree::node::children_count() { + return children.size(); +} + +template +typename wsl::n_ary_tree::node& wsl::n_ary_tree::node::child_at(int index) { + typename std::list::node>::iterator it = children.begin(); + std::advance(it, index); + return *it; +} + +template +unsigned wsl::n_ary_tree::node::index_of(n_ary_tree::node& child) { + int i = 0; + for (node& child_i : children) { + if (&child == &child_i) return i; + i++; + } + throw std::invalid_argument("child not found"); +} + +template +typename wsl::n_ary_tree::iterator +wsl::n_ary_tree::iterator::operator++() { + if (node_ptr->children_count() > 0) { + // Step down the tree + node_ptr = &node_ptr->child_at(0); + return *this; + } else if (node_ptr->parent) { + // If can't move right climb up till it can jump to its + // next brother node + int index = node_ptr->parent->index_of(*node_ptr); + while (index + 1 >= node_ptr->parent->children_count()) { + node_ptr = node_ptr->parent; + if (!node_ptr->parent) { + // Reached the end + node_ptr = nullptr; + return *this; + } + index = node_ptr->parent->index_of(*node_ptr); + } + // Move to the next brother node + node_ptr = &node_ptr->parent->child_at(index + 1); + return *this; + } else { + node_ptr = nullptr; + return *this; + } +} + +template +typename wsl::n_ary_tree::node& wsl::n_ary_tree::iterator::operator*() { + return *node_ptr; +} + +template +typename wsl::n_ary_tree::node* wsl::n_ary_tree::iterator::operator->() { + return node_ptr; +} + +template +bool wsl::n_ary_tree::iterator::operator==( + const n_ary_tree::iterator& other) { + return node_ptr == other.node_ptr; +} + +template +bool wsl::n_ary_tree::iterator::operator!=( + const n_ary_tree::iterator& other) { + return node_ptr != other.node_ptr; +} + +template +wsl::n_ary_tree::n_ary_tree(T root_value) + : root(node(nullptr, root_value)) {} + + +template +typename wsl::n_ary_tree::iterator wsl::n_ary_tree::begin() { + return &root; +} + +template +typename wsl::n_ary_tree::iterator wsl::n_ary_tree::end() { + return nullptr; +} \ No newline at end of file diff --git a/src/util/vector.hpp b/src/util/vector.hpp new file mode 100644 index 0000000..819bb89 --- /dev/null +++ b/src/util/vector.hpp @@ -0,0 +1,62 @@ +#pragma once + +namespace wsl { + +template +struct vec3; + +template +struct vec2 { + T x, y; + + template + operator vec2() { + return vec2{static_cast(x), static_cast(y)}; + } + + template + operator vec3() { + return vec3{static_cast(x), static_cast(y), 0}; + } +}; + +typedef vec2 vec2f; +typedef vec2 vec2i; +typedef vec2 vec2u; + +template +struct vec3 { + T x, y, z; + + template + operator vec3() { + return vec3{static_cast(x), static_cast(y), static_cast(z)}; + } + + operator vec2() { return vec2{x, y}; } +}; + +typedef vec3 vec3f; +typedef vec3 vec3i; +typedef vec3 vec3u; + +template +struct vec4 { + T x, y, z, w; + + template + operator vec4() { + return vec4{static_cast(x), static_cast(y), static_cast(z), + static_cast(w)}; + } + + operator vec3() { return vec3{x, y, z}; } + + operator vec2() { return vec2{x, y}; } +}; + +typedef vec4 vec4f; +typedef vec4 vec4i; +typedef vec4 vec4u; + +} // namespace wsl \ No newline at end of file diff --git a/src/weasel.hpp b/src/weasel.hpp new file mode 100644 index 0000000..a059ad0 --- /dev/null +++ b/src/weasel.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include "core/app.hpp" + +#include "win/window.hpp" \ No newline at end of file diff --git a/src/win/system_events.cpp b/src/win/system_events.cpp new file mode 100644 index 0000000..69e8e00 --- /dev/null +++ b/src/win/system_events.cpp @@ -0,0 +1,14 @@ +#include "win/system_events.hpp" + +wsl::event::system_event::system_event( + std::shared_ptr& event_queue_ptr) + : xwin_event_queue(event_queue_ptr) {} + +wsl::event::quit::quit(std::shared_ptr& event_queue_ptr) + : system_event(event_queue_ptr) {} + +bool wsl::event::quit::dispatch_condition() { + if (std::shared_ptr event_queue = xwin_event_queue.lock()) + return event_queue->front().type == xwin::EventType::Close; + return false; +} \ No newline at end of file diff --git a/src/win/system_events.hpp b/src/win/system_events.hpp new file mode 100644 index 0000000..8b6951e --- /dev/null +++ b/src/win/system_events.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include +#include + +#include "core/event.hpp" + +namespace wsl { + +namespace event { + +class system_event : public event { + public: + system_event(std::shared_ptr& event_queue_ptr); + + protected: + std::weak_ptr xwin_event_queue; +}; + +class quit : public system_event { + public: + quit(std::shared_ptr& event_queue_ptr); + + bool dispatch_condition() override; +}; + +} // namespace event + +} // namespace wsl \ No newline at end of file diff --git a/src/win/window.cpp b/src/win/window.cpp new file mode 100644 index 0000000..a6dbde1 --- /dev/null +++ b/src/win/window.cpp @@ -0,0 +1,33 @@ +#include "win/window.hpp" + +wsl::window::window() { internal_window = std::make_shared(); } + +bool wsl::window::init(const char* title, unsigned int width, + unsigned int height) { + xwin::WindowDesc desc; + desc.title = title; + desc.width = width; + desc.height = height; + return internal_window->create(desc, *events.internal_event_queue); +} + +void wsl::window::close() { internal_window->close(); } + +wsl::vec2u wsl::window::size() { + xwin::UVec2 size = internal_window->getWindowSize(); + std::cout << size.x << ' ' << size.y << std::endl; + std::cout << internal_window->getDesc().width << ' ' << internal_window->getDesc().height << std::endl; + return vec2u{size.x, size.y}; +} + +wsl::window::events::events() + : internal_event_queue(std::make_shared()), + quit(internal_event_queue) {} + +void wsl::window::events::update() { + internal_event_queue->update(); + while (!internal_event_queue->empty()) { + quit.update(); + internal_event_queue->pop(); + } +} \ No newline at end of file diff --git a/src/win/window.hpp b/src/win/window.hpp new file mode 100644 index 0000000..505484e --- /dev/null +++ b/src/win/window.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +#include + +#include "win/system_events.hpp" +#include "util/vector.hpp" + +namespace wsl { + +class window { + public: + window(); + + bool init(const char* title, unsigned int width, unsigned int height); + void close(); + vec2u size(); + + class events { + public: + events(); + + void update(); + + std::shared_ptr internal_event_queue; + + event::quit quit; + }; + + events events; + + std::shared_ptr internal_window; +}; + +} // namespace wsl \ No newline at end of file diff --git a/vendor/CrossWindow b/vendor/CrossWindow new file mode 160000 index 0000000..7fc3f3f --- /dev/null +++ b/vendor/CrossWindow @@ -0,0 +1 @@ +Subproject commit 7fc3f3fcd1917a6e1da22b7d1c9880466fdcefaa diff --git a/vendor/bgfx.cmake b/vendor/bgfx.cmake new file mode 160000 index 0000000..9426a2f --- /dev/null +++ b/vendor/bgfx.cmake @@ -0,0 +1 @@ +Subproject commit 9426a2f44f8c4dad6c45a3b32111974feeb4ba58