Add test project; work on gfx

This commit is contained in:
bailwillharr 2022-11-07 20:15:26 +00:00
parent 3c4fb0de10
commit f4fd782930
43 changed files with 843 additions and 52 deletions

View File

@ -1,6 +1,9 @@
cmake_minimum_required(VERSION 3.8) cmake_minimum_required(VERSION 3.8)
# options # options
option(ENGINE_BUILD_TEST "Compile the test program" ON)
option(ENGINE_BUILD_VULKAN "Use Vulkan 1.3 for graphics" ON)
option(ENGINE_BUILD_OPENGL "Use OpenGL 4.5 for graphics" OFF)
project(engine LANGUAGES CXX project(engine LANGUAGES CXX
VERSION "0.1.0" VERSION "0.1.0"
@ -106,7 +109,20 @@ target_include_directories(${PROJECT_NAME} PRIVATE src)
configure_file(config.h.in config.h) configure_file(config.h.in config.h)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
# figure out what graphics api to use
if (ENGINE_BUILD_VULKAN)
target_compile_definitions(${PROJECT_NAME} PRIVATE "ENGINE_BUILD_VULKAN") target_compile_definitions(${PROJECT_NAME} PRIVATE "ENGINE_BUILD_VULKAN")
elseif(ENGINE_BUILD_OPENGL)
target_compile_definitions(${PROJECT_NAME} PRIVATE "ENGINE_BUILD_OPENGL")
else()
target_compile_definitions(${PROJECT_NAME} PRIVATE "ENGINE_BUILD_NULL")
endif()
# Build the test
if (ENGINE_BUILD_TEST)
add_subdirectory(test)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:enginetest>)
endif()
# external libraries: # external libraries:
@ -126,7 +142,6 @@ endif()
set(GLAD_SPEC "gl" CACHE INTERNAL "" FORCE) set(GLAD_SPEC "gl" CACHE INTERNAL "" FORCE)
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
add_subdirectory(dependencies/glad) add_subdirectory(dependencies/glad)
set_property(TARGET glad PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(${PROJECT_NAME} PUBLIC glad) target_link_libraries(${PROJECT_NAME} PUBLIC glad)
target_include_directories(${PROJECT_NAME} PUBLIC dependencies/glad/include) target_include_directories(${PROJECT_NAME} PUBLIC dependencies/glad/include)

View File

@ -32,7 +32,7 @@ namespace engine {
gfx::Pipeline* createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat, uint64_t uniformBufferSize); gfx::Pipeline* createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat, uint64_t uniformBufferSize);
void destroyPipeline(const gfx::Pipeline* pipeline); void destroyPipeline(const gfx::Pipeline* pipeline);
void updateUniformBuffer(const gfx::Pipeline* pipeline, void* data); void updateUniformBuffer(const gfx::Pipeline* pipeline, void* data, size_t size, uint32_t offset);
gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data); gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data);
void destroyBuffer(const gfx::Buffer* buffer); void destroyBuffer(const gfx::Buffer* buffer);

View File

@ -22,8 +22,8 @@ public:
~Shader() override; ~Shader() override;
struct UniformBuffer { struct UniformBuffer {
glm::mat4 v;
glm::mat4 p; glm::mat4 p;
glm::vec4 color;
}; };
gfx::Pipeline* getPipeline() gfx::Pipeline* getPipeline()

View File

@ -38,13 +38,9 @@ void Camera::updateCam(glm::mat4 transform, glm::mat4* viewMatOut)
glm::mat4 viewMatrix = glm::inverse(transform); glm::mat4 viewMatrix = glm::inverse(transform);
struct { resources::Shader::UniformBuffer uniformData{};
glm::mat4 view;
glm::mat4 proj;
} uniformData{};
uniformData.view = viewMatrix; uniformData.p = m_projMatrix;
uniformData.proj = m_projMatrix;
using namespace resources; using namespace resources;
@ -54,7 +50,7 @@ void Camera::updateCam(glm::mat4 transform, glm::mat4* viewMatOut)
auto lockedPtr = resPtr.lock(); auto lockedPtr = resPtr.lock();
auto shader = dynamic_cast<Shader*>(lockedPtr.get()); auto shader = dynamic_cast<Shader*>(lockedPtr.get());
// SET VIEW TRANSFORM HERE // SET VIEW TRANSFORM HERE
gfxdev->updateUniformBuffer(shader->getPipeline(), &uniformData); gfxdev->updateUniformBuffer(shader->getPipeline(), &uniformData.p, sizeof(uniformData.p), offsetof(resources::Shader::UniformBuffer, p));
} }
*viewMatOut = viewMatrix; *viewMatOut = viewMatrix;

View File

@ -1,5 +1,7 @@
#include "components/mesh_renderer.hpp" #include "components/mesh_renderer.hpp"
#include "resources/shader.hpp"
#include "object.hpp" #include "object.hpp"
#include "resource_manager.hpp" #include "resource_manager.hpp"
@ -25,6 +27,10 @@ Renderer::~Renderer()
void Renderer::render(glm::mat4 transform, glm::mat4 view) void Renderer::render(glm::mat4 transform, glm::mat4 view)
{ {
resources::Shader::UniformBuffer uniformData{};
uniformData.color = glm::vec4{ m_color.r, m_color.g, m_color.b, 1.0 };
gfxdev->updateUniformBuffer(m_shader->getPipeline(), &uniformData.color, sizeof(uniformData.color), offsetof(resources::Shader::UniformBuffer, color));
glm::mat4 pushConsts[] = { transform, view }; glm::mat4 pushConsts[] = { transform, view };
gfxdev->draw(m_shader->getPipeline(), m_mesh->vb, m_mesh->ib, m_mesh->m_vertices.size(), pushConsts, sizeof(glm::mat4) * 2); gfxdev->draw(m_shader->getPipeline(), m_mesh->vb, m_mesh->ib, m_mesh->m_vertices.size(), pushConsts, sizeof(glm::mat4) * 2);
} }

View File

@ -1,29 +1,70 @@
// The implementation of the graphics layer using OpenGL 4.5 // The implementation of the graphics layer using OpenGL 4.5
// This uses SDL specific code // This uses SDL specific code
//#undef ENGINE_BUILD_OPENGL
#ifdef ENGINE_BUILD_OPENGL #ifdef ENGINE_BUILD_OPENGL
#include "gfx_device.hpp" #include "gfx_device.hpp"
#include "util.hpp"
#include "config.h"
#include "log.hpp" #include "log.hpp"
#include <glad/glad.h> #include <glad/glad.h>
#include <SDL2/SDL.h> #include <SDL_video.h>
#include <assert.h>
#include <unordered_set>
#include <array>
#include <fstream> #include <fstream>
#include <filesystem>
#include <optional>
namespace engine { namespace engine {
// EXTERNED GLOBAL VARIABLE
GFXDevice* gfxdev = nullptr;
// structures and enums // structures and enums
// handles
struct gfx::Buffer {
gfx::BufferType type;
// TODO
};
struct gfx::Pipeline {
// TODO
};
// enum converters
namespace vkinternal {
/*
static GLenum getVertexAttribFormat(gfx::VertexAttribFormat fmt)
{
switch (fmt) {
case gfx::VertexAttribFormat::VEC2:
return VK_FORMAT_R32G32_SFLOAT;
case gfx::VertexAttribFormat::VEC3:
return VK_FORMAT_R32G32B32_SFLOAT;
}
throw std::runtime_error("Unknown vertex attribute format");
}
static VkBufferUsageFlagBits getBufferUsageFlag(gfx::BufferType type)
{
switch (type) {
case gfx::BufferType::VERTEX:
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
case gfx::BufferType::INDEX:
return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
}
throw std::runtime_error("Unknown buffer type");
}*/
}
// functions
static std::vector<char> readFile(const std::string& filename) static std::vector<char> readFile(const std::string& filename)
{ {
std::ifstream file(filename, std::ios::ate | std::ios::binary); std::ifstream file(filename, std::ios::ate | std::ios::binary);
@ -37,21 +78,37 @@ namespace engine {
return buffer; return buffer;
} }
// class definitions // class definitions
struct GFXDevice::Impl { struct GFXDevice::Impl {
SDL_GLContext context = nullptr; SDL_Window* window = nullptr;
uint64_t FRAMECOUNT = 0;
SDL_GLContext context;
}; };
GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window) GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window)
{ {
if (gfxdev != nullptr) {
throw std::runtime_error("There can only be one graphics device");
}
gfxdev = this;
pimpl = std::make_unique<Impl>(); pimpl = std::make_unique<Impl>();
pimpl->window = window;
pimpl->context = SDL_GL_CreateContext(window); pimpl->context = SDL_GL_CreateContext(window);
if (pimpl->context == NULL) {
throw std::runtime_error("Unable to create OpenGL context: " + std::string(SDL_GetError()));
}
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
throw std::runtime_error("Unable to initialise GLAD");
}
} }
@ -62,42 +119,66 @@ namespace engine {
SDL_GL_DeleteContext(pimpl->context); SDL_GL_DeleteContext(pimpl->context);
} }
void GFXDevice::drawBuffer(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, uint32_t count) void GFXDevice::getViewportSize(uint32_t* w, uint32_t* h)
{ {
int width, height;
SDL_GL_GetDrawableSize(pimpl->window, &width, &height);
*w = (uint32_t)width;
*h = (uint32_t)height;
} }
void GFXDevice::drawIndexed(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t indexCount) void GFXDevice::draw(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t count, const void* pushConstantData, size_t pushConstantSize)
{ {
assert(vertexBuffer->type == gfx::BufferType::VERTEX);
assert(vertexBuffer != nullptr);
assert(indexBuffer == nullptr || indexBuffer->type == gfx::BufferType::INDEX);
} }
void GFXDevice::renderFrame() void GFXDevice::renderFrame()
{ {
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(pimpl->window);
pimpl->FRAMECOUNT++;
} }
gfx::Pipeline* GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat) gfx::Pipeline* GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat, uint64_t uniformBufferSize)
{ {
return nullptr; gfx::Pipeline* pipeline = new gfx::Pipeline{};
return pipeline;
} }
void GFXDevice::destroyPipeline(const gfx::Pipeline* pipeline) void GFXDevice::destroyPipeline(const gfx::Pipeline* pipeline)
{
delete pipeline;
}
void GFXDevice::updateUniformBuffer(const gfx::Pipeline* pipeline, void* data)
{ {
} }
gfx::Buffer* GFXDevice::createBuffer(gfx::BufferType type, uint64_t size, const void* data) gfx::Buffer* GFXDevice::createBuffer(gfx::BufferType type, uint64_t size, const void* data)
{ {
return nullptr; auto out = new gfx::Buffer{};
out->type = type;
return out;
} }
void GFXDevice::destroyBuffer(const gfx::Buffer* buffer) void GFXDevice::destroyBuffer(const gfx::Buffer* buffer)
{ {
delete buffer;
} }
void GFXDevice::waitIdle() void GFXDevice::waitIdle()
{ {
glFinish(); //glFinish();
} }
} }

View File

@ -1175,8 +1175,10 @@ namespace engine {
void GFXDevice::getViewportSize(uint32_t *w, uint32_t *h) void GFXDevice::getViewportSize(uint32_t *w, uint32_t *h)
{ {
*w = pimpl->swapchain.extent.width; int width, height;
*h = pimpl->swapchain.extent.height; SDL_Vulkan_GetDrawableSize(pimpl->window, &width, &height);
*w = (uint32_t)width;
*h = (uint32_t)height;
} }
void GFXDevice::draw(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t count, const void* pushConstantData, size_t pushConstantSize) void GFXDevice::draw(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t count, const void* pushConstantData, size_t pushConstantSize)
@ -1600,15 +1602,17 @@ namespace engine {
delete pipeline; delete pipeline;
} }
void GFXDevice::updateUniformBuffer(const gfx::Pipeline* pipeline, void* data) void GFXDevice::updateUniformBuffer(const gfx::Pipeline* pipeline, void* data, size_t size, uint32_t offset)
{ {
assert(size <= pipeline->uniformBuffers[0]->size);
VkResult res; VkResult res;
void* uniformDest;
for (gfx::Buffer* buffer : pipeline->uniformBuffers) { for (gfx::Buffer* buffer : pipeline->uniformBuffers) {
void* uniformDest;
res = vmaMapMemory(pimpl->allocator, buffer->allocation, &uniformDest); res = vmaMapMemory(pimpl->allocator, buffer->allocation, &uniformDest);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
memcpy(uniformDest, data, buffer->size); memcpy((uint8_t*)uniformDest + offset, data, size);
vmaUnmapMemory(pimpl->allocator, buffer->allocation); vmaUnmapMemory(pimpl->allocator, buffer->allocation);
} }

View File

@ -31,6 +31,9 @@ namespace engine {
#ifdef ENGINE_BUILD_VULKAN #ifdef ENGINE_BUILD_VULKAN
windowFlags |= SDL_WINDOW_VULKAN; windowFlags |= SDL_WINDOW_VULKAN;
#endif #endif
#ifdef ENGINE_BUILD_OPENGL
windowFlags |= SDL_WINDOW_OPENGL;
#endif
if (m_resizable) { if (m_resizable) {
windowFlags |= SDL_WINDOW_RESIZABLE; windowFlags |= SDL_WINDOW_RESIZABLE;
@ -58,21 +61,6 @@ namespace engine {
const int WINDOWED_MIN_HEIGHT = 480; const int WINDOWED_MIN_HEIGHT = 480;
SDL_SetWindowMinimumSize(m_handle, WINDOWED_MIN_WIDTH, WINDOWED_MIN_HEIGHT); SDL_SetWindowMinimumSize(m_handle, WINDOWED_MIN_WIDTH, WINDOWED_MIN_HEIGHT);
/*
m_glContext = SDL_GL_CreateContext(m_handle);
if (m_glContext == NULL) {
SDL_DestroyWindow(m_handle);
SDL_Quit();
throw std::runtime_error("Unable to create OpenGL context: " + std::string(SDL_GetError()));
}
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
SDL_DestroyWindow(m_handle);
SDL_Quit();
throw std::runtime_error("Unable to initialise GLAD");
}
*/
// onResize(m_winSize.x, m_winSize.y); // onResize(m_winSize.x, m_winSize.y);
} }

53
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,53 @@
cmake_minimum_required(VERSION 3.12)
# options
project(enginetest LANGUAGES CXX
VERSION "0.1.0"
)
set(GAME_SOURCES
src/main.cpp
src/game.cpp
src/game.hpp
src/meshgen.cpp
src/meshgen.hpp
src/terrain.cpp
src/terrain.hpp
src/camera_controller.cpp
src/camera_controller.hpp
)
if (WIN32)
add_executable(${PROJECT_NAME} WIN32 ${GAME_SOURCES} "game.rc")
else()
add_executable(${PROJECT_NAME} ${GAME_SOURCES})
endif()
# compiling options:
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
if (MSVC)
target_compile_options(${PROJECT_NAME} PRIVATE /W3)
target_compile_options(${PROJECT_NAME} PRIVATE /MP)
endif()
target_include_directories(${PROJECT_NAME} PRIVATE src)
# Pass some project information into the source code
configure_file(config.h.in config.h)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE engine)
target_include_directories(${PROJECT_NAME} PRIVATE ../include)
add_custom_command(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink
${PROJECT_SOURCE_DIR}/res $<TARGET_FILE_DIR:enginetest>/res)

1
test/README Normal file
View File

@ -0,0 +1 @@
A random game made using my game engine

4
test/config.h.in Normal file
View File

@ -0,0 +1,4 @@
#pragma once
#define PROJECT_VERSION "@PROJECT_VERSION@"
#define PROJECT_NAME "@PROJECT_NAME@"

1
test/game.rc Normal file
View File

@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "icon1.ico"

BIN
test/icon1.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

BIN
test/res/meshes/cube.mesh Normal file

Binary file not shown.

BIN
test/res/meshes/donut.mesh Normal file

Binary file not shown.

BIN
test/res/meshes/gun.mesh Normal file

Binary file not shown.

BIN
test/res/meshes/monke.mesh Normal file

Binary file not shown.

36
test/res/shader.frag Normal file
View File

@ -0,0 +1,36 @@
#version 450
layout(location = 0) in vec3 fragPos;
layout(location = 1) in vec3 fragNorm;
layout(location = 2) in vec2 fragUV;
layout(location = 3) in vec3 fragLightPos;
layout(location = 4) in vec3 fragColor;
layout(location = 0) out vec4 outColor;
void main() {
// constants
vec3 lightColor = vec3(1.0, 1.0, 1.0);
vec3 ambientColor = vec3(1.0, 1.0, 1.0);
float ambientStrength = 0.1;
vec3 baseColor = fragColor;
vec3 emission = vec3(0.0, 0.0, 0.0);
// code
vec3 norm = normalize(fragNorm);
vec3 lightDir = normalize(fragLightPos - fragPos);
vec3 diffuse = max(dot(norm, lightDir), 0.0) * lightColor;
vec3 ambient = ambientColor * ambientStrength;
vec3 viewDir = normalize(-fragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = 0.5 * spec * lightColor;
vec3 lighting = min(diffuse + ambient + specular, 1.0);
outColor = min( ( vec4(baseColor, 1.0) ) * vec4(lighting + emission, 1.0), vec4(1.0));
}

BIN
test/res/shader.frag.spv Normal file

Binary file not shown.

31
test/res/shader.vert Normal file
View File

@ -0,0 +1,31 @@
#version 450
layout(binding = 0) uniform UBO {
mat4 proj;
vec4 color;
} ubo;
layout( push_constant ) uniform Constants {
mat4 model;
mat4 view;
} constants;
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inNorm;
layout(location = 2) in vec2 inUV;
layout(location = 0) out vec3 fragPos;
layout(location = 1) out vec3 fragNorm;
layout(location = 2) out vec2 fragUV;
layout(location = 3) out vec3 fragLightPos;
layout(location = 4) out vec3 fragColor;
void main() {
gl_Position = ubo.proj * constants.view * constants.model * vec4(inPosition, 1.0);
fragPos = vec3(constants.view * constants.model * vec4(inPosition, 1.0));
fragNorm = mat3(transpose(inverse(constants.view * constants.model))) * inNorm;
fragUV = inUV;
vec3 lightPos = vec3(-5.0, 20.0, 5.0);
fragLightPos = vec3(constants.view * vec4(lightPos, 1.0));
fragColor = ubo.color.rgb;
}

BIN
test/res/shader.vert.spv Normal file

Binary file not shown.

View File

@ -0,0 +1,37 @@
#version 330
uniform float ambientStrength;
uniform vec3 ambientColor;
uniform vec3 lightColor;
uniform vec3 emission;
uniform vec3 baseColor;
uniform sampler2D tex;
in vec3 f_Pos;
in vec3 f_Norm;
in vec2 f_UV;
in vec3 f_lightPos;
out vec4 FragColor;
void main() {
vec3 norm = normalize(f_Norm);
vec3 lightDir = normalize(f_lightPos - f_Pos);
vec3 diffuse = max(dot(norm, lightDir), 0.0) * lightColor;
vec3 ambient = ambientColor * ambientStrength;
vec3 viewDir = normalize(-f_Pos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = 0.5 * spec * lightColor;
vec3 lighting = min(diffuse + ambient + specular, 1.0);
FragColor = min( ( vec4(baseColor, 1.0) * texture(tex, f_UV) ) * vec4(lighting + emission, 1.0), vec4(1.0));
}

View File

@ -0,0 +1,26 @@
#version 330
layout (location = 0) in vec3 v_Position;
layout (location = 1) in vec3 v_Norm;
layout (location = 2) in vec2 v_UV;
uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projMat;
uniform vec3 lightPos;
out vec3 f_Pos;
out vec3 f_Norm;
out vec2 f_UV;
out vec3 f_lightPos;
void main()
{
gl_Position = projMat * viewMat * modelMat * vec4(v_Position, 1.0);
f_Pos = vec3(viewMat * modelMat * vec4(v_Position, 1.0));
f_Norm = mat3(transpose(inverse(viewMat * modelMat))) * v_Norm;
f_UV = v_UV;
f_lightPos = vec3(viewMat * vec4(lightPos, 1.0));
}

View File

@ -0,0 +1,14 @@
#version 330
uniform vec3 textColor;
uniform sampler2D tex;
in vec2 f_UV;
out vec4 FragColor;
void main()
{
FragColor = vec4(textColor, texture(tex, f_UV).r);
}

View File

@ -0,0 +1,25 @@
#version 330
uniform vec2 windowSize;
uniform bool textScaling; // true means keep text aspect ratio
layout (location = 0) in vec3 v_Position;
layout (location = 2) in vec2 v_UV;
uniform mat4 modelMat;
out vec2 f_UV;
void main()
{
float aspect = windowSize.y / windowSize.x;
vec3 pos = v_Position;
if (textScaling) {
pos.x *= aspect;
}
gl_Position = modelMat * vec4(pos, 1.0);
f_UV = v_UV;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
test/res/textures/gun.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
test/res/textures/white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

View File

@ -0,0 +1,118 @@
#include "camera_controller.hpp"
#include "object.hpp"
#include "window.hpp"
#include "input.hpp"
#include <glm/trigonometric.hpp>
#include <glm/gtc/constants.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <log.hpp>
CameraController::CameraController(engine::Object* parent) :
CustomComponent(parent)
{
standingHeight = parent->transform.position.y;
m_yaw = glm::half_pi<float>();
}
void CameraController::onUpdate(glm::mat4 t)
{
// calculate new position
// use one unit per meter
const float dt = win.dt();
// jumping
constexpr float G = 9.8f;
constexpr float JUMPHEIGHT = 16.0f * 25.4f / 1000.0f; // 16 inches
constexpr float JUMPVEL = (float)2.82231110971133017648; //std::sqrt(2 * G * JUMPHEIGHT);
//constexpr float JUMPDURATION = 0.5f;
//constexpr float JUMPVEL = G * JUMPDURATION / 2.0f;
if (inp.getButton("jump") && isJumping == false) {
isJumping = true;
dy = JUMPVEL;
//standingHeight = tcomp->position.y;
}
if (isJumping) {
dy -= G * dt;
parent.transform.position.y += dy * dt;
if (parent.transform.position.y < standingHeight) {
isJumping = false;
dy = 0.0f;
parent.transform.position.y = standingHeight;
}
}
if (win.getButton(engine::inputs::MouseButton::M_LEFT)) {
//standingHeight = tcomp->position.y;
dy += dt * thrust;
isJumping = true;
}
// in metres per second
//constexpr float SPEED = 1.5f;
float SPEED = walk_speed;
if (win.getKey(engine::inputs::Key::LSHIFT)) SPEED *= 10.0f;
const float dx = inp.getAxis("movex") * SPEED;
const float dz = (-inp.getAxis("movey")) * SPEED;
// calculate new pitch and yaw
constexpr float MAX_PITCH = glm::half_pi<float>();
constexpr float MIN_PITCH = -MAX_PITCH;
float dPitch = inp.getAxis("looky") * -1.0f * m_cameraSensitivity;
m_pitch += dPitch;
if (m_pitch <= MIN_PITCH || m_pitch >= MAX_PITCH) {
m_pitch -= dPitch;
}
m_yaw += inp.getAxis("lookx") * -1.0f * m_cameraSensitivity;
// update position relative to camera direction in xz plane
const glm::vec3 d2xRotated = glm::rotateY(glm::vec3{ dx, 0.0f, 0.0f }, m_yaw);
const glm::vec3 d2zRotated = glm::rotateY(glm::vec3{ 0.0f, 0.0f, dz }, m_yaw);
parent.transform.position += (d2xRotated + d2zRotated) * dt;
parent.transform.position.y += dy * dt;
// pitch quaternion
const float halfPitch = m_pitch / 2.0f;
glm::quat pitchQuat{};
pitchQuat.x = glm::sin(halfPitch);
pitchQuat.y = 0.0f;
pitchQuat.z = 0.0f;
pitchQuat.w = glm::cos(halfPitch);
// yaw quaternion
const float halfYaw = m_yaw / 2.0f;
glm::quat yawQuat{};
yawQuat.x = 0.0f;
yawQuat.y = glm::sin(halfYaw);
yawQuat.z = 0.0f;
yawQuat.w = glm::cos(halfYaw);
// update rotation
parent.transform.rotation = yawQuat * pitchQuat;
if (win.getKeyPress(engine::inputs::Key::P)) {
std::string pos_string{
"x: " + std::to_string(parent.transform.position.x) +
" y: " + std::to_string(parent.transform.position.y) +
" z: " + std::to_string(parent.transform.position.z)
};
#ifdef NDEBUG
win.infoBox("POSITION", pos_string);
#endif
INFO("position: " + pos_string);
}
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "components/custom.hpp"
class CameraController : public engine::components::CustomComponent {
public:
CameraController(engine::Object* parent);
void onUpdate(glm::mat4 t) override;
float m_cameraSensitivity = 0.007f;
private:
float m_yaw = 0.0f;
float m_pitch = 0.0f;
float walk_speed = 4.0f;
bool isJumping = false;
float dy = 0.0f;
float standingHeight = 0.0f;
float thrust = 25.0f;
};

122
test/src/game.cpp Normal file
View File

@ -0,0 +1,122 @@
#include "config.h"
#include "engine.hpp"
#include "window.hpp"
#include "input.hpp"
#include "sceneroot.hpp"
#include "components/camera.hpp"
#include "components/mesh_renderer.hpp"
#include "camera_controller.hpp"
#include "meshgen.hpp"
#include <glm/gtc/quaternion.hpp>
#include <log.hpp>
void playGame()
{
engine::Application app(PROJECT_NAME, PROJECT_VERSION);
// configure window
app.window()->setRelativeMouseMode(true);
// input config
// game buttons
app.input()->addInputButton("fire", engine::inputs::MouseButton::M_LEFT);
app.input()->addInputButton("aim", engine::inputs::MouseButton::M_RIGHT);
app.input()->addInputButton("jump", engine::inputs::Key::SPACE);
app.input()->addInputButton("sneak", engine::inputs::Key::LSHIFT);
// game movement
app.input()->addInputButtonAsAxis("movex", engine::inputs::Key::D, engine::inputs::Key::A);
app.input()->addInputButtonAsAxis("movey", engine::inputs::Key::W, engine::inputs::Key::S);
// looking around
app.input()->addInputAxis("lookx", engine::inputs::MouseAxis::X);
app.input()->addInputAxis("looky", engine::inputs::MouseAxis::Y);
// create the scene
auto cam = app.scene()->createChild("cam");
constexpr float HEIGHT_INCHES = 6.0f * 12.0f;
// eye level is about 4 1/2 inches below height
constexpr float EYE_LEVEL = (HEIGHT_INCHES - 4.5f) * 25.4f / 1000.0f;
cam->transform.position = { 0.0f, EYE_LEVEL, 0.0f };
auto camCamera = cam->createComponent<engine::components::Camera>();
camCamera->usePerspective(70.0f);
cam->createComponent<CameraController>();
cam->createComponent<engine::components::Renderer>()->m_mesh = genSphereMesh(0.2f, 20);
cam->getComponent<engine::components::Renderer>()->setTexture("textures/cobble_stone.png");
auto gun = cam->createChild("gun");
gun->transform.position = glm::vec3{ 0.2f, -0.1f, -0.15f };
gun->transform.rotation = glm::angleAxis(glm::pi<float>(), glm::vec3{ 0.0f, 1.0f, 0.0f });
float GUN_SCALE = 9.0f / 560.0f;
GUN_SCALE *= 1.0f;
gun->transform.scale *= GUN_SCALE;
auto gunRenderer = gun->createComponent<engine::components::Renderer>();
gunRenderer->setMesh("meshes/gun.mesh");
gunRenderer->setTexture("textures/gun.png");
gunRenderer->m_color = { 0.2f, 0.3f, 0.2f };
// FLOOR
constexpr float GRASS_DENSITY = 128.0f * 20.0f;
auto floor = app.scene()->createChild("floor");
auto floorRenderer = floor->createComponent<engine::components::Renderer>();
floor->transform.position = glm::vec3{ 0.0f, 0.0f, 0.0f };
floorRenderer->setTexture("textures/stone_bricks.png");
floorRenderer->m_mesh = std::make_unique<engine::resources::Mesh>(std::vector<Vertex>{
{ { -16.0f, 0.0f, 16.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, GRASS_DENSITY } },
{ { 16.0f, 0.0f, -16.0f }, { 0.0f, 1.0f, 0.0f }, { GRASS_DENSITY, 0.0f } },
{ { -16.0f, 0.0f, -16.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f } },
{ { 16.0f, 0.0f, 16.0f }, { 0.0f, 1.0f, 0.0f }, { GRASS_DENSITY, GRASS_DENSITY } },
{ { 16.0f, 0.0f, -16.0f }, { 0.0f, 1.0f, 0.0f }, { GRASS_DENSITY, 0.0f } },
{ { -16.0f, 0.0f, 16.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, GRASS_DENSITY } }
});
floor->transform.scale = { 100.0f, 1.0f, 100.0f };
floorRenderer->m_color = { 0.1f, 0.9f, 0.1f };
auto cube = app.scene()->createChild("cube");
auto cubeRen = cube->createComponent<engine::components::Renderer>();
cubeRen->setMesh("meshes/cube.mesh");
cubeRen->m_color = { 0.8f, 0.2f, 0.05f };
cube->transform.position = glm::vec3{ -5.0f, 1.0f, 0.0f };
class Spin : public engine::components::CustomComponent {
public:
Spin(engine::Object* parent) : CustomComponent(parent)
{
}
void onUpdate(glm::mat4 t) override
{
m_yaw += win.dt();
m_yaw = glm::mod(m_yaw, glm::two_pi<float>());
const float halfYaw = m_yaw / 2.0f;
glm::quat yawQuat{};
yawQuat.x = 0.0f;
yawQuat.y = glm::sin(halfYaw);
yawQuat.z = 0.0f;
yawQuat.w = glm::cos(halfYaw);
parent.transform.rotation = yawQuat;
}
private:
float m_yaw = 0.0f;
};
app.scene()->getChild("cube")->createComponent<Spin>();
app.scene()->printTree();
app.gameLoop();
}

3
test/src/game.hpp Normal file
View File

@ -0,0 +1,3 @@
#pragma once
void playGame();

34
test/src/main.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "config.h"
#include "game.hpp"
#include "logger.hpp"
#include "window.hpp"
#include <exception>
int main(int argc, char *argv[])
{
engine::setupLog(PROJECT_NAME);
INFO("{} v{}", PROJECT_NAME, PROJECT_VERSION);
try {
playGame();
}
catch (const std::exception& e) {
CRITICAL("{}", e.what());
#ifdef NDEBUG
engine::Window::errorBox(e.what());
#else
fputs(e.what(), stderr);
fputc('\n', stderr);
#endif
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

135
test/src/meshgen.cpp Normal file
View File

@ -0,0 +1,135 @@
#include "meshgen.hpp"
#include <glm/gtc/constants.hpp>
#include <glm/ext.hpp>
#include <glm/trigonometric.hpp>
#include <iostream>
#include <thread>
std::unique_ptr<engine::resources::Mesh> genSphereMesh(float r, int detail, bool windInside)
{
using namespace glm;
std::vector<Vertex> vertices{};
float angleStep = two_pi<float>() / (float)detail;
for (int i = 0; i < detail; i++) {
// theta goes north-to-south
float theta = i * angleStep;
float theta2 = theta + angleStep;
for (int j = 0; j < detail/2; j++) {
// phi goes west-to-east
float phi = j * angleStep;
float phi2 = phi + angleStep;
vec3 top_left{ r * sin(phi) * cos(theta),
r * cos(phi),
r * sin(phi) * sin(theta) };
vec3 bottom_left{ r * sin(phi) * cos(theta2),
r * cos(phi),
r * sin(phi) * sin(theta2) };
vec3 top_right{ r * sin(phi2) * cos(theta),
r * cos(phi2),
r * sin(phi2) * sin(theta) };
vec3 bottom_right{ r * sin(phi2) * cos(theta2),
r * cos(phi2),
r * sin(phi2) * sin(theta2) };
if (windInside == false) {
// tris are visible from outside the sphere
// triangle 1
vertices.push_back({ top_left, {}, {0.0f, 0.0f} });
vertices.push_back({ bottom_left, {}, {0.0f, 1.0f} });
vertices.push_back({ bottom_right, {}, {1.0f, 1.0f} });
// triangle 2
vertices.push_back({ top_right, {}, {1.0f, 0.0f} });
vertices.push_back({ top_left, {}, {0.0f, 0.0f} });
vertices.push_back({ bottom_right, {}, {1.0f, 1.0f} });
}
else {
// tris are visible from inside the sphere
// triangle 1
vertices.push_back({ bottom_right, {}, {1.0f, 1.0f} });
vertices.push_back({ bottom_left, {}, {0.0f, 1.0f} });
vertices.push_back({ top_left, {}, {0.0f, 0.0f} });
// triangle 2
vertices.push_back({ bottom_right, {}, {1.0f, 1.0f} });
vertices.push_back({ top_left, {}, {0.0f, 0.0f} });
vertices.push_back({ top_right, {}, {1.0f, 0.0f} });
}
glm::vec3 vector1 = (vertices.end() - 1)->pos - (vertices.end() - 2)->pos;
glm::vec3 vector2 = (vertices.end() - 2)->pos - (vertices.end() - 3)->pos;
glm::vec3 norm = glm::normalize(glm::cross(vector1, vector2));
// TODO: FIX NORMALS
if (!windInside)
norm = -norm;
for (auto it = vertices.end() - 6; it != vertices.end(); it++) {
it->norm = norm;
}
}
}
return std::make_unique<engine::resources::Mesh>(vertices);
}
std::unique_ptr<engine::resources::Mesh> genCuboidMesh(float x, float y, float z)
{
// x goes ->
// y goes ^
// z goes into the screen
using glm::vec3;
std::vector<Vertex> v{};
// 0 top_left_front
v.push_back({{ 0.0f, y, 0.0f }, {}, {}});
// 1 bottom_left_front
v.push_back({{ 0.0f, 0.0f, 0.0f }, {}, {}});
// 2 top_right_front
v.push_back({{ x, y, 0.0f }, {}, {}});
// 3 bottom_right_front
v.push_back({{ x, 0.0f, 0.0f }, {}, {}});
// 4 top_left_back
v.push_back({{ 0.0f, y, z }, {}, {}});
// 5 bottom_left_back
v.push_back({{ 0.0f, 0.0f, z }, {}, {}});
// 6 top_right_back
v.push_back({{ x, y, z }, {}, {}});
// 7 bottom_right_back
v.push_back({{ x, 0.0f, z }, {}, {}});
// front quad
std::vector<unsigned int> indices{
// front
0, 1, 3, 2, 0, 3,
// back
4, 5, 7, 6, 4, 7,
// bottom
5, 1, 3, 7, 5, 3,
// top
4, 0, 2, 6, 4, 2,
// left
4, 5, 1, 0, 4, 1,
// right
2, 3, 7, 6, 2, 7
};
return std::make_unique<engine::resources::Mesh>(v, indices);
}

7
test/src/meshgen.hpp Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include "resources/mesh.hpp"
// generates a UV sphere
std::unique_ptr<engine::resources::Mesh> genSphereMesh(float r, int detail, bool windInside = false);
std::unique_ptr<engine::resources::Mesh> genCuboidMesh(float x, float y, float z);

21
test/src/terrain.cpp Normal file
View File

@ -0,0 +1,21 @@
#if 0
#include "terrain.hpp"
#include "resources/mesh.hpp"
std::unique_ptr<engine::resources::Mesh> getChunkMesh(int x, int y)
{
(void)x;
(void)y;
std::vector<Vertex> vertices{
{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
{{1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
{{0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}
};
return std::make_unique<engine::resources::Mesh>(vertices);
}
#endif

9
test/src/terrain.hpp Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <memory>
namespace engine::resources {
class Mesh;
}
std::unique_ptr<engine::resources::Mesh> getChunkMesh(int x, int y);