init: prepare the repository for work

This commit is contained in:
Kevin J. 2025-02-06 23:06:15 +01:00
commit d8c668aef5
30 changed files with 1310178 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
build/
.cache/
compile_commands.json
tools/

18
.gitmodules vendored Normal file
View File

@ -0,0 +1,18 @@
[submodule "thirdparty/bgfx.cmake"]
path = thirdparty/bgfx.cmake
url = https://github.com/bkaradzic/bgfx.cmake
[submodule "thirdparty/glfw.cmake"]
path = thirdparty/glfw.cmake
url = https://github.com/glfw/glfw
[submodule "thirdparty/assimp.cmake"]
path = thirdparty/assimp.cmake
url = https://github.com/assimp/assimp
[submodule "thirdparty/glm.cmake"]
path = thirdparty/glm.cmake
url = https://github.com/icaven/glm
[submodule "thirdparty/imgui"]
path = thirdparty/imgui
url = https://github.com/ocornut/imgui
[submodule "thirdparty/imgui.cmake"]
path = thirdparty/imgui.cmake
url = https://github.com/tamaskenez/imgui-cmake

84
CMakeLists.txt Normal file
View File

@ -0,0 +1,84 @@
cmake_minimum_required(VERSION 3.25.1)
project(pgv
VERSION 0.1
DESCRIPTION "polynomial graphical viewer"
HOMEPAGE_URL "http://git.0xdeadbeer.xyz/0xdeadbeer/pgv"
LANGUAGES CXX)
add_subdirectory("thirdparty/bgfx.cmake")
add_subdirectory("thirdparty/glfw.cmake")
add_subdirectory("thirdparty/assimp.cmake")
add_subdirectory("thirdparty/imgui.cmake")
add_subdirectory("thirdparty/glm.cmake")
add_executable(pgv
src/pgv.cpp
src/common.cpp
src/engine.cpp
src/engine/quad.cpp
src/engine/object.cpp
src/engine/animation.cpp
src/engine/imgui.cpp
)
target_link_libraries(pgv bx)
target_link_libraries(pgv bgfx)
target_link_libraries(pgv bimg)
target_link_libraries(pgv imgui)
target_link_libraries(pgv glfw)
target_link_libraries(pgv assimp)
target_link_libraries(pgv glm)
target_include_directories(pgv PRIVATE "include/")
# build shaders into /build/shaders/
file(GLOB SHADER_SOURCE_FILES "${PROJECT_SOURCE_DIR}/shaders/*.sc")
set(SHADER_PLATFORM "linux")
set(SHADER_PROFILE "440")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/shaders")
foreach(SHADER_SOURCE ${SHADER_SOURCE_FILES})
cmake_path(ABSOLUTE_PATH SHADER_SOURCE NORMALIZE)
cmake_path(GET SHADER_SOURCE FILENAME SHADER_NAME)
cmake_path(GET SHADER_SOURCE STEM SHADER_STEM)
set(VERTEX_SHADER_TYPE -1)
set(FRAGMENT_SHADER_TYPE -1)
set(SHADER_TYPE)
string(FIND "${SHADER_NAME}" "vs" VERTEX_SHADER_TYPE)
string(FIND "${SHADER_NAME}" "fs" FRAGMENT_SHADER_TYPE)
if(${VERTEX_SHADER_TYPE} GREATER -1)
set(SHADER_TYPE "vertex")
elseif(${FRAGMENT_SHADER_TYPE} GREATER -1)
set(SHADER_TYPE "fragment")
else()
continue()
endif()
set(SHADER_COMMAND_ARGUMENTS "-f ${SHADER_SOURCE} -o ${CMAKE_CURRENT_BINARY_DIR}/shaders/${SHADER_LANGUAGE}/${SHADER_STEM}.bin --type ${SHADER_TYPE} --platform ${SHADER_PLATFORM} --profile ${SHADER_PROFILE}")
set(SHADER_COMMAND "${PROJECT_SOURCE_DIR}/tools/shaderc ${SHADER_COMMAND_ARGUMENTS}")
add_custom_target(${SHADER_NAME} ALL
COMMAND /bin/bash -c "${SHADER_COMMAND}"
)
endforeach()
# build textures into /build/textures
file(GLOB TEXTURE_SOURCE_FILES "${PROJECT_SOURCE_DIR}/textures/*")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/textures")
foreach(TEXTURE_SOURCE ${TEXTURE_SOURCE_FILES})
cmake_path(ABSOLUTE_PATH TEXTURE_SOURCE NORMALIZE)
cmake_path(GET TEXTURE_SOURCE FILENAME TEXTURE_NAME)
cmake_path(GET TEXTURE_SOURCE STEM TEXTURE_STEM)
set(TEXTURE_COMMAND_ARGUMENTS "-f ${TEXTURE_SOURCE} -o ${CMAKE_CURRENT_BINARY_DIR}/textures/${TEXTURE_STEM}.dds")
set(TEXTURE_COMMAND "${PROJECT_SOURCE_DIR}/tools/texturec ${TEXTURE_COMMAND_ARGUMENTS}")
add_custom_target(${TEXTURE_NAME} ALL
COMMAND /bin/bash -c "${TEXTURE_COMMAND}"
)
endforeach()
# build models into /build/models
add_custom_target("models" ALL
COMMAND /bin/bash -c "cp -rf ${PROJECT_SOURCE_DIR}/models/ ${CMAKE_CURRENT_BINARY_DIR}/"
)
# file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/models")
# file(COPY "${PROJECT_SOURCE_DIR}/models/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/models/")

61
README Normal file
View File

@ -0,0 +1,61 @@
PGV
Polynomial Graphical Viewer
I am personally planning to use it for simple terrain generation
as an alternative to noise maps.
TECHNICALS
The underlying API renderer is BGFX. Source code is in C++.
Intermediate GUI is ran with the help of dear-imgui and a
custom port of it to BGFX - which I took from the bigg
framework (bgfx + imgui + glfw + glm).
For the time being, this remains tested only on a modern
Linux kernel. Patches and pull requests that highten the
project's value or make it cross-platform are more than
welcome. For any technical questions regarding the tool's
source code, please contact me via email.
BUILD AND RUN
git clone http://git.0xdeadbeer.xyz/0xdeadbeer/pgv
cd pgv
git submodule update --init --recursive
cd thirdparty/bgfx.cmake
mkdir build
cmake ..
make -j16 # adjust this number accordingly
# $proj_root is the inside location of your root project - location of the pgv repository
ln -s $proj_root/thirdparty/bgfx.cmake/build/cmake/bgfx/shaderc $proj_root/tools/shaderc
ln -s $proj_root/thirdparty/bgfx.cmake/build/cmake/bimg/texturec $proj_root/tools/texturec
cd $proj_root
mkdir build
cd build
cmake ..
make -j16 # adjust this number accordingly
./pgv
SUBMODULES
bgfx.cmake
glfw.cmake
imgui.cmake
assimp.cmake
glm.cmake

7
content/main.map Normal file
View File

@ -0,0 +1,7 @@
# author: 0xdeadbeer (Kevin Jerebica)
# description: inclined hill map
seed 294852748

24
include/common.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef COMMON_HPP
#define COMMON_HPP
#include <iostream>
#include <bgfx/bgfx.h>
#include <bx/file.h>
#define GLFW_DEBUG
#define DEFAULT_WIDTH 1280
#define DEFAULT_HEIGHT 720
#define LOG(x) std::cout << "--log: " << x << std::endl;
#define ERROR(x) std::cout << "--error: " << x << std::endl;
#define DEFAULT_VERTEX "shaders/vs_basic.bin"
#define DEFAULT_FRAGMENT "shaders/fs_basic.bin"
bgfx::Memory* load_mem(bx::FileReader* reader, bx::FilePath& filepath);
bgfx::ShaderHandle load_shader(bx::FileReader* reader, std::string filename);
bgfx::ProgramHandle load_program(std::string vs_name, std::string fs_name);
bgfx::TextureHandle load_texture(std::string filename);
#endif

59
include/engine.hpp Normal file
View File

@ -0,0 +1,59 @@
#ifndef ENGINE_HPP
#define ENGINE_HPP
#include <iostream>
#include <bx/file.h>
#include <bx/bx.h>
#include <bgfx/bgfx.h>
#include <GLFW/glfw3.h>
#include <engine/object.hpp>
#define CAMERA_WIDTH 50.0f
#define CAMERA_NEAR 0.01f
#define CAMERA_FAR 100.0f
class Engine {
public:
Engine(void);
int Init(void);
int Update(void);
void Shutdown(void);
static void GlfwErrorCallback(int error, const char *s);
void Instantiate(EngineObject* obj);
GLFWwindow* main_window;
int main_view;
int keyboard_slots[GLFW_KEY_LAST];
int cursor_slots[GLFW_MOUSE_BUTTON_LAST+1];
int cursor_xpos;
int cursor_ypos;
static void keyboard_callback(GLFWwindow *window, int key, int scancode, int action, int mods);
static void cursor_callback(GLFWwindow *window, double x, double y);
static void cursor_button_callback(GLFWwindow *window, int button, int action, int mods);
static void window_size_callback(GLFWwindow *window, int width, int height);
static void scroll_callback(GLFWwindow *window, double xoffset, double yoffset);
static void char_callback(GLFWwindow *window, unsigned int codepoint);
void reset(void);
private:
int width;
int height;
std::string title;
bgfx::ProgramHandle program;
bgfx::UniformHandle u_position;
bgfx::UniformHandle u_rotation;
bgfx::UniformHandle u_scale;
std::vector<EngineObject *> objs;
float last_time;
float dt;
float time;
};
#endif

View File

@ -0,0 +1,28 @@
#ifndef ANIMATION_HPP
#define ANIMATION_HPP
#include <iostream>
#include <engine.hpp>
#include <engine/object.hpp>
class Animation {
public:
Animation(
Engine *ref,
std::string slide_texture,
int cell_width,
int cell_height,
int cell_num,
float speed
);
void Cycle(float time, EngineObject* o);
private:
Engine *ref;
bgfx::TextureHandle slide_texture;
int cell_width;
int cell_height;
int cell_num;
float speed;
};
#endif

15
include/engine/imgui.hpp Normal file
View File

@ -0,0 +1,15 @@
#ifndef IMGUI_HPP
#define IMGUI_HPP
#include <GLFW/glfw3.h>
#include <imgui.h>
void imgui_init(GLFWwindow *window);
void imgui_render(ImDrawData *draw_data);
void imgui_reset(int width, int height);
void imgui_events(float dt);
void imgui_shutdown(void);
void imgui_set_clipboard_text(void *user_data, const char *text);
const char *imgui_get_clipboard_text(void *user_data);
#endif

30
include/engine/object.hpp Normal file
View File

@ -0,0 +1,30 @@
#ifndef OBJECT_HPP
#define OBJECT_HPP
#include <vector>
#include <engine/quad.hpp>
#include <glm/glm.hpp>
#include <bgfx/bgfx.h>
#include <assimp/scene.h>
class EngineObject {
public:
EngineObject();
int load_node(aiScene *scene, aiNode *node);
int load_model(std::string filename);
glm::vec4 position;
glm::vec4 rotation;
glm::vec4 scale;
std::vector<float> vertices;
std::vector<unsigned int> indices;
bgfx::VertexLayout layout;
bgfx::TextureHandle texture;
bgfx::VertexBufferHandle vbh;
bgfx::IndexBufferHandle ibh;
};
#endif

26
include/engine/quad.hpp Normal file
View File

@ -0,0 +1,26 @@
#ifndef QUAD_HPP
#define QUAD_HPP
#include <iostream>
#include <vector>
#include <bgfx/bgfx.h>
struct VertexData {
float x;
float y;
float z;
float u;
float v;
};
class EngineQuad {
public:
std::vector<VertexData> vertices;
std::vector<uint16_t> indices;
bgfx::VertexLayout layout;
EngineQuad(void);
EngineQuad(std::vector<VertexData> _v, std::vector<uint16_t> _i);
};
#endif

25
models/cube.obj Normal file
View File

@ -0,0 +1,25 @@
# Blender 4.3.2
# www.blender.org
o Cube
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
s 0
g off
f 5 3 1
f 3 8 4
f 7 6 8
f 2 8 6
f 1 4 2
f 5 2 6
f 5 7 3
f 3 7 8
f 7 5 6
f 2 4 8
f 1 3 4
f 5 1 2

1309064
models/dragon.obj Normal file

File diff suppressed because it is too large Load Diff

1
shaders/bgfx_shader.sh Symbolic link
View File

@ -0,0 +1 @@
../thirdparty/bgfx.cmake/bgfx/src/bgfx_shader.sh

8
shaders/fs_basic.sc Normal file
View File

@ -0,0 +1,8 @@
$input f_position
#include <bgfx_shader.sh>
#include <shaderlib.sh>
void main() {
gl_FragColor = vec4(f_position.xyz, 1.0f);
}

1
shaders/shaderlib.sh Symbolic link
View File

@ -0,0 +1 @@
../thirdparty/bgfx.cmake/bgfx/examples/common/shaderlib.sh

3
shaders/varying.def.sc Normal file
View File

@ -0,0 +1,3 @@
vec3 a_position : POSITION;
vec3 f_position : POSITION;

34
shaders/vs_basic.sc Normal file
View File

@ -0,0 +1,34 @@
$input a_position
$output f_position
uniform vec4 u_position;
uniform vec4 u_rotation;
uniform vec4 u_scale;
#include <bgfx_shader.sh>
#include <shaderlib.sh>
void main() {
// rotation
mat3 x_rot = mat3(1, 0, 0,
0, cos(u_rotation.x), -sin(u_rotation.x),
0, sin(u_rotation.x), cos(u_rotation.x));
mat3 y_rot = mat3(cos(u_rotation.y), 0, sin(u_rotation.y),
0, 1, 0,
-sin(u_rotation.y), 0, cos(u_rotation.y));
mat3 z_rot = mat3(cos(u_rotation.z), -sin(u_rotation.z), 0,
sin(u_rotation.z), cos(u_rotation.z), 0,
0, 0, 1);
vec3 r_position = a_position;
r_position = mul(r_position, x_rot);
r_position = mul(r_position, y_rot);
r_position = mul(r_position, z_rot);
vec4 scale = mul(u_scale, vec4(r_position, 1.0f));
vec4 view = mul(u_view, scale);
vec4 pos = view + u_position;
gl_Position = mul(u_proj, pos);
f_position = a_position;
}

52
src/common.cpp Normal file
View File

@ -0,0 +1,52 @@
#include "bgfx/defines.h"
#include <iostream>
#include <string>
#include <bx/filepath.h>
#include <bx/file.h>
#include <bx/string.h>
#include <bgfx/bgfx.h>
#include <common.hpp>
bx::DefaultAllocator default_allocator;
bx::FileReader* reader = BX_NEW(&default_allocator, bx::FileReader);
bgfx::Memory* load_mem(bx::FileReader* reader, bx::FilePath& filepath) {
if (!bx::open(reader, filepath)) {
ERROR("--error: failed to load " + std::string(filepath.getCPtr()));
return NULL;
}
uint32_t size = (uint32_t)bx::getSize(reader);
const bgfx::Memory* mem = bgfx::alloc(size+1);
bx::read(reader, mem->data, size, bx::ErrorAssert{});
bx::close(reader);
mem->data[mem->size-1] = '\0';
return (bgfx::Memory *) mem;
}
bgfx::ShaderHandle load_shader(bx::FileReader* reader, std::string filename) {
bx::FilePath filepath(filename.c_str());
bgfx::ShaderHandle handle = bgfx::createShader(
load_mem(reader, filepath));
LOG("loading shader: " + filename);
bgfx::setName(handle, filename.c_str(), filename.length());
return handle;
}
bgfx::ProgramHandle load_program(std::string vs_name,
std::string fs_name) {
bgfx::ShaderHandle vsh = load_shader(reader, vs_name);
bgfx::ShaderHandle fsh = load_shader(reader, fs_name);
return bgfx::createProgram(vsh, fsh, true);
}
bgfx::TextureHandle load_texture(std::string filename) {
bx::FilePath filepath(filename.c_str());
return bgfx::createTexture(load_mem(reader, filepath), BGFX_TEXTURE_BLIT_DST|BGFX_SAMPLER_POINT);
}

267
src/engine.cpp Normal file
View File

@ -0,0 +1,267 @@
#include <iostream>
#include "bgfx/defines.h"
#include "engine/object.hpp"
#include "imgui.h"
#include <bx/file.h>
#include <bx/math.h>
#include <glm/fwd.hpp>
#include <vector>
#include <cstring>
#include <engine.hpp>
#include <bgfx/bgfx.h>
#include <glm/glm.hpp>
#include <common.hpp>
#include <GLFW/glfw3.h>
#define GLFW_EXPOSE_NATIVE_X11
#include <GLFW/glfw3native.h>
#include <engine/quad.hpp>
#include <engine/imgui.hpp>
Engine::Engine(void) {
this->width = DEFAULT_WIDTH;
this->height = DEFAULT_HEIGHT;
this->title = "Polynomial Graphical Viewer";
this->main_view = 0;
memset(this->keyboard_slots, 0, sizeof(this->keyboard_slots));
memset(this->cursor_slots, 0, sizeof(this->cursor_slots));
this->last_time = 0;
this->dt = 0;
this->time = 0;
}
void Engine::keyboard_callback(GLFWwindow *window, int key, int scancode, int action, int mods) {
Engine *engine = (Engine *) glfwGetWindowUserPointer(window);
engine->keyboard_slots[key] = action;
}
void Engine::cursor_callback(GLFWwindow *window, double x, double y) {
Engine *engine = (Engine *) glfwGetWindowUserPointer(window);
engine->cursor_xpos = x;
engine->cursor_ypos = y;
}
void Engine::cursor_button_callback(GLFWwindow *window, int button, int action, int mods) {
Engine *engine = (Engine *) glfwGetWindowUserPointer(window);
engine->cursor_slots[button] = action;
ImGuiIO &io = ImGui::GetIO();
if (button >= 0 && button < IM_ARRAYSIZE(io.MouseDown)) {
if (action == GLFW_PRESS) {
io.MouseDown[button] = true;
}
else {
io.MouseDown[button] = false;
}
}
}
void Engine::window_size_callback(GLFWwindow *window, int width, int height) {
Engine *engine = (Engine *) glfwGetWindowUserPointer(window);
engine->width = width;
engine->height = height;
engine->reset();
}
void Engine::scroll_callback(GLFWwindow *window, double xoffset, double yoffset) {
ImGuiIO &io = ImGui::GetIO();
io.MouseWheelH += xoffset;
io.MouseWheel += yoffset;
}
void Engine::char_callback(GLFWwindow *window, unsigned int codepoint) {
ImGuiIO &io = ImGui::GetIO();
io.AddInputCharacter(codepoint);
}
void Engine::reset(void) {
bgfx::reset(this->width, this->height, 0);
imgui_reset(this->width, this->height);
bgfx::setViewRect(this->main_view, 0, 0, width, height);
bgfx::setViewClear(this->main_view,
BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH,
0x00000000,
1.0f,
0);
}
int Engine::Init(void) {
int ret = glfwInit();
if (ret < 0) {
ERROR("failed initializing glfw");
return -1;
}
glfwSetErrorCallback(Engine::GlfwErrorCallback);
this->main_window = glfwCreateWindow(this->width, this->height, this->title.c_str(),
#ifdef GLFW_DEBUG
NULL
#else
glfwGetPrimaryMonitor() // fullscreen
#endif
, NULL);
if (!this->main_window) {
ERROR("failed creating window");
return -1;
}
glfwSetWindowUserPointer(this->main_window, this);
glfwSetKeyCallback(this->main_window, Engine::keyboard_callback);
glfwSetCursorPosCallback(this->main_window, Engine::cursor_callback);
glfwSetMouseButtonCallback(this->main_window, Engine::cursor_button_callback);
glfwSetWindowSizeCallback(this->main_window, this->window_size_callback);
glfwSetScrollCallback(this->main_window, this->scroll_callback);
glfwSetCharCallback(this->main_window, this->char_callback);;
#ifdef GLFW_DEBUG
glfwSetInputMode(this->main_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
#endif
bgfx::Init init;
init.platformData.ndt = glfwGetX11Display();
init.platformData.nwh = (void*) (uintptr_t) glfwGetX11Window(this->main_window);
glfwGetWindowSize(this->main_window, &this->width, &this->height);
init.resolution.width = this->width;
init.resolution.height = this->height;
init.resolution.reset = BGFX_RESET_VSYNC;
if (!bgfx::init(init)) {
ERROR("failed initializing bgfx");
return -1;
}
bgfx::setViewClear(this->main_view,
BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH,
0x00000000,
1.0f,
0);
{
bx::Vec3 at = {0.0f, 0.0f, 0.0f};
bx::Vec3 eye = {0.0f, 0.0f, -35.0f};
float view[16];
bx::mtxLookAt(view, eye, at);
float proj[16];
bx::mtxProj(proj, 60.0f, float(this->width)/float(this->height), 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth);
bgfx::setViewTransform(this->main_view, view, proj);
}
bgfx::setViewRect(this->main_view, 0, 0, this->width, this->height);
this->u_position = bgfx::createUniform("u_position", bgfx::UniformType::Vec4);
this->u_rotation = bgfx::createUniform("u_rotation", bgfx::UniformType::Vec4);
this->u_scale = bgfx::createUniform("u_scale", bgfx::UniformType::Vec4);
this->program = load_program(DEFAULT_VERTEX, DEFAULT_FRAGMENT);
imgui_init(this->main_window);
reset();
return 0;
}
float angular_velocity[3];
int Engine::Update(void) {
this->time = glfwGetTime();
this->dt = this->time - this->last_time;
this->last_time = this->time;
glfwPollEvents();
imgui_events(this->dt);
ImGui::NewFrame();
///////////////
// UPDATE
///////////////
this->objs.at(0)->rotation.x += angular_velocity[0] * dt;
this->objs.at(0)->rotation.y += angular_velocity[1] * dt;
this->objs.at(0)->rotation.z += angular_velocity[2] * dt;
bgfx::touch(this->main_view);
ImGui::ShowDemoWindow();
ImGui::Begin("Hello there");
ImGui::Text("Hello theree!");
ImGui::SliderFloat("angular velocity (x component)", &angular_velocity[0], -2.5f, 2.5f);
ImGui::SliderFloat("angular velocity (y component)", &angular_velocity[1], -2.5f, 2.5f);
ImGui::SliderFloat("angular velocity (z component)", &angular_velocity[2], -2.5f, 2.5f);
ImGui::End();
///////////////
// UPDATE
///////////////
ImGui::Render();
imgui_render(ImGui::GetDrawData());
std::int32_t new_width;
std::int32_t new_height;
glfwGetFramebufferSize(this->main_window, &new_width, &new_height);
if (new_width != this->width || new_height != this->height) {
bgfx::reset(new_width, new_height, 0);
bgfx::setViewRect(this->main_view, 0, 0, bgfx::BackbufferRatio::Equal);
this->width = new_width;
this->height = new_height;
}
for (int i = 0; i < this->objs.size(); i++) {
bgfx::setState(BGFX_STATE_WRITE_R |
BGFX_STATE_WRITE_G |
BGFX_STATE_WRITE_B |
BGFX_STATE_WRITE_A |
BGFX_STATE_WRITE_Z |
BGFX_STATE_DEPTH_TEST_LESS |
BGFX_STATE_CULL_CCW );
EngineObject* obj = this->objs[i];
bgfx::setVertexBuffer(0, obj->vbh);
bgfx::setIndexBuffer(obj->ibh);
bgfx::setUniform(this->u_position, &obj->position);
bgfx::setUniform(this->u_rotation, &obj->rotation);
bgfx::setUniform(this->u_scale, &obj->scale);
bgfx::submit(this->main_view, this->program);
}
bgfx::frame();
return 0;
}
void Engine::Shutdown(void) {
imgui_shutdown();
for (int i = 0; i < this->objs.size(); i++) {
EngineObject* obj = this->objs[i];
bgfx::destroy(obj->vbh);
bgfx::destroy(obj->ibh);
}
bgfx::destroy(this->u_position);
bgfx::destroy(this->u_rotation);
bgfx::destroy(this->u_scale);
bgfx::destroy(this->program);
bgfx::shutdown();
glfwTerminate();
}
void Engine::GlfwErrorCallback(int error, const char *s) {
ERROR("glfw failed -> " << s);
}
void Engine::Instantiate(EngineObject* obj) {
this->objs.push_back(obj);
}

34
src/engine/animation.cpp Normal file
View File

@ -0,0 +1,34 @@
#include <engine/animation.hpp>
#include <engine/object.hpp>
#include <common.hpp>
Animation::Animation(
Engine* ref,
std::string slide_texture,
int cell_width,
int cell_height,
int cell_num,
float speed
) {
this->ref = ref;
this->slide_texture = load_texture(slide_texture);
this->cell_width = cell_width;
this->cell_height = cell_height;
this->cell_num = cell_num;
this->speed = speed;
}
void Animation::Cycle(float time, EngineObject *o) {
int stage = (int) (time / (this->speed*1000.0f)) % this->cell_num;
bgfx::blit(
this->ref->main_view,
o->texture,
0,
0,
this->slide_texture,
stage*cell_width,
0,
this->cell_width,
this->cell_height
);
}

200
src/engine/imgui.cpp Normal file
View File

@ -0,0 +1,200 @@
#include "bgfx/defines.h"
#include "bx/bx.h"
#include <bgfx/bgfx.h>
#include <GLFW/glfw3.h>
#include <engine/imgui.hpp>
#include <imgui.h>
const int vs_ocornut_imgui_len = 480;
const unsigned char vs_ocornut_imgui[] = {
0x56,0x53,0x48,0x06,0x00,0x00,0x00,0x00,0x01,0x83,0xF2,0xE1,0x01,0x00,0x0B,0x75,0x5F,0x76,0x69,0x65,0x77,0x54,0x65,0x78,0x65,
0x6C,0x02,0x01,0x00,0x00,0x01,0x00,0xBA,0x01,0x00,0x00,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x20,0x76,0x65,0x63,0x34,
0x20,0x61,0x5F,0x63,0x6F,0x6C,0x6F,0x72,0x30,0x3B,0x0A,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x20,0x76,0x65,0x63,0x33,
0x20,0x61,0x5F,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x3B,0x0A,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x20,0x76,0x65,
0x63,0x32,0x20,0x61,0x5F,0x74,0x65,0x78,0x63,0x6F,0x6F,0x72,0x64,0x30,0x3B,0x0A,0x76,0x61,0x72,0x79,0x69,0x6E,0x67,0x20,0x76,
0x65,0x63,0x34,0x20,0x76,0x5F,0x63,0x6F,0x6C,0x6F,0x72,0x30,0x3B,0x0A,0x76,0x61,0x72,0x79,0x69,0x6E,0x67,0x20,0x76,0x65,0x63,
0x32,0x20,0x76,0x5F,0x74,0x65,0x78,0x63,0x6F,0x6F,0x72,0x64,0x30,0x3B,0x0A,0x75,0x6E,0x69,0x66,0x6F,0x72,0x6D,0x20,0x76,0x65,
0x63,0x34,0x20,0x75,0x5F,0x76,0x69,0x65,0x77,0x54,0x65,0x78,0x65,0x6C,0x3B,0x0A,0x76,0x6F,0x69,0x64,0x20,0x6D,0x61,0x69,0x6E,
0x20,0x28,0x29,0x0A,0x7B,0x0A,0x20,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x6D,0x70,0x76,0x61,0x72,0x5F,0x31,0x3B,0x0A,0x20,0x20,
0x74,0x6D,0x70,0x76,0x61,0x72,0x5F,0x31,0x20,0x3D,0x20,0x28,0x28,0x32,0x2E,0x30,0x20,0x2A,0x20,0x61,0x5F,0x70,0x6F,0x73,0x69,
0x74,0x69,0x6F,0x6E,0x2E,0x78,0x79,0x29,0x20,0x2A,0x20,0x75,0x5F,0x76,0x69,0x65,0x77,0x54,0x65,0x78,0x65,0x6C,0x2E,0x78,0x79,
0x29,0x3B,0x0A,0x20,0x20,0x76,0x65,0x63,0x34,0x20,0x74,0x6D,0x70,0x76,0x61,0x72,0x5F,0x32,0x3B,0x0A,0x20,0x20,0x74,0x6D,0x70,
0x76,0x61,0x72,0x5F,0x32,0x2E,0x7A,0x77,0x20,0x3D,0x20,0x76,0x65,0x63,0x32,0x28,0x30,0x2E,0x30,0x2C,0x20,0x31,0x2E,0x30,0x29,
0x3B,0x0A,0x20,0x20,0x74,0x6D,0x70,0x76,0x61,0x72,0x5F,0x32,0x2E,0x78,0x20,0x3D,0x20,0x28,0x74,0x6D,0x70,0x76,0x61,0x72,0x5F,
0x31,0x2E,0x78,0x20,0x2D,0x20,0x31,0x2E,0x30,0x29,0x3B,0x0A,0x20,0x20,0x74,0x6D,0x70,0x76,0x61,0x72,0x5F,0x32,0x2E,0x79,0x20,
0x3D,0x20,0x28,0x31,0x2E,0x30,0x20,0x2D,0x20,0x74,0x6D,0x70,0x76,0x61,0x72,0x5F,0x31,0x2E,0x79,0x29,0x3B,0x0A,0x20,0x20,0x67,
0x6C,0x5F,0x50,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x20,0x3D,0x20,0x74,0x6D,0x70,0x76,0x61,0x72,0x5F,0x32,0x3B,0x0A,0x20,0x20,
0x76,0x5F,0x74,0x65,0x78,0x63,0x6F,0x6F,0x72,0x64,0x30,0x20,0x3D,0x20,0x61,0x5F,0x74,0x65,0x78,0x63,0x6F,0x6F,0x72,0x64,0x30,
0x3B,0x0A,0x20,0x20,0x76,0x5F,0x63,0x6F,0x6C,0x6F,0x72,0x30,0x20,0x3D,0x20,0x61,0x5F,0x63,0x6F,0x6C,0x6F,0x72,0x30,0x3B,0x0A,
0x7D,0x0A,0x0A,0x00,0x00
};
const int fs_ocornut_imgui_len = 186;
const unsigned char fs_ocornut_imgui[] = {
0x46,0x53,0x48,0x06,0x01,0x83,0xF2,0xE1,0x00,0x00,0x00,0x00,0x01,0x00,0x05,0x73,0x5F,0x74,0x65,0x78,0x00,0x01,0x00,0x00,0x01,
0x00,0x9A,0x00,0x00,0x00,0x76,0x61,0x72,0x79,0x69,0x6E,0x67,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x5F,0x63,0x6F,0x6C,0x6F,0x72,
0x30,0x3B,0x0A,0x76,0x61,0x72,0x79,0x69,0x6E,0x67,0x20,0x76,0x65,0x63,0x32,0x20,0x76,0x5F,0x74,0x65,0x78,0x63,0x6F,0x6F,0x72,
0x64,0x30,0x3B,0x0A,0x75,0x6E,0x69,0x66,0x6F,0x72,0x6D,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x72,0x32,0x44,0x20,0x73,0x5F,0x74,
0x65,0x78,0x3B,0x0A,0x76,0x6F,0x69,0x64,0x20,0x6D,0x61,0x69,0x6E,0x20,0x28,0x29,0x0A,0x7B,0x0A,0x20,0x20,0x67,0x6C,0x5F,0x46,
0x72,0x61,0x67,0x43,0x6F,0x6C,0x6F,0x72,0x20,0x3D,0x20,0x28,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x44,0x20,0x28,0x73,0x5F,
0x74,0x65,0x78,0x2C,0x20,0x76,0x5F,0x74,0x65,0x78,0x63,0x6F,0x6F,0x72,0x64,0x30,0x29,0x20,0x2A,0x20,0x76,0x5F,0x63,0x6F,0x6C,
0x6F,0x72,0x30,0x29,0x3B,0x0A,0x7D,0x0A,0x0A,0x00,0x00
};
bgfx::VertexLayout imgui_vertex_layout;
bgfx::TextureHandle imgui_font_texture;
bgfx::UniformHandle imgui_font_uniform;
bgfx::ProgramHandle imgui_program;
void imgui_render(ImDrawData *data);
GLFWwindow *imgui_window = NULL;
GLFWcursor *mouse_cursors[ImGuiMouseCursor_COUNT] = { 0 };
void imgui_init(GLFWwindow *window) {
imgui_window = window;
unsigned char *data;
int width = 0;
int height = 0;
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
imgui_vertex_layout
.begin()
.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
.end();
io.Fonts->AddFontDefault();
io.Fonts->GetTexDataAsRGBA32(&data, &width, &height);
imgui_font_texture = bgfx::createTexture2D(width, height, false, 1, bgfx::TextureFormat::BGRA8, 0, bgfx::copy(data, width*height*4));
imgui_font_uniform = bgfx::createUniform("s_tex", bgfx::UniformType::Sampler);
bgfx::ShaderHandle vs = bgfx::createShader(bgfx::makeRef(vs_ocornut_imgui, vs_ocornut_imgui_len));
bgfx::ShaderHandle fs = bgfx::createShader(bgfx::makeRef(fs_ocornut_imgui, fs_ocornut_imgui_len));
imgui_program = bgfx::createProgram(vs, fs, true);
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;
io.SetClipboardTextFn = imgui_set_clipboard_text;
io.GetClipboardTextFn = imgui_get_clipboard_text;
io.ClipboardUserData = window;
mouse_cursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
mouse_cursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
mouse_cursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
mouse_cursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
mouse_cursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
mouse_cursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
mouse_cursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
mouse_cursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
}
void imgui_render(ImDrawData *draw_data) {
for (int i = 0; i < draw_data->CmdListsCount; ++i) {
bgfx::TransientVertexBuffer tvb;
bgfx::TransientIndexBuffer tib;
const ImDrawList *draw_list = draw_data->CmdLists[i];
unsigned int num_vertices = (unsigned int) draw_list->VtxBuffer.size();
unsigned int num_indices = (unsigned int) draw_list->IdxBuffer.size();
if (!bgfx::getAvailTransientVertexBuffer(num_vertices, imgui_vertex_layout) ||
!bgfx::getAvailTransientIndexBuffer(num_indices)) {
break;
}
bgfx::allocTransientVertexBuffer(&tvb, num_vertices, imgui_vertex_layout);
bgfx::allocTransientIndexBuffer(&tib, num_indices);
ImDrawVert *verts = (ImDrawVert *) tvb.data;
memcpy(verts, draw_list->VtxBuffer.begin(), num_vertices * sizeof(ImDrawVert));
ImDrawIdx *indices = (ImDrawIdx *) tib.data;
memcpy(indices, draw_list->IdxBuffer.begin(), num_indices * sizeof(ImDrawIdx));
unsigned int offset = 0;
for (const ImDrawCmd *cmd = draw_list->CmdBuffer.begin(), *cmd_end = draw_list->CmdBuffer.end(); cmd != cmd_end; ++cmd) {
if (cmd->UserCallback) {
cmd->UserCallback(draw_list, cmd);
}
else if (cmd->ElemCount != 0) {
unsigned long state = BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_MSAA;
bgfx::TextureHandle th = imgui_font_texture;
if (((unsigned int *) cmd->TextureId) != NULL) {
th.idx = (unsigned short) *((unsigned int *) cmd->TextureId);
}
state |= BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA);
const unsigned short xx = (unsigned short) bx::max(cmd->ClipRect.x, 0.0f);
const unsigned short yy = (unsigned short) bx::max(cmd->ClipRect.y, 0.0f);
bgfx::setScissor(xx, yy, (unsigned short) bx::min(cmd->ClipRect.z, 65535.0f)-xx, (unsigned short) bx::min(cmd->ClipRect.w, 65535.0f)-yy);
bgfx::setState(state);
bgfx::setTexture(0, imgui_font_uniform, th);
bgfx::setVertexBuffer(0, &tvb, 0, num_vertices);
bgfx::setIndexBuffer(&tib, offset, cmd->ElemCount);
bgfx::submit(200, imgui_program);
}
offset += cmd->ElemCount;
}
}
}
void imgui_reset(int width, int height) {
bgfx::setViewRect(200, 0, 0, width, height);
}
void imgui_events(float dt) {
ImGuiIO &io = ImGui::GetIO();
int w = 0;
int h = 0;
int display_w = 0;
int display_h = 0;
glfwGetWindowSize(imgui_window, &w, &h);
glfwGetFramebufferSize(imgui_window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h);
io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float) display_w/w) : 0, h > 0 ? ((float) display_h/h) : 0);
io.DeltaTime = dt;
const ImVec2 mouse_pos_backup = io.MousePos;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
const bool focused = glfwGetWindowAttrib(imgui_window, GLFW_FOCUSED) != 0;
if (focused) {
if (io.WantSetMousePos) {
glfwSetCursorPos(imgui_window, (double) mouse_pos_backup.x, (double) mouse_pos_backup.y);
} else {
double mouse_x = 0;
double mouse_y = 0;
glfwGetCursorPos(imgui_window, &mouse_x, &mouse_y);
io.MousePos = ImVec2((float) mouse_x, (float) mouse_y);
}
}
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
glfwSetCursor(imgui_window, mouse_cursors[imgui_cursor] ? mouse_cursors[imgui_cursor] : mouse_cursors[ImGuiMouseCursor_Arrow]);
glfwSetInputMode(imgui_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
void imgui_shutdown(void) {
bgfx::destroy(imgui_font_uniform);
bgfx::destroy(imgui_font_texture);
bgfx::destroy(imgui_program);
ImGui::DestroyContext();
}
const char *imgui_get_clipboard_text(void *user_data) {
return glfwGetClipboardString((GLFWwindow *) user_data);
}
void imgui_set_clipboard_text(void *user_data, const char *text) {
glfwSetClipboardString((GLFWwindow *) user_data, text);
}

68
src/engine/object.cpp Normal file
View File

@ -0,0 +1,68 @@
#include "assimp/mesh.h"
#include "assimp/vector3.h"
#include "common.hpp"
#include "glm/fwd.hpp"
#include <engine/object.hpp>
#include <bgfx/bgfx.h>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
EngineObject::EngineObject() {
this->position = glm::vec4(0.0f, 0.0f, 1.0f, 0.0f);
this->rotation = glm::vec4(0.0f);
this->scale = glm::vec4(1.0f);
this->layout.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
.end();
}
int EngineObject::load_node(aiScene *scene, aiNode *node) {
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
aiMesh *mesh = scene->mMeshes[i];
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
this->vertices.push_back(mesh->mVertices[j].x);
this->vertices.push_back(mesh->mVertices[j].y);
this->vertices.push_back(mesh->mVertices[j].z);
}
for (unsigned int j = 0; j < mesh->mNumFaces; ++j) {
aiFace *face = &(mesh->mFaces[j]);
this->indices.insert(this->indices.end(), &face->mIndices[0], &face->mIndices[face->mNumIndices]);
}
}
for (int i = 0; i < node->mNumChildren; ++i) {
this->load_node(scene, node->mChildren[i]);
}
return 0;
}
int EngineObject::load_model(std::string filename) {
Assimp::Importer importer;
aiScene *scene = (aiScene *) importer.ReadFile(filename, aiProcess_Triangulate | aiProcess_FlipUVs);
if (scene == nullptr || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
std::cout << "--error: failed loading model from file-system" << std::endl;
return -1;
}
aiNode *root = scene->mRootNode;
int ret = this->load_node(scene, root);
if (ret < 0) {
std::cout << "-error: failed loading node tree" << std::endl;
return -1;
}
this->vbh = bgfx::createVertexBuffer(bgfx::makeRef(
this->vertices.data(),
this->vertices.size()*sizeof(float)),
this->layout);
this->ibh = bgfx::createIndexBuffer(bgfx::makeRef(
this->indices.data(),
this->indices.size()*sizeof(unsigned int)),
BGFX_BUFFER_INDEX32);
return 0;
}

26
src/engine/quad.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <engine/quad.hpp>
#include <bgfx/bgfx.h>
EngineQuad::EngineQuad(void) {
this->vertices = {
{-0.5f, -0.5f, 0.0f, 0, 1},
{-0.5f, 0.5f, 0.0f, 0, 0},
{0.5f, -0.5f, 0.0f, 1, 1},
{0.5f, 0.5f, 0.0f, 1, 0}
};
this->indices = {0, 1, 2, 1, 2, 3};
this->layout.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
.end();
}
EngineQuad::EngineQuad(std::vector<VertexData> _v, std::vector<uint16_t> _i) {
this->vertices = _v;
this->indices = _i;
this->layout.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
.end();
}

34
src/pgv.cpp Normal file
View File

@ -0,0 +1,34 @@
#include <bgfx/bgfx.h>
#include <GLFW/glfw3.h>
#include <common.hpp>
#include <engine.hpp>
#include <engine/animation.hpp>
#include <chrono>
#define GET_MS \
std::chrono::duration_cast<std::chrono::milliseconds>( \
std::chrono::system_clock::now().time_since_epoch() \
);
int main(int argc, char *argv[]) {
Engine engine;
int ret = engine.Init();
std::cout << "ret " << ret << std::endl;
if (ret < 0) {
ERROR("failed initializing engine");
return EXIT_FAILURE;
}
EngineObject obj;
obj.load_model("models/cube.obj");
obj.position.z = -30.0f;
engine.Instantiate(&obj);
while (!glfwWindowShouldClose(engine.main_window)) {
engine.Update();
}
engine.Shutdown();
return EXIT_SUCCESS;
}

1
thirdparty/assimp.cmake vendored Submodule

@ -0,0 +1 @@
Subproject commit d41511bf8a7c3e84584788306da6a5c812ca9a6a

1
thirdparty/bgfx.cmake vendored Submodule

@ -0,0 +1 @@
Subproject commit cf79284dad04727eb56cbdbd81e641627484fa09

1
thirdparty/glfw.cmake vendored Submodule

@ -0,0 +1 @@
Subproject commit e7ea71be039836da3a98cea55ae5569cb5eb885c

1
thirdparty/glm.cmake vendored Submodule

@ -0,0 +1 @@
Subproject commit dca38025fba63bb9284023e6de55f756b9e37cec

1
thirdparty/imgui.cmake vendored Submodule

@ -0,0 +1 @@
Subproject commit 21a8fa1d0f46f100c142dace636bae85699e5aeb