restructured project to match a more standard cmake setup

This commit is contained in:
Noel Berry
2020-12-31 13:43:23 -08:00
parent c841bd82a1
commit 241d863ac4
97 changed files with 233 additions and 264 deletions

View File

@ -0,0 +1,60 @@
#pragma once
#include <blah/core/app.h>
#include <blah/graphics/renderpass.h>
#include <blah/graphics/texture.h>
#include <blah/graphics/framebuffer.h>
#include <blah/graphics/shader.h>
#include <blah/graphics/mesh.h>
#include <blah/graphics/material.h>
#include <blah/math/color.h>
namespace Blah
{
// Graphics backend API used for rendering.
// All rendering ends up going through here.
namespace GraphicsBackend
{
// Initializes the graphics backend
bool init();
// Shuts down the graphics backend
void shutdown();
// Returns info about the renderer
const RendererFeatures& features();
// Returns the renderer type
Renderer renderer();
// Called once per frame
void frame();
// Called before rendering begins
void before_render();
// Called after renderings ends
void after_render();
// Performs a draw call
void render(const RenderPass& pass);
// Clears the backbuffer
void clear_backbuffer(Color color);
// Creates a new Texture.
// if the Texture is invalid, this should return an empty reference.
TextureRef create_texture(int width, int height, TextureFormat format);
// Creates a new FrameBuffer.
// if the FrameBuffer is invalid, this should return an empty reference.
FrameBufferRef create_framebuffer(int width, int height, const TextureFormat* attachments, int attachment_count);
// Creates a new Shader.
// if the Shader is invalid, this should return an empty reference.
ShaderRef create_shader(const ShaderData* data);
// Creates a new Mesh.
// if the Mesh is invalid, this should return an empty reference.
MeshRef create_mesh();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,235 @@
#if !(defined(BLAH_USE_OPENGL) || defined(BLAH_USE_D3D11))
#include "../internal/graphics_backend.h"
#include "../internal/platform_backend.h"
#include <blah/core/log.h>
namespace Blah
{
class Dummy_Texture : public Texture
{
private:
int m_width;
int m_height;
TextureFormat m_format;
bool m_framebuffer;
public:
Dummy_Texture(int width, int height, TextureFormat format, bool framebuffer)
{
m_width = width;
m_height = height;
m_format = format;
m_framebuffer = framebuffer;
}
virtual int width() const override
{
return m_width;
}
virtual int height() const override
{
return m_height;
}
virtual TextureFormat format() const override
{
return m_format;
}
virtual void set_data(unsigned char* data) override
{
}
virtual void get_data(unsigned char* data) override
{
}
virtual bool is_framebuffer() const override
{
return m_framebuffer;
}
};
class Dummy_FrameBuffer : public FrameBuffer
{
private:
Attachments m_attachments;
public:
Dummy_FrameBuffer(int width, int height, const TextureFormat* attachments, int attachmentCount)
{
for (int i = 0; i < attachmentCount; i++)
{
m_attachments.push_back(
TextureRef(new Dummy_Texture(width, height, attachments[i], true))
);
}
}
virtual Attachments& attachments() override
{
return m_attachments;
}
virtual const Attachments& attachments() const override
{
return m_attachments;
}
virtual TextureRef& attachment(int index) override
{
return m_attachments[index];
}
virtual const TextureRef& attachment(int index) const override
{
return m_attachments[index];
}
virtual int width() const override
{
return m_attachments[0]->width();
}
virtual int height() const override
{
return m_attachments[0]->height();
}
virtual void clear(Color color) override
{
}
};
class Dummy_Shader : public Shader
{
private:
Vector<UniformInfo> m_uniforms;
public:
Dummy_Shader(const ShaderData* data)
{
}
virtual Vector<UniformInfo>& uniforms() override
{
return m_uniforms;
}
virtual const Vector<UniformInfo>& uniforms() const override
{
return m_uniforms;
}
};
class Dummy_Mesh : public Mesh
{
private:
int64_t m_index_count = 0;
int64_t m_vertex_count = 0;
int64_t m_instance_count = 0;
public:
Dummy_Mesh()
{
}
virtual void index_data(IndexFormat format, const void* indices, int64_t count) override
{
m_index_count = count;
}
virtual void vertex_data(const VertexFormat& format, const void* vertices, int64_t count) override
{
m_vertex_count = count;
}
virtual void instance_data(const VertexFormat& format, const void* instances, int64_t count) override
{
m_instance_count = count;
}
virtual int64_t index_count() const override
{
return m_index_count;
}
virtual int64_t vertex_count() const override
{
return m_vertex_count;
}
virtual int64_t instance_count() const override
{
return m_instance_count;
}
};
bool GraphicsBackend::init()
{
Log::print("Dummy Renderer");
return true;
}
Renderer GraphicsBackend::renderer()
{
return Renderer::None;
}
void GraphicsBackend::shutdown()
{
}
const RendererFeatures& GraphicsBackend::features()
{
static const RendererFeatures features { false, true, 4096 };
return features;
}
void GraphicsBackend::frame() {}
void GraphicsBackend::before_render() {}
void GraphicsBackend::after_render() {}
TextureRef GraphicsBackend::create_texture(int width, int height, TextureFormat format)
{
return TextureRef(new Dummy_Texture(width, height, format, false));
}
FrameBufferRef GraphicsBackend::create_framebuffer(int width, int height, const TextureFormat* attachments, int attachmentCount)
{
return FrameBufferRef(new Dummy_FrameBuffer(width, height, attachments, attachmentCount));
}
ShaderRef GraphicsBackend::create_shader(const ShaderData* data)
{
return ShaderRef(new Dummy_Shader(data));
}
MeshRef GraphicsBackend::create_mesh()
{
return MeshRef(new Dummy_Mesh());
}
void GraphicsBackend::render(const RenderPass& pass)
{
}
void GraphicsBackend::clear_backbuffer(Color color)
{
}
}
#endif // !(defined(BLAH_USE_OPENGL) || defined(BLAH_USE_D3D11))

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
#pragma once
#include <blah/input/input.h>
namespace Blah
{
namespace InputBackend
{
// This is called internally by the app, and initializes the input state
void init();
// This is called internally by the app, and updates the input state
void frame();
// Call this when the Mouse moves relative to the window
void on_mouse_move(float x, float y);
// Call this when the Mouse moves relative to the screen
void on_mouse_screen_move(float x, float y);
// Call this when a Mouse Button is pressed
void on_mouse_down(MouseButton button);
// Call this when a Mouse Button is released
void on_mouse_up(MouseButton button);
// Call this when the Mouse Wheel moves
void on_mouse_wheel(Point wheel);
// Call this when a keyboard key is pressed
void on_key_down(Key key);
// Call this when a keyboard key is released
void on_key_up(Key key);
// Call this on Text Input
void on_text_utf8(const char* text);
// Call this when a Controller is connected. Note that the Name parameter must be kept valid
// until on_controller_disconnect is called with the same index.
void on_controller_connect(int index, const char* name, int isGamepad, int buttonCount, int axisCount, uint16_t vendor, uint16_t product, uint16_t version);
// Call this when a controller is disconnected
void on_controller_disconnect(int index);
// Call this when a controller button is pressed
void on_button_down(int index, int button);
// Call this when a controller button is released
void on_button_up(int index, int button);
/// Call this when a controller axis is moved
void on_axis_move(int index, int axis, float value);
}
}

View File

@ -0,0 +1,120 @@
#pragma once
#include <inttypes.h>
#include <blah/core/filesystem.h>
#include <blah/containers/vector.h>
namespace Blah
{
struct Config;
enum class FileMode;
namespace PlatformBackend
{
typedef void* FileHandle;
// Initialize the System
bool init(const Config* config);
// Called after the on_startup callback, but before the update loop begins
void ready();
// Called during shutdown
void shutdown();
// The time, in milliseconds, since the Application was started
uint64_t time();
// Called every frame
void frame();
// Sleeps the current thread
void sleep(int milliseconds);
// Called to present the window contents
void present();
// Gets the Application Window Title in UTF-8
const char* get_title();
// Sets the Application Window Title in UTF-8
void set_title(const char* title);
// Gets the Application Window Position, in Screen Coordinates
void get_position(int* x, int* y);
// Sets the Application Window Position, in Screen Coordinates
void set_position(int x, int y);
// Sets the Window Fullscreen if enabled is not 0
void set_fullscreen(bool enabled);
// Gets the Application Window Size, in Screen Coordinates
void get_size(int* width, int* height);
// Sets the Application Window Size, in Screen Coordinates
void set_size(int width, int height);
// Gets the Application Window Drawing Size, in Pixels. This may differ from the Window Size on hi-dpi displays.
void get_draw_size(int* width, int* height);
// Gets the Desktop Content Scale. Gui should be scaled by this value
float get_content_scale();
// Returns the absoluate path to the directory that the application was started from
const char* app_path();
// Returns the absolute path to the user directory where save data and settings should be stored
const char* user_path();
// Returns true if a file with the given path exists
bool file_exists(const char* path);
// Returns true if a file with the given path was deleted
bool file_delete(const char* path);
// Returns true if a directory with the given path was successfully created
bool dir_create(const char* path);
// Returns true if a directory with the given path exists
bool dir_exists(const char* path);
// Returns true if a directory with the given path was deleted
bool dir_delete(const char* path);
// enumerates a directory and appends each file to the given list
void dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive);
// opens a directory in the OS file explorer / finder
void dir_explore(const char* path);
// Opens a file and sets the handle. returns true if the file was successfully opened
bool file_open(const char* path, FileHandle* handle, FileMode mode);
// Returns the length of the file
int64_t file_length(FileHandle file);
// Returns the Position of the file
int64_t file_position(FileHandle file);
// Seeks the Position of the file and returns the new position from the start of the file
int64_t file_seek(FileHandle file, int64_t seekTo);
// Reads a specific number of elements of a given size from the file into ptr
int64_t file_read(FileHandle file, void* ptr, int64_t size);
// Writes a specific number of elements of the given size from ptr to the file
int64_t file_write(FileHandle file, const void* ptr, int64_t size);
// Closes a file
void file_close(FileHandle file);
// OpenGL Methods
void* gl_get_func(const char* name);
void* gl_context_create();
void gl_context_make_current(void* context);
void gl_context_destroy(void* context);
// D3D11 Methods
void* d3d11_get_hwnd();
}
}

View File

@ -0,0 +1,660 @@
#ifdef BLAH_USE_SDL2
#include "../internal/platform_backend.h"
#include "../internal/input_backend.h"
#include "../internal/graphics_backend.h"
#include <blah/input/input.h>
#include <blah/core/app.h>
#include <blah/core/filesystem.h>
#include <blah/core/log.h>
#include <SDL.h>
#include <SDL_vulkan.h>
#include <SDL_syswm.h>
#if _WIN32
// on Windows we're using the C++ <filesystem> API for now
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winuser.h> // for SetProcessDPIAware
#include <filesystem> // for File Reading/Writing
#include <shellapi.h> // for file explore
namespace fs = std::filesystem;
#else
// on non-Windows we use POSIX standard file system stuff
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#endif
using namespace Blah;
namespace
{
SDL_Window* window = nullptr;
SDL_Joystick* joysticks[Blah::Input::max_controllers];
SDL_GameController* gamepads[Blah::Input::max_controllers];
char* basePath = nullptr;
char* userPath = nullptr;
bool displayed = false;
void sdl_log(void* userdata, int category, SDL_LogPriority priority, const char* message)
{
if (priority <= SDL_LOG_PRIORITY_INFO)
Log::print(message);
else if (priority <= SDL_LOG_PRIORITY_WARN)
Log::warn(message);
else
Log::error(message);
}
}
bool PlatformBackend::init(const Config* config)
{
// Required to call this for Windows
// I'm not sure why SDL2 doesn't do this on Windows automatically?
#if _WIN32
SetProcessDPIAware();
#endif
// TODO:
// control this via some kind of config flag
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
SDL_LogSetOutputFunction(sdl_log, nullptr);
// Get SDL version
SDL_version version;
SDL_GetVersion(&version);
Log::print("SDL v%i.%i.%i", version.major, version.minor, version.patch);
// initialize SDL
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) != 0)
{
Log::error("Failed to initialize SDL2");
return false;
}
int flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE;
// enable OpenGL
if (App::renderer() == Renderer::OpenGL)
{
flags |= SDL_WINDOW_OPENGL;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// TODO:
// This should be controlled via the gfx api somehow?
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
}
// enable DirectX
else if (App::renderer() == Renderer::D3D11)
{
}
// create the window
window = SDL_CreateWindow(config->name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, config->width, config->height, flags);
if (window == nullptr)
{
Log::error("Failed to create a Window");
return false;
}
// Scale Window to monitor for High DPI displays
// Other platforms do this automatically ... Windows we need to explitely do so
#if _WIN32
{
// find the display index
int display = SDL_GetWindowDisplayIndex(window);
float ddpi, hdpi, vdpi;
if (SDL_GetDisplayDPI(display, &ddpi, &hdpi, &vdpi) == 0)
{
// scale the window up basesd on the display DPI
float hidpiRes = 96;
float dpi = (ddpi / hidpiRes);
if (dpi != 1)
{
SDL_DisplayMode mode;
SDL_GetDesktopDisplayMode(display, &mode);
SDL_SetWindowPosition(window, (int)(mode.w - config->width * dpi) / 2, (int)(mode.h - config->height * dpi) / 2);
SDL_SetWindowSize(window, (int)(config->width * dpi), (int)(config->height * dpi));
}
}
}
#endif
// set window properties
SDL_SetWindowResizable(window, SDL_TRUE);
SDL_SetWindowMinimumSize(window, 256, 256);
return true;
}
void PlatformBackend::ready()
{
// enable V-Sync
if (App::renderer() == Renderer::OpenGL)
SDL_GL_SetSwapInterval(1);
}
void PlatformBackend::shutdown()
{
if (window != nullptr)
SDL_DestroyWindow(window);
window = nullptr;
displayed = false;
if (basePath != nullptr)
SDL_free(basePath);
if (userPath != nullptr)
SDL_free(userPath);
SDL_Quit();
}
uint64_t PlatformBackend::time()
{
return (uint64_t)SDL_GetTicks();
}
void PlatformBackend::frame()
{
// update the mouse every frame
{
int winX, winY, x, y;
SDL_GetWindowPosition(window, &winX, &winY);
SDL_GetGlobalMouseState(&x, &y);
InputBackend::on_mouse_move((float)(x - winX), (float)(y - winY));
InputBackend::on_mouse_screen_move((float)x, (float)y);
}
// poll normal events
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
auto config = App::config();
if (config->on_exit_request != nullptr)
config->on_exit_request();
}
// Mouse
else if (event.type == SDL_MOUSEBUTTONDOWN)
{
MouseButton btn = MouseButton::None;
if (event.button.button == SDL_BUTTON_LEFT)
btn = MouseButton::Left;
else if (event.button.button == SDL_BUTTON_RIGHT)
btn = MouseButton::Right;
else if (event.button.button == SDL_BUTTON_MIDDLE)
btn = MouseButton::Middle;
InputBackend::on_mouse_down(btn);
}
else if (event.type == SDL_MOUSEBUTTONUP)
{
MouseButton btn = MouseButton::None;
if (event.button.button == SDL_BUTTON_LEFT)
btn = MouseButton::Left;
else if (event.button.button == SDL_BUTTON_RIGHT)
btn = MouseButton::Right;
else if (event.button.button == SDL_BUTTON_MIDDLE)
btn = MouseButton::Middle;
InputBackend::on_mouse_up(btn);
}
else if (event.type == SDL_MOUSEWHEEL)
{
InputBackend::on_mouse_wheel(Point(event.wheel.x, event.wheel.y));
}
// Keyboard
else if (event.type == SDL_KEYDOWN)
{
if (event.key.repeat == 0)
InputBackend::on_key_down((Key)event.key.keysym.scancode);
}
else if (event.type == SDL_KEYUP)
{
if (event.key.repeat == 0)
InputBackend::on_key_up((Key)event.key.keysym.scancode);
}
else if (event.type == SDL_TEXTINPUT)
{
InputBackend::on_text_utf8(event.text.text);
}
// Joystick Controller
else if (event.type == SDL_JOYDEVICEADDED)
{
Sint32 index = event.jdevice.which;
if (SDL_IsGameController(index) == SDL_FALSE)
{
SDL_Joystick* ptr = joysticks[index] = SDL_JoystickOpen(index);
const char* name = SDL_JoystickName(ptr);
int button_count = SDL_JoystickNumButtons(ptr);
int axis_count = SDL_JoystickNumAxes(ptr);
uint16_t vendor = SDL_JoystickGetVendor(ptr);
uint16_t product = SDL_JoystickGetProduct(ptr);
uint16_t version = SDL_JoystickGetProductVersion(ptr);
InputBackend::on_controller_connect(index, name, 0, button_count, axis_count, vendor, product, version);
}
}
else if (event.type == SDL_JOYDEVICEREMOVED)
{
Sint32 index = event.jdevice.which;
if (SDL_IsGameController(index) == SDL_FALSE)
{
InputBackend::on_controller_disconnect(index);
SDL_JoystickClose(joysticks[index]);
}
}
else if (event.type == SDL_JOYBUTTONDOWN)
{
Sint32 index = event.jdevice.which;
if (SDL_IsGameController(index) == SDL_FALSE)
InputBackend::on_button_down(index, event.jbutton.button);
}
else if (event.type == SDL_JOYBUTTONUP)
{
Sint32 index = event.jdevice.which;
if (SDL_IsGameController(index) == SDL_FALSE)
InputBackend::on_button_up(index, event.jbutton.button);
}
else if (event.type == SDL_JOYAXISMOTION)
{
Sint32 index = event.jaxis.which;
if (SDL_IsGameController(index) == SDL_FALSE)
{
float value;
if (event.jaxis.value >= 0)
value = event.jaxis.value / 32767.0f;
else
value = event.jaxis.value / 32768.0f;
InputBackend::on_axis_move(index, event.jaxis.axis, value);
}
}
// Gamepad Controller
else if (event.type == SDL_CONTROLLERDEVICEADDED)
{
Sint32 index = event.cdevice.which;
SDL_GameController* ptr = gamepads[index] = SDL_GameControllerOpen(index);
const char* name = SDL_GameControllerName(ptr);
uint16_t vendor = SDL_GameControllerGetVendor(ptr);
uint16_t product = SDL_GameControllerGetProduct(ptr);
uint16_t version = SDL_GameControllerGetProductVersion(ptr);
InputBackend::on_controller_connect(index, name, 1, 15, 6, vendor, product, version);
}
else if (event.type == SDL_CONTROLLERDEVICEREMOVED)
{
Sint32 index = event.cdevice.which;
InputBackend::on_controller_disconnect(index);
SDL_GameControllerClose(gamepads[index]);
}
else if (event.type == SDL_CONTROLLERBUTTONDOWN)
{
Sint32 index = event.cbutton.which;
int button = (int)Button::None;
if (event.cbutton.button >= 0 && event.cbutton.button < 15)
button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum!
InputBackend::on_button_down(index, button);
}
else if (event.type == SDL_CONTROLLERBUTTONUP)
{
Sint32 index = event.cbutton.which;
int button = (int)Button::None;
if (event.cbutton.button >= 0 && event.cbutton.button < 15)
button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum!
InputBackend::on_button_up(index, button);
}
else if (event.type == SDL_CONTROLLERAXISMOTION)
{
Sint32 index = event.caxis.which;
int axis = (int)Axis::None;
if (event.caxis.axis >= 0 && event.caxis.axis < 6)
axis = event.caxis.axis; // NOTE: These map directly to Engine Axis enum!
float value;
if (event.caxis.value >= 0)
value = event.caxis.value / 32767.0f;
else
value = event.caxis.value / 32768.0f;
InputBackend::on_axis_move(index, axis, value);
}
}
}
void PlatformBackend::sleep(int milliseconds)
{
if (milliseconds >= 0)
SDL_Delay((uint32_t)milliseconds);
}
void PlatformBackend::present()
{
if (App::renderer() == Renderer::OpenGL)
{
SDL_GL_SwapWindow(window);
}
// display the window
// this avoids a short black screen on macoS
if (!displayed)
{
SDL_ShowWindow(window);
displayed = true;
}
}
const char* PlatformBackend::get_title()
{
return nullptr;
}
void PlatformBackend::set_title(const char* title)
{
SDL_SetWindowTitle(window, title);
}
void PlatformBackend::get_position(int* x, int* y)
{
SDL_GetWindowPosition(window, x, y);
}
void PlatformBackend::set_position(int x, int y)
{
SDL_SetWindowPosition(window, x, y);
}
void PlatformBackend::set_fullscreen(bool enabled)
{
if (enabled)
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
else
SDL_SetWindowFullscreen(window, 0);
}
void PlatformBackend::get_size(int* width, int* height)
{
SDL_GetWindowSize(window, width, height);
}
void PlatformBackend::set_size(int width, int height)
{
SDL_SetWindowSize(window, width, height);
}
void PlatformBackend::get_draw_size(int* width, int* height)
{
if (App::renderer() == Renderer::OpenGL)
{
SDL_GL_GetDrawableSize(window, width, height);
}
else
{
SDL_GetWindowSize(window, width, height);
}
}
float PlatformBackend::get_content_scale()
{
// TODO:
// This is incorrect! but for some reason the scale
// is HUGE if I use the Display DPI on macOS :/
#if __APPLE__
return 2.0f;
#endif
#if _WIN32
float hidpiRes = 96;
#else
float hidpiRes = 72;
#endif
int index = SDL_GetWindowDisplayIndex(window);
if (index < 0)
Log::error(SDL_GetError());
float ddpi, x, y;
if (SDL_GetDisplayDPI(index, &ddpi, &x, &y) != 0)
Log::error(SDL_GetError());
return (ddpi / hidpiRes);
}
// FILE IO
const char* PlatformBackend::app_path()
{
if (basePath == nullptr)
basePath = SDL_GetBasePath();
return basePath;
}
const char* PlatformBackend::user_path()
{
if (userPath == nullptr)
{
const Config* config = App::config();
userPath = SDL_GetPrefPath(nullptr, config->name);
}
return userPath;
}
// Windows File System methods
#if _WIN32
bool PlatformBackend::file_exists(const char* path)
{
return fs::is_regular_file(path);
}
bool PlatformBackend::file_delete(const char* path)
{
return fs::remove(path);
}
bool PlatformBackend::dir_create(const char* path)
{
std::error_code error;
return fs::create_directories(path, error);
}
bool PlatformBackend::dir_exists(const char* path)
{
return fs::is_directory(path);
}
bool PlatformBackend::dir_delete(const char* path)
{
BLAH_ERROR("not implemented");
return false;
}
void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
{
if (fs::is_directory(path))
{
if (recursive)
{
for (auto& p : fs::recursive_directory_iterator(path))
list.emplace_back(p.path().string().c_str());
}
else
{
for (auto& p : fs::directory_iterator(path))
list.emplace_back(p.path().string().c_str());
}
}
}
void PlatformBackend::dir_explore(const char* path)
{
ShellExecute(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT);
}
// Non-Windows File System Methods
#else
bool PlatformBackend::file_exists(const char* path)
{
struct stat buffer;
return (stat(path, &buffer) == 0) && S_ISREG(buffer.st_mode);
}
bool PlatformBackend::file_delete(const char* path)
{
BLAH_ERROR("not implemented");
return false;
}
bool PlatformBackend::dir_create(const char* path)
{
char tmp[265];
char* p = NULL;
size_t len;
snprintf(tmp, sizeof(tmp), "%s", path);
len = strlen(tmp);
if (tmp[len - 1] == '/')
tmp[len - 1] = 0;
for (p = tmp + 1; *p; p++)
if (*p == '/') {
*p = 0;
mkdir(tmp, S_IRWXU);
*p = '/';
}
return mkdir(tmp, S_IRWXU) == 0;
}
bool PlatformBackend::dir_exists(const char* path)
{
struct stat buffer;
return (stat(path, &buffer) == 0) && S_ISDIR(buffer.st_mode);
}
bool PlatformBackend::dir_delete(const char* path)
{
BLAH_ERROR("not implemented");
return false;
}
void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
{
DIR* dirp = opendir(path);
if (dirp != NULL)
{
struct dirent* dp;
while ((dp = readdir(dirp)) != NULL)
{
if (dp->d_name[0] == '.')
continue;
FilePath subpath = FilePath(path).append(dp->d_name);
list.push_back(subpath);
if (recursive && dp->d_type == DT_DIR)
dir_enumerate(list, subpath + "/", true);
}
closedir(dirp);
}
}
void PlatformBackend::dir_explore(const char* path)
{
BLAH_ERROR("'dir_explore' Not Implemented");
}
#endif
bool PlatformBackend::file_open(const char* path, PlatformBackend::FileHandle* handle, FileMode mode)
{
const char* sdlMode = "rb";
if (mode == FileMode::Write)
sdlMode = "wb";
auto ptr = SDL_RWFromFile(path, sdlMode);
*handle = (PlatformBackend::FileHandle)ptr;
return ptr != nullptr;
}
int64_t PlatformBackend::file_length(PlatformBackend::FileHandle stream)
{
return SDL_RWsize((SDL_RWops*)stream);
}
int64_t PlatformBackend::file_position(PlatformBackend::FileHandle stream)
{
return SDL_RWtell((SDL_RWops*)stream);
}
int64_t PlatformBackend::file_seek(PlatformBackend::FileHandle stream, int64_t seekTo)
{
return SDL_RWseek((SDL_RWops*)stream, seekTo, RW_SEEK_SET);
}
int64_t PlatformBackend::file_read(PlatformBackend::FileHandle stream, void* ptr, int64_t length)
{
return SDL_RWread((SDL_RWops*)stream, ptr, sizeof(char), length);
}
int64_t PlatformBackend::file_write(PlatformBackend::FileHandle stream, const void* ptr, int64_t length)
{
return SDL_RWwrite((SDL_RWops*)stream, ptr, sizeof(char), length);
}
void PlatformBackend::file_close(PlatformBackend::FileHandle stream)
{
if (stream != nullptr)
SDL_RWclose((SDL_RWops*)stream);
}
void* PlatformBackend::gl_get_func(const char* name)
{
return SDL_GL_GetProcAddress(name);
}
void* PlatformBackend::gl_context_create()
{
void* pointer = SDL_GL_CreateContext(window);
if (pointer == nullptr)
Log::error("SDL_GL_CreateContext failed: %s", SDL_GetError());
return pointer;
}
void PlatformBackend::gl_context_make_current(void* context)
{
SDL_GL_MakeCurrent(window, context);
}
void PlatformBackend::gl_context_destroy(void* context)
{
SDL_GL_DeleteContext(context);
}
void* PlatformBackend::d3d11_get_hwnd()
{
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
SDL_GetWindowWMInfo(window, &info);
return info.info.win.window;
}
#endif // BLAH_USE_SDL2