mirror of
https://github.com/NoelFB/blah.git
synced 2025-07-15 18:51:53 +08:00
Refactored Graphics to allow Renderer choice at runtime
This commit is contained in:
@ -1,60 +0,0 @@
|
||||
#pragma once
|
||||
#include <blah/app.h>
|
||||
#include <blah/graphics/renderpass.h>
|
||||
#include <blah/graphics/texture.h>
|
||||
#include <blah/graphics/target.h>
|
||||
#include <blah/graphics/shader.h>
|
||||
#include <blah/graphics/mesh.h>
|
||||
#include <blah/graphics/material.h>
|
||||
#include <blah/numerics/color.h>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
// Graphics backend API used for rendering.
|
||||
// All rendering ends up going through here.
|
||||
namespace Graphics
|
||||
{
|
||||
// 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 update();
|
||||
|
||||
// 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, float depth, u8 stencil, ClearMask mask);
|
||||
|
||||
// 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 Target.
|
||||
// if the Target is invalid, this should return an empty reference.
|
||||
TargetRef create_target(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();
|
||||
}
|
||||
}
|
@ -1,215 +0,0 @@
|
||||
#if !(defined(BLAH_GRAPHICS_OPENGL) || defined(BLAH_GRAPHICS_D3D11))
|
||||
|
||||
#include "graphics.h"
|
||||
#include "platform.h"
|
||||
#include <blah/common.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_Target : public Target
|
||||
{
|
||||
private:
|
||||
Attachments m_attachments;
|
||||
|
||||
public:
|
||||
|
||||
Dummy_Target(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& textures() override
|
||||
{
|
||||
return m_attachments;
|
||||
}
|
||||
|
||||
virtual const Attachments& textures() const override
|
||||
{
|
||||
return m_attachments;
|
||||
}
|
||||
|
||||
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:
|
||||
i64 m_index_count = 0;
|
||||
i64 m_vertex_count = 0;
|
||||
i64 m_instance_count = 0;
|
||||
public:
|
||||
|
||||
Dummy_Mesh()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual void index_data(IndexFormat format, const void* indices, i64 count) override
|
||||
{
|
||||
m_index_count = count;
|
||||
}
|
||||
|
||||
virtual void vertex_data(const VertexFormat& format, const void* vertices, i64 count) override
|
||||
{
|
||||
m_vertex_count = count;
|
||||
}
|
||||
|
||||
virtual void instance_data(const VertexFormat& format, const void* instances, i64 count) override
|
||||
{
|
||||
m_instance_count = count;
|
||||
}
|
||||
|
||||
virtual i64 index_count() const override
|
||||
{
|
||||
return m_index_count;
|
||||
}
|
||||
|
||||
virtual i64 vertex_count() const override
|
||||
{
|
||||
return m_vertex_count;
|
||||
}
|
||||
|
||||
virtual i64 instance_count() const override
|
||||
{
|
||||
return m_instance_count;
|
||||
}
|
||||
};
|
||||
|
||||
bool Graphics::init()
|
||||
{
|
||||
Log::info("Dummy Renderer");
|
||||
return true;
|
||||
}
|
||||
|
||||
Renderer Graphics::renderer()
|
||||
{
|
||||
return Renderer::None;
|
||||
}
|
||||
|
||||
void Graphics::shutdown()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const RendererFeatures& Graphics::features()
|
||||
{
|
||||
static const RendererFeatures features{ false, true, 4096 };
|
||||
return features;
|
||||
}
|
||||
|
||||
void Graphics::update() {}
|
||||
void Graphics::before_render() {}
|
||||
void Graphics::after_render() {}
|
||||
|
||||
TextureRef Graphics::create_texture(int width, int height, TextureFormat format)
|
||||
{
|
||||
return TextureRef(new Dummy_Texture(width, height, format, false));
|
||||
}
|
||||
|
||||
TargetRef Graphics::create_target(int width, int height, const TextureFormat* attachments, int attachmentCount)
|
||||
{
|
||||
return TargetRef(new Dummy_Target(width, height, attachments, attachmentCount));
|
||||
}
|
||||
|
||||
ShaderRef Graphics::create_shader(const ShaderData* data)
|
||||
{
|
||||
return ShaderRef(new Dummy_Shader(data));
|
||||
}
|
||||
|
||||
MeshRef Graphics::create_mesh()
|
||||
{
|
||||
return MeshRef(new Dummy_Mesh());
|
||||
}
|
||||
|
||||
void Graphics::render(const RenderPass& pass)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Graphics::clear_backbuffer(Color color)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !(defined(BLAH_GRAPHICS_OPENGL) || defined(BLAH_GRAPHICS_D3D11))
|
@ -42,7 +42,7 @@ namespace Blah
|
||||
|
||||
// Sets the Application Window Position, in Screen Coordinates
|
||||
void set_position(int x, int y);
|
||||
|
||||
|
||||
// Gets whether the Window has focus
|
||||
bool get_focused();
|
||||
|
||||
@ -97,6 +97,9 @@ namespace Blah
|
||||
// gets the contents of the clipboard into the given string
|
||||
const char* get_clipboard();
|
||||
|
||||
// Tries to open a URL in a web browser
|
||||
void open_url(const char* url);
|
||||
|
||||
// OpenGL Methods
|
||||
void* gl_get_func(const char* name);
|
||||
void* gl_context_create();
|
||||
@ -105,8 +108,5 @@ namespace Blah
|
||||
|
||||
// D3D11 Methods
|
||||
void* d3d11_get_hwnd();
|
||||
|
||||
// Tries to open a URL in a web browser
|
||||
void open_url(const char* url);
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "platform.h"
|
||||
#include "input.h"
|
||||
#include "graphics.h"
|
||||
#include "renderer.h"
|
||||
#include <blah/input.h>
|
||||
#include <blah/app.h>
|
||||
#include <blah/filesystem.h>
|
||||
@ -37,7 +37,7 @@ namespace Blah
|
||||
char* base_path = nullptr;
|
||||
char* user_path = nullptr;
|
||||
bool displayed = false;
|
||||
};
|
||||
} g_platform;
|
||||
|
||||
// Blah SDL2 File
|
||||
class SDL2File : public File
|
||||
@ -118,8 +118,6 @@ namespace Blah
|
||||
|
||||
using namespace Blah;
|
||||
|
||||
static Blah::SDL2Platform g_platform;
|
||||
|
||||
bool Platform::init(const Config& config)
|
||||
{
|
||||
g_platform = SDL2Platform();
|
||||
@ -150,7 +148,7 @@ bool Platform::init(const Config& config)
|
||||
int flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE;
|
||||
|
||||
// enable OpenGL
|
||||
if (App::renderer() == Renderer::OpenGL)
|
||||
if (config.renderer_type == RendererType::OpenGL)
|
||||
{
|
||||
flags |= SDL_WINDOW_OPENGL;
|
||||
|
||||
@ -217,7 +215,7 @@ void Platform::ready()
|
||||
// enable V-Sync
|
||||
// TODO:
|
||||
// This should be a toggle or controllable in some way
|
||||
if (App::renderer() == Renderer::OpenGL)
|
||||
if (App::renderer().type == RendererType::OpenGL)
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
#endif
|
||||
}
|
||||
@ -454,7 +452,7 @@ void Platform::sleep(int milliseconds)
|
||||
|
||||
void Platform::present()
|
||||
{
|
||||
if (App::renderer() == Renderer::OpenGL)
|
||||
if (App::renderer().type == RendererType::OpenGL)
|
||||
{
|
||||
SDL_GL_SwapWindow(g_platform.window);
|
||||
}
|
||||
@ -514,7 +512,7 @@ void Platform::set_size(int width, int height)
|
||||
|
||||
void Platform::get_draw_size(int* width, int* height)
|
||||
{
|
||||
if (App::renderer() == Renderer::OpenGL)
|
||||
if (App::renderer().type == RendererType::OpenGL)
|
||||
{
|
||||
SDL_GL_GetDrawableSize(g_platform.window, width, height);
|
||||
}
|
||||
|
@ -1,14 +1,11 @@
|
||||
#ifdef BLAH_PLATFORM_WIN32
|
||||
|
||||
// Note:
|
||||
// This backend implementation is unfinished!
|
||||
// It's missing a few things, namely:
|
||||
// - Controller Support
|
||||
// (And error testing)
|
||||
// This is unfinished! It is missing Controller Support!
|
||||
|
||||
#include "platform.h"
|
||||
#include "input.h"
|
||||
#include "graphics.h"
|
||||
#include "renderer.h"
|
||||
#include <blah/input.h>
|
||||
#include <blah/app.h>
|
||||
#include <blah/filesystem.h>
|
||||
@ -22,11 +19,20 @@
|
||||
#include <shellapi.h> // for file explore
|
||||
#include <shlobj.h> // for known folder
|
||||
#include <chrono> // for ticks method
|
||||
#include <Xinput.h> // for XInput
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
using Duration = std::chrono::system_clock::duration;
|
||||
|
||||
typedef HRESULT(WINAPI* DirectInput8Create_fn)(HINSTANCE, DWORD, REFIID, LPVOID*, LPUNKNOWN);
|
||||
typedef DWORD(WINAPI* XInputGetCapabilities_fn)(DWORD, DWORD, XINPUT_CAPABILITIES*);
|
||||
typedef DWORD(WINAPI* XInputGetState_fn)(DWORD, XINPUT_STATE*);
|
||||
typedef void*(WINAPI* wglGetProcAddress_fn)(const char*);
|
||||
typedef HGLRC(WINAPI* wglCreateContext_fn)(HDC);
|
||||
typedef BOOL(WINAPI* wglDeleteContext_fn)(HGLRC);
|
||||
typedef BOOL(WINAPI* wglMakeCurrent_fn)(HDC, HGLRC);
|
||||
|
||||
// Win32 Platform State
|
||||
struct Win32Platform
|
||||
{
|
||||
@ -38,14 +44,34 @@ namespace Blah
|
||||
RECT windowed_position;
|
||||
bool fullscreen = false;
|
||||
InputState* input_state = nullptr;
|
||||
String clipboard;
|
||||
|
||||
// XInput
|
||||
struct
|
||||
{
|
||||
HMODULE dll;
|
||||
XInputGetCapabilities_fn get_capabilities;
|
||||
XInputGetState_fn get_state;
|
||||
} xinput;
|
||||
|
||||
struct Joystick
|
||||
{
|
||||
bool connected = false;
|
||||
bool accounted = false;
|
||||
GUID dinstance = GUID_NULL;
|
||||
DWORD xindex = 0;
|
||||
} joysticks[Input::max_controllers];
|
||||
|
||||
// OpenGL Methods
|
||||
// These are only loaded if built using the OpenGL Backend
|
||||
HMODULE opengl_dll;
|
||||
void* (WINAPI* wglGetProcAddress) (const char* proc);
|
||||
HGLRC (WINAPI* wglCreateContext) (HDC hdc);
|
||||
BOOL (WINAPI* wglDeleteContext) (HGLRC hglrc);
|
||||
BOOL (WINAPI* wglMakeCurrent) (HDC hdc, HGLRC hglrc);
|
||||
struct
|
||||
{
|
||||
HMODULE dll;
|
||||
wglGetProcAddress_fn get_proc_address;
|
||||
wglCreateContext_fn create_context;
|
||||
wglDeleteContext_fn delete_context;
|
||||
wglMakeCurrent_fn make_current;
|
||||
} gl;
|
||||
};
|
||||
|
||||
// Win32 File Class
|
||||
@ -53,11 +79,16 @@ namespace Blah
|
||||
{
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
LARGE_INTEGER m_size;
|
||||
|
||||
public:
|
||||
Win32File(HANDLE handle)
|
||||
{
|
||||
m_handle = handle;
|
||||
|
||||
LARGE_INTEGER file_size;
|
||||
if (GetFileSizeEx(m_handle, &file_size))
|
||||
m_size = file_size;
|
||||
}
|
||||
|
||||
~Win32File()
|
||||
@ -67,13 +98,7 @@ namespace Blah
|
||||
|
||||
size_t length() override
|
||||
{
|
||||
// Todo: cache this value? not sure how performant it is
|
||||
|
||||
LARGE_INTEGER file_size;
|
||||
if (GetFileSizeEx(m_handle, &file_size))
|
||||
return file_size.QuadPart;
|
||||
|
||||
return 0;
|
||||
return m_size.QuadPart;
|
||||
}
|
||||
|
||||
size_t position() override
|
||||
@ -149,11 +174,14 @@ namespace Blah
|
||||
}
|
||||
};
|
||||
|
||||
// Main Windows Procedure callback
|
||||
LRESULT CALLBACK win32_window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
// Converts Windows scancode to Blah key
|
||||
Key win32_scancode_to_key(WPARAM wParam, LPARAM lParam);
|
||||
|
||||
// Main Windows Procedure callback
|
||||
LRESULT CALLBACK win32_window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
// Detects joysticks (connects & disconnects)
|
||||
void win32_detect_joysticks();
|
||||
}
|
||||
|
||||
using namespace Blah;
|
||||
@ -198,22 +226,30 @@ bool Platform::init(const Config& config)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup Window Size based on content scale
|
||||
{
|
||||
auto scale = get_content_scale();
|
||||
int sw = (int)(App::config().width * scale);
|
||||
int sh = (int)(App::config().height * scale);
|
||||
set_size(sw, sh);
|
||||
}
|
||||
|
||||
// Create the OpenGL device info
|
||||
if (App::renderer() == Renderer::OpenGL)
|
||||
if (config.renderer_type == RendererType::OpenGL)
|
||||
{
|
||||
// Load the DLL
|
||||
g_platform.opengl_dll = LoadLibraryA("opengl32.dll");
|
||||
if (g_platform.opengl_dll == NULL)
|
||||
g_platform.gl.dll = LoadLibraryA("opengl32.dll");
|
||||
if (g_platform.gl.dll == NULL)
|
||||
{
|
||||
Log::error("OpenGL Instantiation Failed - unable to fine opengl32.dll");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the Windows GL functions we need
|
||||
g_platform.wglGetProcAddress = (void* (WINAPI*)(const char*))GetProcAddress(g_platform.opengl_dll, "wglGetProcAddress");
|
||||
g_platform.wglCreateContext = (HGLRC(WINAPI*) (HDC))GetProcAddress(g_platform.opengl_dll, "wglCreateContext");
|
||||
g_platform.wglDeleteContext = (BOOL(WINAPI*) (HGLRC))GetProcAddress(g_platform.opengl_dll, "wglDeleteContext");
|
||||
g_platform.wglMakeCurrent = (BOOL(WINAPI*) (HDC, HGLRC))GetProcAddress(g_platform.opengl_dll, "wglMakeCurrent");
|
||||
g_platform.gl.get_proc_address = (wglGetProcAddress_fn)GetProcAddress(g_platform.gl.dll, "wglGetProcAddress");
|
||||
g_platform.gl.create_context = (wglCreateContext_fn)GetProcAddress(g_platform.gl.dll, "wglCreateContext");
|
||||
g_platform.gl.delete_context = (wglDeleteContext_fn)GetProcAddress(g_platform.gl.dll, "wglDeleteContext");
|
||||
g_platform.gl.make_current = (wglMakeCurrent_fn)GetProcAddress(g_platform.gl.dll, "wglMakeCurrent");
|
||||
|
||||
// TODO:
|
||||
// Allow the user to apply (some of) these values before instantiation.
|
||||
@ -250,8 +286,25 @@ bool Platform::init(const Config& config)
|
||||
SetPixelFormat(hdc, pixel_format, &pfd);
|
||||
}
|
||||
|
||||
// Reset our game timer
|
||||
g_platform.start_time = std::chrono::system_clock::now().time_since_epoch();
|
||||
// xinput api
|
||||
{
|
||||
const char* dlls[] = { "xinput1_4.dll", "xinput1_3.dll", "xinput9_1_0.dll", "xinput1_2.dll", "xinput1_1.dll", NULL };
|
||||
|
||||
for (int i = 0; dlls[i]; i++)
|
||||
{
|
||||
g_platform.xinput.dll = LoadLibraryA(dlls[i]);
|
||||
|
||||
if (g_platform.xinput.dll)
|
||||
{
|
||||
g_platform.xinput.get_capabilities = (XInputGetCapabilities_fn)GetProcAddress(g_platform.xinput.dll, "XInputGetCapabilities");
|
||||
g_platform.xinput.get_state = (XInputGetState_fn)GetProcAddress(g_platform.xinput.dll, "XInputGetState");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_platform.xinput.dll)
|
||||
Log::warn("Failed to find XInput dll; No Controller Support");
|
||||
}
|
||||
|
||||
// Get Working Directory
|
||||
{
|
||||
@ -283,6 +336,9 @@ bool Platform::init(const Config& config)
|
||||
CoTaskMemFree(path);
|
||||
}
|
||||
|
||||
// Reset our game timer
|
||||
g_platform.start_time = std::chrono::system_clock::now().time_since_epoch();
|
||||
|
||||
// Not currently fullscreen
|
||||
g_platform.fullscreen = false;
|
||||
|
||||
@ -292,20 +348,18 @@ bool Platform::init(const Config& config)
|
||||
|
||||
void Platform::ready()
|
||||
{
|
||||
// Setup Window Size
|
||||
{
|
||||
auto scale = get_content_scale();
|
||||
int sw = (int)(App::config().width * scale);
|
||||
int sh = (int)(App::config().height * scale);
|
||||
set_size(sw, sh);
|
||||
}
|
||||
|
||||
// Display the game window
|
||||
ShowWindow(g_platform.hwnd, SW_SHOW);
|
||||
}
|
||||
|
||||
void Platform::shutdown()
|
||||
{
|
||||
if (g_platform.xinput.dll)
|
||||
FreeLibrary(g_platform.xinput.dll);
|
||||
|
||||
if (g_platform.gl.dll)
|
||||
FreeLibrary(g_platform.gl.dll);
|
||||
|
||||
DestroyWindow(g_platform.hwnd);
|
||||
}
|
||||
|
||||
@ -334,6 +388,17 @@ LRESULT CALLBACK Blah::win32_window_procedure(HWND hwnd, UINT msg, WPARAM wParam
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
|
||||
|
||||
// Controller connected event
|
||||
case WM_DEVICECHANGE:
|
||||
{
|
||||
// DBT_DEVNODES_CHANGED = 0x0007
|
||||
// https://docs.microsoft.com/en-us/windows/win32/devio/wm-devicechange
|
||||
if (wParam == 0x0007)
|
||||
win32_detect_joysticks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Mouse Input
|
||||
case WM_LBUTTONDOWN:
|
||||
g_platform.input_state->mouse.on_press(MouseButton::Left);
|
||||
@ -410,8 +475,13 @@ LRESULT CALLBACK Blah::win32_window_procedure(HWND hwnd, UINT msg, WPARAM wParam
|
||||
void Platform::update(InputState& state)
|
||||
{
|
||||
// store reference to input state
|
||||
bool first_update = g_platform.input_state == nullptr;
|
||||
g_platform.input_state = &state;
|
||||
|
||||
// if this is the first update, poll joysticks that are already connected
|
||||
if (first_update)
|
||||
win32_detect_joysticks();
|
||||
|
||||
// Catch & Dispatch Window Messages
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
@ -429,7 +499,7 @@ void Platform::sleep(int milliseconds)
|
||||
|
||||
void Platform::present()
|
||||
{
|
||||
if (App::renderer() == Renderer::OpenGL)
|
||||
if (App::renderer().type == RendererType::OpenGL)
|
||||
{
|
||||
HDC hdc = GetDC(g_platform.hwnd);
|
||||
SwapBuffers(hdc);
|
||||
@ -463,6 +533,12 @@ void Platform::set_position(int x, int y)
|
||||
SetWindowPos(g_platform.hwnd, NULL, x, y, w, h, 0);
|
||||
}
|
||||
|
||||
bool Platform::get_focused()
|
||||
{
|
||||
Log::warn("App::focused not implemented for Win32 yet");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Platform::set_fullscreen(bool enabled)
|
||||
{
|
||||
if (g_platform.fullscreen == enabled)
|
||||
@ -628,30 +704,19 @@ FileRef Platform::file_open(const char* path, FileMode mode)
|
||||
return FileRef(new Win32File(result));
|
||||
}
|
||||
|
||||
// clipboard
|
||||
void Platform::set_clipboard(const char* text)
|
||||
{
|
||||
BLAH_ASSERT(false, "Not Implemented Yet");
|
||||
}
|
||||
|
||||
const char* Platform::get_clipboard()
|
||||
{
|
||||
BLAH_ASSERT(false, "Not Implemented Yet");
|
||||
}
|
||||
|
||||
void* Platform::gl_get_func(const char* name)
|
||||
{
|
||||
// this check is taken from https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions
|
||||
// wglGetProcAddress doesn't always return valid pointers for some specific methods?
|
||||
|
||||
void* p = (void*)g_platform.wglGetProcAddress(name);
|
||||
void* p = (void*)g_platform.gl.get_proc_address(name);
|
||||
if ((p == 0) ||
|
||||
(p == (void*)0x1) ||
|
||||
(p == (void*)0x2) ||
|
||||
(p == (void*)0x3) ||
|
||||
(p == (void*)-1))
|
||||
{
|
||||
p = (void*)GetProcAddress(g_platform.opengl_dll, name);
|
||||
p = (void*)GetProcAddress(g_platform.gl.dll, name);
|
||||
}
|
||||
|
||||
return p;
|
||||
@ -660,7 +725,7 @@ void* Platform::gl_get_func(const char* name)
|
||||
void* Platform::gl_context_create()
|
||||
{
|
||||
HDC hdc = GetDC(g_platform.hwnd);
|
||||
return g_platform.wglCreateContext(hdc);
|
||||
return g_platform.gl.create_context(hdc);
|
||||
}
|
||||
|
||||
void Platform::gl_context_make_current(void* context)
|
||||
@ -668,15 +733,15 @@ void Platform::gl_context_make_current(void* context)
|
||||
if (context != nullptr)
|
||||
{
|
||||
HDC hdc = GetDC(g_platform.hwnd);
|
||||
g_platform.wglMakeCurrent(hdc, (HGLRC)context);
|
||||
g_platform.gl.make_current(hdc, (HGLRC)context);
|
||||
}
|
||||
else
|
||||
g_platform.wglMakeCurrent(NULL, NULL);
|
||||
g_platform.gl.make_current(NULL, NULL);
|
||||
}
|
||||
|
||||
void Platform::gl_context_destroy(void* context)
|
||||
{
|
||||
g_platform.wglDeleteContext((HGLRC)context);
|
||||
g_platform.gl.delete_context((HGLRC)context);
|
||||
}
|
||||
|
||||
void* Platform::d3d11_get_hwnd()
|
||||
@ -864,4 +929,116 @@ Key Blah::win32_scancode_to_key(WPARAM wParam, LPARAM lParam)
|
||||
return Key::Unknown;
|
||||
}
|
||||
|
||||
void Blah::win32_detect_joysticks()
|
||||
{
|
||||
// mark all joysticks as unnacounted for
|
||||
for (int i = 0; i < Input::max_controllers; i++)
|
||||
g_platform.joysticks[i].accounted = false;
|
||||
|
||||
// check for xinput controllers
|
||||
if (g_platform.xinput.dll)
|
||||
{
|
||||
for (DWORD index = 0; index < XUSER_MAX_COUNT; index++)
|
||||
{
|
||||
// can't get capabilities; not connected
|
||||
XINPUT_CAPABILITIES xic;
|
||||
if (g_platform.xinput.get_capabilities(index, 0, &xic) != ERROR_SUCCESS)
|
||||
continue;
|
||||
|
||||
// already connected
|
||||
bool already_connected = false;
|
||||
for (int i = 0; i < Input::max_controllers; i++)
|
||||
{
|
||||
auto& it = g_platform.joysticks[i];
|
||||
if (it.connected && it.dinstance == GUID_NULL && it.xindex == index)
|
||||
{
|
||||
it.accounted = true;
|
||||
already_connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (already_connected)
|
||||
continue;
|
||||
|
||||
// find an empty slot and mark connected
|
||||
for (int i = 0; i < Input::max_controllers; i++)
|
||||
{
|
||||
auto& it = g_platform.joysticks[i];
|
||||
if (!it.connected)
|
||||
{
|
||||
it.connected = it.accounted = true;
|
||||
it.dinstance = GUID_NULL;
|
||||
it.xindex = index;
|
||||
|
||||
Log::info("Connected XInput [%i]", i);
|
||||
|
||||
// TODO:
|
||||
// Get Product Info & Proper Name
|
||||
g_platform.input_state->controllers[i].on_connect("Xbox Controller", true, 15, 6, 0, 0, 0);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// call disconnect on joysticks that aren't accounted for
|
||||
for (int i = 0; i < Input::max_controllers; i++)
|
||||
{
|
||||
auto& it = g_platform.joysticks[i];
|
||||
if (it.connected && !it.accounted)
|
||||
{
|
||||
Log::info("Disconnected [%i]", i);
|
||||
g_platform.input_state->controllers[i].on_disconnect();
|
||||
it = Win32Platform::Joystick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Platform::set_clipboard(const char* text)
|
||||
{
|
||||
auto len = strlen(text);
|
||||
if (auto glob = GlobalAlloc(GMEM_MOVEABLE, len))
|
||||
{
|
||||
if (auto data = GlobalLock(glob))
|
||||
{
|
||||
memcpy(data, text, len);
|
||||
GlobalUnlock(glob);
|
||||
|
||||
if (OpenClipboard(nullptr))
|
||||
{
|
||||
SetClipboardData(CF_TEXT, data);
|
||||
CloseClipboard();
|
||||
}
|
||||
}
|
||||
|
||||
GlobalFree(glob);
|
||||
}
|
||||
}
|
||||
|
||||
const char* Platform::get_clipboard()
|
||||
{
|
||||
if (OpenClipboard(nullptr))
|
||||
{
|
||||
HANDLE data = GetClipboardData(CF_TEXT);
|
||||
if (data)
|
||||
{
|
||||
auto text = static_cast<const char*>(GlobalLock(data));
|
||||
if (text)
|
||||
g_platform.clipboard = text;
|
||||
GlobalUnlock(data);
|
||||
}
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
return g_platform.clipboard.cstr();
|
||||
}
|
||||
|
||||
void Platform::open_url(const char* url)
|
||||
{
|
||||
auto cmd = String("start ") + url;
|
||||
system(cmd.cstr());
|
||||
}
|
||||
|
||||
#endif // BLAH_PLATFORM_WIN32
|
||||
|
90
src/internal/renderer.h
Normal file
90
src/internal/renderer.h
Normal file
@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
#include <blah/app.h>
|
||||
#include <blah/graphics/renderpass.h>
|
||||
#include <blah/graphics/texture.h>
|
||||
#include <blah/graphics/target.h>
|
||||
#include <blah/graphics/shader.h>
|
||||
#include <blah/graphics/mesh.h>
|
||||
#include <blah/graphics/material.h>
|
||||
#include <blah/numerics/color.h>
|
||||
|
||||
#define BLAH_ASSERT_RENDERER() BLAH_ASSERT(Renderer::instance, "Renderer has not been created")
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
class Renderer
|
||||
{
|
||||
public:
|
||||
|
||||
// Reference to the current Renderer in use
|
||||
inline static Renderer* instance = nullptr;
|
||||
|
||||
// Renderer Features
|
||||
RendererFeatures features;
|
||||
|
||||
virtual ~Renderer() = default;
|
||||
|
||||
// Initialize the Graphics
|
||||
virtual bool init() = 0;
|
||||
|
||||
// Shutdown the Graphics
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
// Called once per frame
|
||||
virtual void update() = 0;
|
||||
|
||||
// Called before rendering begins
|
||||
virtual void before_render() = 0;
|
||||
|
||||
// Called after renderings ends
|
||||
virtual void after_render() = 0;
|
||||
|
||||
// Performs a draw call
|
||||
virtual void render(const RenderPass& pass) = 0;
|
||||
|
||||
// Clears the backbuffer
|
||||
virtual void clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask) = 0;
|
||||
|
||||
// Creates a new Texture.
|
||||
// if the Texture is invalid, this should return an empty reference.
|
||||
virtual TextureRef create_texture(int width, int height, TextureFormat format) = 0;
|
||||
|
||||
// Creates a new Target.
|
||||
// if the Target is invalid, this should return an empty reference.
|
||||
virtual TargetRef create_target(int width, int height, const TextureFormat* attachments, int attachment_count) = 0;
|
||||
|
||||
// Creates a new Shader.
|
||||
// if the Shader is invalid, this should return an empty reference.
|
||||
virtual ShaderRef create_shader(const ShaderData* data) = 0;
|
||||
|
||||
// Creates a new Mesh.
|
||||
// if the Mesh is invalid, this should return an empty reference.
|
||||
virtual MeshRef create_mesh() = 0;
|
||||
|
||||
private:
|
||||
static Renderer* try_make_opengl();
|
||||
static Renderer* try_make_d3d11();
|
||||
|
||||
public:
|
||||
static Renderer* try_make_renderer(RendererType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case RendererType::None: return nullptr;
|
||||
case RendererType::OpenGL: return try_make_opengl();
|
||||
case RendererType::D3D11: return try_make_d3d11();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static RendererType default_type()
|
||||
{
|
||||
#if defined(BLAH_RENDERER_D3D11) and defined(_WIN32)
|
||||
return RendererType::D3D11;
|
||||
#else
|
||||
return RendererType::OpenGL;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
#ifdef BLAH_GRAPHICS_D3D11
|
||||
#ifdef BLAH_RENDERER_D3D11
|
||||
|
||||
// TODO:
|
||||
// Note the D3D11 Implementation is still a work-in-progress
|
||||
|
||||
#include "graphics.h"
|
||||
#include "renderer.h"
|
||||
#include "platform.h"
|
||||
#include <blah/common.h>
|
||||
#include <cstdio>
|
||||
@ -15,12 +15,16 @@
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
// shorthand to our internal state
|
||||
#define renderer ((Renderer_D3D11*)Renderer::instance)
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
class D3D11_Shader;
|
||||
|
||||
struct D3D11
|
||||
class Renderer_D3D11 : public Renderer
|
||||
{
|
||||
public:
|
||||
// main resources
|
||||
ID3D11Device* device = nullptr;
|
||||
ID3D11DeviceContext* context = nullptr;
|
||||
@ -28,9 +32,6 @@ namespace Blah
|
||||
ID3D11RenderTargetView* backbuffer_view = nullptr;
|
||||
ID3D11DepthStencilView* backbuffer_depth_view = nullptr;
|
||||
|
||||
// supported renderer features
|
||||
RendererFeatures features;
|
||||
|
||||
// last backbuffer size
|
||||
Point last_size;
|
||||
|
||||
@ -72,6 +73,18 @@ namespace Blah
|
||||
Vector<StoredSampler> sampler_cache;
|
||||
Vector<StoredDepthStencil> depthstencil_cache;
|
||||
|
||||
bool init() override;
|
||||
void shutdown() override;
|
||||
void update() override;
|
||||
void before_render() override;
|
||||
void after_render() override;
|
||||
void render(const RenderPass& pass) override;
|
||||
void clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask) override;
|
||||
TextureRef create_texture(int width, int height, TextureFormat format) override;
|
||||
TargetRef create_target(int width, int height, const TextureFormat* attachments, int attachment_count) override;
|
||||
ShaderRef create_shader(const ShaderData* data) override;
|
||||
MeshRef create_mesh() override;
|
||||
|
||||
ID3D11InputLayout* get_layout(D3D11_Shader* shader, const VertexFormat& format);
|
||||
ID3D11BlendState* get_blend(const BlendMode& blend);
|
||||
ID3D11RasterizerState* get_rasterizer(const RenderPass& pass);
|
||||
@ -79,17 +92,12 @@ namespace Blah
|
||||
ID3D11DepthStencilState* get_depthstencil(const RenderPass& pass);
|
||||
};
|
||||
|
||||
// D3D11 State
|
||||
D3D11 state;
|
||||
|
||||
// Utility Methods
|
||||
D3D11_BLEND_OP blend_op(BlendOp op);
|
||||
D3D11_BLEND blend_factor(BlendFactor factor);
|
||||
bool reflect_uniforms(Vector<UniformInfo>& append_uniforms_to, Vector<ID3D11Buffer*>& append_buffers_to, ID3DBlob* shader, ShaderType shader_type);
|
||||
void apply_uniforms(D3D11_Shader* shader, const MaterialRef& material, ShaderType type);
|
||||
|
||||
// ~ BEGIN IMPLEMENTATION ~
|
||||
|
||||
class D3D11_Texture : public Texture
|
||||
{
|
||||
private:
|
||||
@ -160,7 +168,7 @@ namespace Blah
|
||||
|
||||
m_dxgi_format = desc.Format;
|
||||
|
||||
auto hr = state.device->CreateTexture2D(&desc, NULL, &texture);
|
||||
auto hr = renderer->device->CreateTexture2D(&desc, NULL, &texture);
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
if (texture)
|
||||
@ -171,7 +179,7 @@ namespace Blah
|
||||
|
||||
if (!is_depth_stencil)
|
||||
{
|
||||
hr = state.device->CreateShaderResourceView(texture, NULL, &view);
|
||||
hr = renderer->device->CreateShaderResourceView(texture, NULL, &view);
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
texture->Release();
|
||||
@ -220,7 +228,7 @@ namespace Blah
|
||||
box.back = 1;
|
||||
|
||||
// set data
|
||||
state.context->UpdateSubresource(
|
||||
renderer->context->UpdateSubresource(
|
||||
texture,
|
||||
0,
|
||||
&box,
|
||||
@ -249,7 +257,7 @@ namespace Blah
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
hr = state.device->CreateTexture2D(&desc, NULL, &staging);
|
||||
hr = renderer->device->CreateTexture2D(&desc, NULL, &staging);
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
BLAH_ASSERT(false, "Failed to create staging texture to get data");
|
||||
@ -266,7 +274,7 @@ namespace Blah
|
||||
box.back = 1;
|
||||
|
||||
// copy data to staging texture
|
||||
state.context->CopySubresourceRegion(
|
||||
renderer->context->CopySubresourceRegion(
|
||||
staging, 0,
|
||||
0, 0, 0,
|
||||
texture, 0,
|
||||
@ -274,7 +282,7 @@ namespace Blah
|
||||
|
||||
// get data
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
hr = state.context->Map(staging, 0, D3D11_MAP_READ, 0, &map);
|
||||
hr = renderer->context->Map(staging, 0, D3D11_MAP_READ, 0, &map);
|
||||
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
@ -287,7 +295,7 @@ namespace Blah
|
||||
for (int y = 0; y < m_height; y++)
|
||||
memcpy(data + y * bytes_per_row, (unsigned char*)map.pData + map.RowPitch * y, bytes_per_row);
|
||||
|
||||
state.context->Unmap(staging, 0);
|
||||
renderer->context->Unmap(staging, 0);
|
||||
}
|
||||
|
||||
bool is_framebuffer() const override
|
||||
@ -316,12 +324,12 @@ namespace Blah
|
||||
|
||||
if (attachments[i] == TextureFormat::DepthStencil)
|
||||
{
|
||||
state.device->CreateDepthStencilView(tex->texture, nullptr, &depth_view);
|
||||
renderer->device->CreateDepthStencilView(tex->texture, nullptr, &depth_view);
|
||||
}
|
||||
else
|
||||
{
|
||||
ID3D11RenderTargetView* view = nullptr;
|
||||
state.device->CreateRenderTargetView(tex->texture, nullptr, &view);
|
||||
renderer->device->CreateRenderTargetView(tex->texture, nullptr, &view);
|
||||
color_views.push_back(view);
|
||||
}
|
||||
}
|
||||
@ -355,7 +363,7 @@ namespace Blah
|
||||
if (((int)mask & (int)ClearMask::Color) == (int)ClearMask::Color)
|
||||
{
|
||||
for (int i = 0; i < color_views.size(); i++)
|
||||
state.context->ClearRenderTargetView(color_views[i], col);
|
||||
renderer->context->ClearRenderTargetView(color_views[i], col);
|
||||
}
|
||||
|
||||
if (depth_view)
|
||||
@ -367,7 +375,7 @@ namespace Blah
|
||||
flags |= D3D11_CLEAR_STENCIL;
|
||||
|
||||
if (flags != 0)
|
||||
state.context->ClearDepthStencilView(depth_view, flags, depth, stencil);
|
||||
renderer->context->ClearDepthStencilView(depth_view, flags, depth, stencil);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -442,7 +450,7 @@ namespace Blah
|
||||
|
||||
// create vertex shader
|
||||
{
|
||||
hr = state.device->CreateVertexShader(
|
||||
hr = renderer->device->CreateVertexShader(
|
||||
vertex_blob->GetBufferPointer(),
|
||||
vertex_blob->GetBufferSize(),
|
||||
NULL,
|
||||
@ -454,7 +462,7 @@ namespace Blah
|
||||
|
||||
// create fragment shader
|
||||
{
|
||||
hr = state.device->CreatePixelShader(
|
||||
hr = renderer->device->CreatePixelShader(
|
||||
fragment_blob->GetBufferPointer(),
|
||||
fragment_blob->GetBufferSize(),
|
||||
NULL,
|
||||
@ -607,7 +615,7 @@ namespace Blah
|
||||
data.pSysMem = indices;
|
||||
|
||||
// create
|
||||
auto hr = state.device->CreateBuffer(&desc, &data, &index_buffer);
|
||||
auto hr = renderer->device->CreateBuffer(&desc, &data, &index_buffer);
|
||||
BLAH_ASSERT(SUCCEEDED(hr), "Failed to update Index Data");
|
||||
}
|
||||
}
|
||||
@ -615,13 +623,13 @@ namespace Blah
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
|
||||
auto hr = state.context->Map(index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
auto hr = renderer->context->Map(index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
BLAH_ASSERT(SUCCEEDED(hr), "Failed to update Index Data");
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
memcpy(map.pData, indices, index_stride * count);
|
||||
state.context->Unmap(index_buffer, 0);
|
||||
renderer->context->Unmap(index_buffer, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -655,7 +663,7 @@ namespace Blah
|
||||
data.pSysMem = vertices;
|
||||
|
||||
// create
|
||||
auto hr = state.device->CreateBuffer(&desc, &data, &vertex_buffer);
|
||||
auto hr = renderer->device->CreateBuffer(&desc, &data, &vertex_buffer);
|
||||
BLAH_ASSERT(SUCCEEDED(hr), "Failed to update Vertex Data");
|
||||
}
|
||||
}
|
||||
@ -663,13 +671,13 @@ namespace Blah
|
||||
else if (vertices)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
auto hr = state.context->Map(vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
auto hr = renderer->context->Map(vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
BLAH_ASSERT(SUCCEEDED(hr), "Failed to update Vertex Data");
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
memcpy(map.pData, vertices, vertex_format.stride * count);
|
||||
state.context->Unmap(vertex_buffer, 0);
|
||||
renderer->context->Unmap(vertex_buffer, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -695,10 +703,9 @@ namespace Blah
|
||||
}
|
||||
};
|
||||
|
||||
bool Graphics::init()
|
||||
bool Renderer_D3D11::init()
|
||||
{
|
||||
state = D3D11();
|
||||
state.last_size = Point(App::draw_width(), App::draw_height());
|
||||
last_size = Point(App::backbuffer()->width(), App::backbuffer()->height());
|
||||
|
||||
// Define Swap Chain
|
||||
DXGI_SWAP_CHAIN_DESC desc = {};
|
||||
@ -729,21 +736,21 @@ namespace Blah
|
||||
0,
|
||||
D3D11_SDK_VERSION,
|
||||
&desc,
|
||||
&state.swap_chain,
|
||||
&state.device,
|
||||
&swap_chain,
|
||||
&device,
|
||||
&feature_level,
|
||||
&state.context);
|
||||
&context);
|
||||
|
||||
// Exit out if it's not OK
|
||||
if (!SUCCEEDED(hr) || !state.swap_chain || !state.device || !state.context)
|
||||
if (!SUCCEEDED(hr) || !swap_chain || !device || !context)
|
||||
return false;
|
||||
|
||||
// Get the backbuffer
|
||||
ID3D11Texture2D* frame_buffer = nullptr;
|
||||
state.swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&frame_buffer);
|
||||
swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&frame_buffer);
|
||||
if (frame_buffer)
|
||||
{
|
||||
state.device->CreateRenderTargetView(frame_buffer, nullptr, &state.backbuffer_view);
|
||||
device->CreateRenderTargetView(frame_buffer, nullptr, &backbuffer_view);
|
||||
frame_buffer->Release();
|
||||
}
|
||||
|
||||
@ -751,9 +758,10 @@ namespace Blah
|
||||
// create a depth backbuffer
|
||||
|
||||
// Store Features
|
||||
state.features.instancing = true;
|
||||
state.features.max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
state.features.origin_bottom_left = false;
|
||||
features.type = RendererType::D3D11;
|
||||
features.instancing = true;
|
||||
features.max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
features.origin_bottom_left = false;
|
||||
|
||||
// Print Driver Info
|
||||
{
|
||||
@ -761,7 +769,7 @@ namespace Blah
|
||||
IDXGIAdapter* dxgi_adapter;
|
||||
DXGI_ADAPTER_DESC adapter_desc;
|
||||
|
||||
hr = state.device->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgi_device);
|
||||
hr = device->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgi_device);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
@ -782,85 +790,72 @@ namespace Blah
|
||||
return true;
|
||||
}
|
||||
|
||||
Renderer Graphics::renderer()
|
||||
{
|
||||
return Renderer::D3D11;
|
||||
}
|
||||
|
||||
void Graphics::shutdown()
|
||||
void Renderer_D3D11::shutdown()
|
||||
{
|
||||
// release cached objects
|
||||
for (auto& it : state.blend_cache)
|
||||
for (auto& it : blend_cache)
|
||||
it.state->Release();
|
||||
for (auto& it : state.depthstencil_cache)
|
||||
for (auto& it : depthstencil_cache)
|
||||
it.state->Release();
|
||||
for (auto& it : state.layout_cache)
|
||||
for (auto& it : layout_cache)
|
||||
it.layout->Release();
|
||||
for (auto& it : state.rasterizer_cache)
|
||||
for (auto& it : rasterizer_cache)
|
||||
it.state->Release();
|
||||
for (auto& it : state.sampler_cache)
|
||||
for (auto& it : sampler_cache)
|
||||
it.state->Release();
|
||||
|
||||
// release main devices
|
||||
if (state.backbuffer_view)
|
||||
state.backbuffer_view->Release();
|
||||
if (state.backbuffer_depth_view)
|
||||
state.backbuffer_depth_view->Release();
|
||||
state.swap_chain->Release();
|
||||
state.context->ClearState();
|
||||
state.context->Flush();
|
||||
state.context->Release();
|
||||
state.device->Release();
|
||||
|
||||
// reset state
|
||||
state = D3D11();
|
||||
if (backbuffer_view)
|
||||
backbuffer_view->Release();
|
||||
if (backbuffer_depth_view)
|
||||
backbuffer_depth_view->Release();
|
||||
swap_chain->Release();
|
||||
context->ClearState();
|
||||
context->Flush();
|
||||
context->Release();
|
||||
device->Release();
|
||||
}
|
||||
|
||||
const RendererFeatures& Graphics::features()
|
||||
void Renderer_D3D11::update()
|
||||
{
|
||||
return state.features;
|
||||
|
||||
}
|
||||
|
||||
void Graphics::update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Graphics::before_render()
|
||||
void Renderer_D3D11::before_render()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
auto next_size = Point(App::draw_width(), App::draw_height());
|
||||
if (state.last_size != next_size)
|
||||
auto next_size = Point(App::backbuffer()->width(), App::backbuffer()->height());
|
||||
if (last_size != next_size)
|
||||
{
|
||||
// release old buffer
|
||||
if (state.backbuffer_view)
|
||||
state.backbuffer_view->Release();
|
||||
if (backbuffer_view)
|
||||
backbuffer_view->Release();
|
||||
|
||||
// perform resize
|
||||
hr = state.swap_chain->ResizeBuffers(0, next_size.x, next_size.y, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
|
||||
hr = swap_chain->ResizeBuffers(0, next_size.x, next_size.y, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
|
||||
BLAH_ASSERT(SUCCEEDED(hr), "Failed to update Backbuffer on Resize");
|
||||
state.last_size = next_size;
|
||||
last_size = next_size;
|
||||
|
||||
// get the new buffer
|
||||
ID3D11Texture2D* frame_buffer = nullptr;
|
||||
hr = state.swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&frame_buffer);
|
||||
hr = swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&frame_buffer);
|
||||
if (SUCCEEDED(hr) && frame_buffer)
|
||||
{
|
||||
hr = state.device->CreateRenderTargetView(frame_buffer, nullptr, &state.backbuffer_view);
|
||||
hr = device->CreateRenderTargetView(frame_buffer, nullptr, &backbuffer_view);
|
||||
BLAH_ASSERT(SUCCEEDED(hr), "Failed to update Backbuffer on Resize");
|
||||
frame_buffer->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::after_render()
|
||||
void Renderer_D3D11::after_render()
|
||||
{
|
||||
auto hr = state.swap_chain->Present(1, 0);
|
||||
auto hr = swap_chain->Present(1, 0);
|
||||
BLAH_ASSERT(SUCCEEDED(hr), "Failed to Present swap chain");
|
||||
}
|
||||
|
||||
TextureRef Graphics::create_texture(int width, int height, TextureFormat format)
|
||||
TextureRef Renderer_D3D11::create_texture(int width, int height, TextureFormat format)
|
||||
{
|
||||
auto result = new D3D11_Texture(width, height, format, false);
|
||||
|
||||
@ -871,12 +866,12 @@ namespace Blah
|
||||
return TextureRef();
|
||||
}
|
||||
|
||||
TargetRef Graphics::create_target(int width, int height, const TextureFormat* attachments, int attachment_count)
|
||||
TargetRef Renderer_D3D11::create_target(int width, int height, const TextureFormat* attachments, int attachment_count)
|
||||
{
|
||||
return TargetRef(new D3D11_Target(width, height, attachments, attachment_count));
|
||||
}
|
||||
|
||||
ShaderRef Graphics::create_shader(const ShaderData* data)
|
||||
ShaderRef Renderer_D3D11::create_shader(const ShaderData* data)
|
||||
{
|
||||
auto result = new D3D11_Shader(data);
|
||||
if (result->valid)
|
||||
@ -886,23 +881,23 @@ namespace Blah
|
||||
return ShaderRef();
|
||||
}
|
||||
|
||||
MeshRef Graphics::create_mesh()
|
||||
MeshRef Renderer_D3D11::create_mesh()
|
||||
{
|
||||
return MeshRef(new D3D11_Mesh());
|
||||
}
|
||||
|
||||
void Graphics::render(const RenderPass& pass)
|
||||
void Renderer_D3D11::render(const RenderPass& pass)
|
||||
{
|
||||
auto ctx = state.context;
|
||||
auto ctx = context;
|
||||
auto mesh = (D3D11_Mesh*)pass.mesh.get();
|
||||
auto shader = (D3D11_Shader*)(pass.material->shader().get());
|
||||
|
||||
// OM
|
||||
{
|
||||
// Set the Target
|
||||
if (pass.target == App::backbuffer || !pass.target)
|
||||
if (pass.target == App::backbuffer() || !pass.target)
|
||||
{
|
||||
ctx->OMSetRenderTargets(1, &state.backbuffer_view, state.backbuffer_depth_view);
|
||||
ctx->OMSetRenderTargets(1, &backbuffer_view, backbuffer_depth_view);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -912,14 +907,14 @@ namespace Blah
|
||||
|
||||
// Depth
|
||||
{
|
||||
auto depthstencil = state.get_depthstencil(pass);
|
||||
auto depthstencil = get_depthstencil(pass);
|
||||
if (depthstencil)
|
||||
ctx->OMSetDepthStencilState(depthstencil, 0);
|
||||
}
|
||||
|
||||
// Blend Mode
|
||||
{
|
||||
auto blend = state.get_blend(pass.blend);
|
||||
auto blend = get_blend(pass.blend);
|
||||
if (blend)
|
||||
{
|
||||
auto color = Color::from_rgba(pass.blend.rgba);
|
||||
@ -941,7 +936,7 @@ namespace Blah
|
||||
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
// Assign Layout
|
||||
auto layout = state.get_layout(shader, mesh->vertex_format);
|
||||
auto layout = get_layout(shader, mesh->vertex_format);
|
||||
ctx->IASetInputLayout(layout);
|
||||
|
||||
// Assign Vertex Buffer
|
||||
@ -1000,7 +995,7 @@ namespace Blah
|
||||
auto& samplers = pass.material->samplers();
|
||||
for (int i = 0; i < samplers.size(); i++)
|
||||
{
|
||||
auto sampler = state.get_sampler(samplers[i]);
|
||||
auto sampler = get_sampler(samplers[i]);
|
||||
if (sampler)
|
||||
ctx->PSSetSamplers(i, 1, &sampler);
|
||||
}
|
||||
@ -1034,7 +1029,7 @@ namespace Blah
|
||||
|
||||
// Rasterizer
|
||||
{
|
||||
auto rasterizer = state.get_rasterizer(pass);
|
||||
auto rasterizer = get_rasterizer(pass);
|
||||
if (rasterizer)
|
||||
ctx->RSSetState(rasterizer);
|
||||
}
|
||||
@ -1065,15 +1060,15 @@ namespace Blah
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask)
|
||||
void Renderer_D3D11::clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask)
|
||||
{
|
||||
if (((int)mask & (int)ClearMask::Color) == (int)ClearMask::Color)
|
||||
{
|
||||
float clear[4] = { color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f };
|
||||
state.context->ClearRenderTargetView(state.backbuffer_view, clear);
|
||||
context->ClearRenderTargetView(backbuffer_view, clear);
|
||||
}
|
||||
|
||||
if (state.backbuffer_depth_view)
|
||||
if (backbuffer_depth_view)
|
||||
{
|
||||
UINT flags = 0;
|
||||
if (((int)mask & (int)ClearMask::Depth) == (int)ClearMask::Depth)
|
||||
@ -1082,7 +1077,7 @@ namespace Blah
|
||||
flags |= D3D11_CLEAR_STENCIL;
|
||||
|
||||
if (flags != 0)
|
||||
state.context->ClearDepthStencilView(state.backbuffer_depth_view, flags, depth, stencil);
|
||||
context->ClearDepthStencilView(backbuffer_depth_view, flags, depth, stencil);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1179,7 +1174,7 @@ namespace Blah
|
||||
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
|
||||
ID3D11Buffer* buffer;
|
||||
state.device->CreateBuffer(&buffer_desc, nullptr, &buffer);
|
||||
renderer->device->CreateBuffer(&buffer_desc, nullptr, &buffer);
|
||||
append_buffers_to.push_back(buffer);
|
||||
}
|
||||
|
||||
@ -1278,14 +1273,14 @@ namespace Blah
|
||||
if (buffers[i])
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
state.context->Map(buffers[i], 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
renderer->context->Map(buffers[i], 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
memcpy(map.pData, values[i].begin(), values[i].size() * sizeof(float));
|
||||
state.context->Unmap(buffers[i], 0);
|
||||
renderer->context->Unmap(buffers[i], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11InputLayout* D3D11::get_layout(D3D11_Shader* shader, const VertexFormat& format)
|
||||
ID3D11InputLayout* Renderer_D3D11::get_layout(D3D11_Shader* shader, const VertexFormat& format)
|
||||
{
|
||||
// find existing
|
||||
for (auto& it : layout_cache)
|
||||
@ -1374,7 +1369,7 @@ namespace Blah
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11BlendState* D3D11::get_blend(const BlendMode& blend)
|
||||
ID3D11BlendState* Renderer_D3D11::get_blend(const BlendMode& blend)
|
||||
{
|
||||
for (auto& it : blend_cache)
|
||||
if (it.blend == blend)
|
||||
@ -1414,7 +1409,7 @@ namespace Blah
|
||||
desc.RenderTarget[i] = desc.RenderTarget[0];
|
||||
|
||||
ID3D11BlendState* blend_state = nullptr;
|
||||
auto hr = state.device->CreateBlendState(&desc, &blend_state);
|
||||
auto hr = renderer->device->CreateBlendState(&desc, &blend_state);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
@ -1427,7 +1422,7 @@ namespace Blah
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11SamplerState* D3D11::get_sampler(const TextureSampler& sampler)
|
||||
ID3D11SamplerState* Renderer_D3D11::get_sampler(const TextureSampler& sampler)
|
||||
{
|
||||
for (auto& it : sampler_cache)
|
||||
if (it.sampler == sampler)
|
||||
@ -1462,7 +1457,7 @@ namespace Blah
|
||||
}
|
||||
|
||||
ID3D11SamplerState* result;
|
||||
auto hr = state.device->CreateSamplerState(&desc, &result);
|
||||
auto hr = renderer->device->CreateSamplerState(&desc, &result);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
@ -1475,7 +1470,7 @@ namespace Blah
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11RasterizerState* D3D11::get_rasterizer(const RenderPass& pass)
|
||||
ID3D11RasterizerState* Renderer_D3D11::get_rasterizer(const RenderPass& pass)
|
||||
{
|
||||
for (auto& it : rasterizer_cache)
|
||||
if (it.cull == pass.cull && it.has_scissor == pass.has_scissor)
|
||||
@ -1502,7 +1497,7 @@ namespace Blah
|
||||
desc.AntialiasedLineEnable = false;
|
||||
|
||||
ID3D11RasterizerState* result;
|
||||
auto hr = state.device->CreateRasterizerState(&desc, &result);
|
||||
auto hr = renderer->device->CreateRasterizerState(&desc, &result);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
@ -1516,7 +1511,7 @@ namespace Blah
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11DepthStencilState* D3D11::get_depthstencil(const RenderPass& pass)
|
||||
ID3D11DepthStencilState* Renderer_D3D11::get_depthstencil(const RenderPass& pass)
|
||||
{
|
||||
for (auto& it : depthstencil_cache)
|
||||
if (it.depth == pass.depth)
|
||||
@ -1541,7 +1536,7 @@ namespace Blah
|
||||
}
|
||||
|
||||
ID3D11DepthStencilState* result;
|
||||
auto hr = state.device->CreateDepthStencilState(&desc, &result);
|
||||
auto hr = renderer->device->CreateDepthStencilState(&desc, &result);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
@ -1555,4 +1550,17 @@ namespace Blah
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BLAH_GRAPHICS_D3D11
|
||||
Blah::Renderer* Blah::Renderer::try_make_d3d11()
|
||||
{
|
||||
return new Blah::Renderer_D3D11();
|
||||
}
|
||||
|
||||
#else // BLAH_RENDERER_D3D11
|
||||
|
||||
#include "renderer.h"
|
||||
Blah::Renderer* Blah::Renderer::try_make_d3d11()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,6 +1,6 @@
|
||||
#ifdef BLAH_GRAPHICS_OPENGL
|
||||
#ifdef BLAH_RENDERER_OPENGL
|
||||
|
||||
#include "graphics.h"
|
||||
#include "renderer.h"
|
||||
#include "platform.h"
|
||||
#include <blah/common.h>
|
||||
#include <stdio.h>
|
||||
@ -338,14 +338,22 @@ typedef void (APIENTRY* DEBUGPROC)(GLenum source,
|
||||
const GLchar* message,
|
||||
const void* userParam);
|
||||
|
||||
// shorthand to our internal state
|
||||
#define renderer ((Renderer_OpenGL*)Renderer::instance)
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
struct State
|
||||
class Renderer_OpenGL : public Renderer
|
||||
{
|
||||
// GL function pointers
|
||||
#define GL_FUNC(name, ret, ...) typedef ret (*name ## Func) (__VA_ARGS__); name ## Func name;
|
||||
GL_FUNCTIONS
|
||||
#undef GL_FUNC
|
||||
public:
|
||||
|
||||
struct Bindings
|
||||
{
|
||||
// GL function pointers
|
||||
#define GL_FUNC(name, ret, ...) typedef ret (*name ## Func) (__VA_ARGS__); name ## Func name;
|
||||
GL_FUNCTIONS
|
||||
#undef GL_FUNC
|
||||
} gl;
|
||||
|
||||
// state
|
||||
void* context;
|
||||
@ -358,11 +366,19 @@ namespace Blah
|
||||
int max_samples;
|
||||
int max_texture_image_units;
|
||||
int max_texture_size;
|
||||
RendererFeatures features;
|
||||
};
|
||||
|
||||
// static state
|
||||
State gl;
|
||||
bool init() override;
|
||||
void shutdown() override;
|
||||
void update() override;
|
||||
void before_render() override;
|
||||
void after_render() override;
|
||||
void render(const RenderPass& pass) override;
|
||||
void clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask) override;
|
||||
TextureRef create_texture(int width, int height, TextureFormat format) override;
|
||||
TargetRef create_target(int width, int height, const TextureFormat* attachments, int attachment_count) override;
|
||||
ShaderRef create_shader(const ShaderData* data) override;
|
||||
MeshRef create_mesh() override;
|
||||
};
|
||||
|
||||
// debug callback
|
||||
void APIENTRY gl_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
|
||||
@ -408,7 +424,7 @@ namespace Blah
|
||||
GLuint gl_mesh_assign_attributes(GLuint buffer, GLenum buffer_type, const VertexFormat& format, GLint divisor)
|
||||
{
|
||||
// bind
|
||||
gl.BindBuffer(buffer_type, buffer);
|
||||
renderer->gl.BindBuffer(buffer_type, buffer);
|
||||
|
||||
// TODO: disable existing enabled attributes ..
|
||||
// ...
|
||||
@ -485,9 +501,9 @@ namespace Blah
|
||||
}
|
||||
|
||||
u32 location = (u32)(attribute.index);
|
||||
gl.EnableVertexAttribArray(location);
|
||||
gl.VertexAttribPointer(location, components, type, attribute.normalized, format.stride, (void*)ptr);
|
||||
gl.VertexAttribDivisor(location, divisor);
|
||||
renderer->gl.EnableVertexAttribArray(location);
|
||||
renderer->gl.VertexAttribPointer(location, components, type, attribute.normalized, format.stride, (void*)ptr);
|
||||
renderer->gl.VertexAttribDivisor(location, divisor);
|
||||
|
||||
ptr += components * component_size;
|
||||
}
|
||||
@ -565,9 +581,9 @@ namespace Blah
|
||||
m_gl_format = GL_RED;
|
||||
m_gl_type = GL_UNSIGNED_BYTE;
|
||||
|
||||
if (width > gl.max_texture_size || height > gl.max_texture_size)
|
||||
if (width > renderer->max_texture_size || height > renderer->max_texture_size)
|
||||
{
|
||||
Log::error("Exceeded Max Texture Size of %i", gl.max_texture_size);
|
||||
Log::error("Exceeded Max Texture Size of %i", renderer->max_texture_size);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -601,16 +617,16 @@ namespace Blah
|
||||
return;
|
||||
}
|
||||
|
||||
gl.GenTextures(1, &m_id);
|
||||
gl.ActiveTexture(GL_TEXTURE0);
|
||||
gl.BindTexture(GL_TEXTURE_2D, m_id);
|
||||
gl.TexImage2D(GL_TEXTURE_2D, 0, m_gl_internal_format, width, height, 0, m_gl_format, m_gl_type, nullptr);
|
||||
renderer->gl.GenTextures(1, &m_id);
|
||||
renderer->gl.ActiveTexture(GL_TEXTURE0);
|
||||
renderer->gl.BindTexture(GL_TEXTURE_2D, m_id);
|
||||
renderer->gl.TexImage2D(GL_TEXTURE_2D, 0, m_gl_internal_format, width, height, 0, m_gl_format, m_gl_type, nullptr);
|
||||
}
|
||||
|
||||
~OpenGL_Texture()
|
||||
{
|
||||
if (m_id > 0)
|
||||
gl.DeleteTextures(1, &m_id);
|
||||
if (m_id > 0 && renderer)
|
||||
renderer->gl.DeleteTextures(1, &m_id);
|
||||
}
|
||||
|
||||
GLuint gl_id() const
|
||||
@ -639,26 +655,26 @@ namespace Blah
|
||||
{
|
||||
m_sampler = sampler;
|
||||
|
||||
gl.BindTexture(GL_TEXTURE_2D, m_id);
|
||||
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (m_sampler.filter == TextureFilter::Nearest ? GL_NEAREST : GL_LINEAR));
|
||||
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (m_sampler.filter == TextureFilter::Nearest ? GL_NEAREST : GL_LINEAR));
|
||||
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (m_sampler.wrap_x == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
|
||||
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (m_sampler.wrap_y == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
|
||||
renderer->gl.BindTexture(GL_TEXTURE_2D, m_id);
|
||||
renderer->gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (m_sampler.filter == TextureFilter::Nearest ? GL_NEAREST : GL_LINEAR));
|
||||
renderer->gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (m_sampler.filter == TextureFilter::Nearest ? GL_NEAREST : GL_LINEAR));
|
||||
renderer->gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (m_sampler.wrap_x == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
|
||||
renderer->gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (m_sampler.wrap_y == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_data(unsigned char* data) override
|
||||
{
|
||||
gl.ActiveTexture(GL_TEXTURE0);
|
||||
gl.BindTexture(GL_TEXTURE_2D, m_id);
|
||||
gl.TexImage2D(GL_TEXTURE_2D, 0, m_gl_internal_format, m_width, m_height, 0, m_gl_format, m_gl_type, data);
|
||||
renderer->gl.ActiveTexture(GL_TEXTURE0);
|
||||
renderer->gl.BindTexture(GL_TEXTURE_2D, m_id);
|
||||
renderer->gl.TexImage2D(GL_TEXTURE_2D, 0, m_gl_internal_format, m_width, m_height, 0, m_gl_format, m_gl_type, data);
|
||||
}
|
||||
|
||||
virtual void get_data(unsigned char* data) override
|
||||
{
|
||||
gl.ActiveTexture(GL_TEXTURE0);
|
||||
gl.BindTexture(GL_TEXTURE_2D, m_id);
|
||||
gl.GetTexImage(GL_TEXTURE_2D, 0, m_gl_internal_format, m_gl_type, data);
|
||||
renderer->gl.ActiveTexture(GL_TEXTURE0);
|
||||
renderer->gl.BindTexture(GL_TEXTURE_2D, m_id);
|
||||
renderer->gl.GetTexImage(GL_TEXTURE_2D, 0, m_gl_internal_format, m_gl_type, data);
|
||||
}
|
||||
|
||||
virtual bool is_framebuffer() const override
|
||||
@ -680,11 +696,11 @@ namespace Blah
|
||||
|
||||
OpenGL_Target(int width, int height, const TextureFormat* attachments, int attachmentCount)
|
||||
{
|
||||
gl.GenFramebuffers(1, &m_id);
|
||||
renderer->gl.GenFramebuffers(1, &m_id);
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
|
||||
gl.BindFramebuffer(GL_FRAMEBUFFER, m_id);
|
||||
renderer->gl.BindFramebuffer(GL_FRAMEBUFFER, m_id);
|
||||
|
||||
for (int i = 0; i < attachmentCount; i++)
|
||||
{
|
||||
@ -696,20 +712,20 @@ namespace Blah
|
||||
|
||||
if (attachments[i] != TextureFormat::DepthStencil)
|
||||
{
|
||||
gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, gltex->gl_id(), 0);
|
||||
renderer->gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, gltex->gl_id(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, gltex->gl_id(), 0);
|
||||
renderer->gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, gltex->gl_id(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~OpenGL_Target()
|
||||
{
|
||||
if (m_id > 0)
|
||||
if (m_id > 0 && renderer)
|
||||
{
|
||||
gl.DeleteFramebuffers(1, &m_id);
|
||||
renderer->gl.DeleteFramebuffers(1, &m_id);
|
||||
m_id = 0;
|
||||
}
|
||||
}
|
||||
@ -740,13 +756,13 @@ namespace Blah
|
||||
if (((int)mask & (int)ClearMask::Stencil) == (int)ClearMask::Stencil)
|
||||
clear |= GL_STENCIL_BUFFER_BIT;
|
||||
|
||||
gl.BindFramebuffer(GL_FRAMEBUFFER, m_id);
|
||||
gl.Disable(GL_SCISSOR_TEST);
|
||||
gl.ColorMask(true, true, true, true);
|
||||
gl.ClearColor(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f);
|
||||
gl.ClearDepth(depth);
|
||||
gl.ClearStencil(stencil);
|
||||
gl.Clear(clear);
|
||||
renderer->gl.BindFramebuffer(GL_FRAMEBUFFER, m_id);
|
||||
renderer->gl.Disable(GL_SCISSOR_TEST);
|
||||
renderer->gl.ColorMask(true, true, true, true);
|
||||
renderer->gl.ClearColor(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f);
|
||||
renderer->gl.ClearDepth(depth);
|
||||
renderer->gl.ClearStencil(stencil);
|
||||
renderer->gl.Clear(clear);
|
||||
}
|
||||
};
|
||||
|
||||
@ -778,47 +794,47 @@ namespace Blah
|
||||
GLchar log[1024];
|
||||
GLsizei log_length = 0;
|
||||
|
||||
GLuint vertex_shader = gl.CreateShader(GL_VERTEX_SHADER);
|
||||
GLuint vertex_shader = renderer->gl.CreateShader(GL_VERTEX_SHADER);
|
||||
{
|
||||
const GLchar* source = (const GLchar*)data->vertex.cstr();
|
||||
gl.ShaderSource(vertex_shader, 1, &source, nullptr);
|
||||
gl.CompileShader(vertex_shader);
|
||||
gl.GetShaderInfoLog(vertex_shader, 1024, &log_length, log);
|
||||
renderer->gl.ShaderSource(vertex_shader, 1, &source, nullptr);
|
||||
renderer->gl.CompileShader(vertex_shader);
|
||||
renderer->gl.GetShaderInfoLog(vertex_shader, 1024, &log_length, log);
|
||||
|
||||
if (log_length > 0)
|
||||
{
|
||||
gl.DeleteShader(vertex_shader);
|
||||
renderer->gl.DeleteShader(vertex_shader);
|
||||
Log::error(log);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint fragment_shader = gl.CreateShader(GL_FRAGMENT_SHADER);
|
||||
GLuint fragment_shader = renderer->gl.CreateShader(GL_FRAGMENT_SHADER);
|
||||
{
|
||||
const GLchar* source = (const GLchar*)data->fragment.cstr();
|
||||
gl.ShaderSource(fragment_shader, 1, &source, nullptr);
|
||||
gl.CompileShader(fragment_shader);
|
||||
gl.GetShaderInfoLog(fragment_shader, 1024, &log_length, log);
|
||||
renderer->gl.ShaderSource(fragment_shader, 1, &source, nullptr);
|
||||
renderer->gl.CompileShader(fragment_shader);
|
||||
renderer->gl.GetShaderInfoLog(fragment_shader, 1024, &log_length, log);
|
||||
|
||||
if (log_length > 0)
|
||||
{
|
||||
gl.DeleteShader(vertex_shader);
|
||||
gl.DeleteShader(fragment_shader);
|
||||
renderer->gl.DeleteShader(vertex_shader);
|
||||
renderer->gl.DeleteShader(fragment_shader);
|
||||
Log::error(log);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// create actual shader program
|
||||
GLuint id = gl.CreateProgram();
|
||||
gl.AttachShader(id, vertex_shader);
|
||||
gl.AttachShader(id, fragment_shader);
|
||||
gl.LinkProgram(id);
|
||||
gl.GetProgramInfoLog(id, 1024, &log_length, log);
|
||||
gl.DetachShader(id, vertex_shader);
|
||||
gl.DetachShader(id, fragment_shader);
|
||||
gl.DeleteShader(vertex_shader);
|
||||
gl.DeleteShader(fragment_shader);
|
||||
GLuint id = renderer->gl.CreateProgram();
|
||||
renderer->gl.AttachShader(id, vertex_shader);
|
||||
renderer->gl.AttachShader(id, fragment_shader);
|
||||
renderer->gl.LinkProgram(id);
|
||||
renderer->gl.GetProgramInfoLog(id, 1024, &log_length, log);
|
||||
renderer->gl.DetachShader(id, vertex_shader);
|
||||
renderer->gl.DetachShader(id, fragment_shader);
|
||||
renderer->gl.DeleteShader(vertex_shader);
|
||||
renderer->gl.DeleteShader(fragment_shader);
|
||||
|
||||
if (log_length > 0)
|
||||
{
|
||||
@ -832,7 +848,7 @@ namespace Blah
|
||||
const int max_name_length = 256;
|
||||
|
||||
GLint active_uniforms = 0;
|
||||
gl.GetProgramiv(id, GL_ACTIVE_UNIFORMS, &active_uniforms);
|
||||
renderer->gl.GetProgramiv(id, GL_ACTIVE_UNIFORMS, &active_uniforms);
|
||||
|
||||
for (int i = 0; i < active_uniforms; i++)
|
||||
{
|
||||
@ -841,7 +857,7 @@ namespace Blah
|
||||
GLenum type;
|
||||
GLchar name[max_name_length + 1];
|
||||
|
||||
gl.GetActiveUniform(id, i, max_name_length, &length, &size, &type, name);
|
||||
renderer->gl.GetActiveUniform(id, i, max_name_length, &length, &size, &type, name);
|
||||
name[length] = '\0';
|
||||
|
||||
// array names end with "[0]", and we don't want that
|
||||
@ -863,7 +879,7 @@ namespace Blah
|
||||
tex_uniform.array_length = size;
|
||||
tex_uniform.type = UniformType::Texture2D;
|
||||
tex_uniform.shader = ShaderType::Fragment;
|
||||
uniform_locations.push_back(gl.GetUniformLocation(id, name));
|
||||
uniform_locations.push_back(renderer->gl.GetUniformLocation(id, name));
|
||||
m_uniforms.push_back(tex_uniform);
|
||||
|
||||
UniformInfo sampler_uniform;
|
||||
@ -872,7 +888,7 @@ namespace Blah
|
||||
sampler_uniform.array_length = size;
|
||||
sampler_uniform.type = UniformType::Sampler2D;
|
||||
sampler_uniform.shader = ShaderType::Fragment;
|
||||
uniform_locations.push_back(gl.GetUniformLocation(id, name));
|
||||
uniform_locations.push_back(renderer->gl.GetUniformLocation(id, name));
|
||||
m_uniforms.push_back(sampler_uniform);
|
||||
}
|
||||
else
|
||||
@ -882,7 +898,7 @@ namespace Blah
|
||||
uniform.type = UniformType::None;
|
||||
uniform.buffer_index = 0;
|
||||
uniform.array_length = size;
|
||||
uniform_locations.push_back(gl.GetUniformLocation(id, name));
|
||||
uniform_locations.push_back(renderer->gl.GetUniformLocation(id, name));
|
||||
uniform.shader = (ShaderType)((int)ShaderType::Vertex | (int)ShaderType::Fragment);
|
||||
|
||||
if (type == GL_FLOAT)
|
||||
@ -912,15 +928,15 @@ namespace Blah
|
||||
|
||||
// assign ID if the uniforms were valid
|
||||
if (!valid_uniforms)
|
||||
gl.DeleteProgram(id);
|
||||
renderer->gl.DeleteProgram(id);
|
||||
else
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
~OpenGL_Shader()
|
||||
{
|
||||
if (m_id > 0)
|
||||
gl.DeleteProgram(m_id);
|
||||
if (m_id > 0 && renderer)
|
||||
renderer->gl.DeleteProgram(m_id);
|
||||
m_id = 0;
|
||||
}
|
||||
|
||||
@ -975,19 +991,22 @@ namespace Blah
|
||||
m_vertex_attribs_enabled = 0;
|
||||
m_instance_attribs_enabled = 0;
|
||||
|
||||
gl.GenVertexArrays(1, &m_id);
|
||||
renderer->gl.GenVertexArrays(1, &m_id);
|
||||
}
|
||||
|
||||
~OpenGL_Mesh()
|
||||
{
|
||||
if (m_vertex_buffer != 0)
|
||||
gl.DeleteBuffers(1, &m_vertex_buffer);
|
||||
if (m_index_buffer != 0)
|
||||
gl.DeleteBuffers(1, &m_index_buffer);
|
||||
if (m_instance_buffer != 0)
|
||||
gl.DeleteBuffers(1, &m_instance_buffer);
|
||||
if (m_id != 0)
|
||||
gl.DeleteVertexArrays(1, &m_id);
|
||||
if (renderer)
|
||||
{
|
||||
if (m_vertex_buffer != 0)
|
||||
renderer->gl.DeleteBuffers(1, &m_vertex_buffer);
|
||||
if (m_index_buffer != 0)
|
||||
renderer->gl.DeleteBuffers(1, &m_index_buffer);
|
||||
if (m_instance_buffer != 0)
|
||||
renderer->gl.DeleteBuffers(1, &m_instance_buffer);
|
||||
if (m_id != 0)
|
||||
renderer->gl.DeleteVertexArrays(1, &m_id);
|
||||
}
|
||||
m_id = 0;
|
||||
}
|
||||
|
||||
@ -1010,10 +1029,10 @@ namespace Blah
|
||||
{
|
||||
m_index_count = count;
|
||||
|
||||
gl.BindVertexArray(m_id);
|
||||
renderer->gl.BindVertexArray(m_id);
|
||||
{
|
||||
if (m_index_buffer == 0)
|
||||
gl.GenBuffers(1, &(m_index_buffer));
|
||||
renderer->gl.GenBuffers(1, &(m_index_buffer));
|
||||
|
||||
switch (format)
|
||||
{
|
||||
@ -1027,52 +1046,52 @@ namespace Blah
|
||||
break;
|
||||
}
|
||||
|
||||
gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
|
||||
gl.BufferData(GL_ELEMENT_ARRAY_BUFFER, m_index_size * count, indices, GL_DYNAMIC_DRAW);
|
||||
renderer->gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
|
||||
renderer->gl.BufferData(GL_ELEMENT_ARRAY_BUFFER, m_index_size * count, indices, GL_DYNAMIC_DRAW);
|
||||
}
|
||||
gl.BindVertexArray(0);
|
||||
renderer->gl.BindVertexArray(0);
|
||||
}
|
||||
|
||||
virtual void vertex_data(const VertexFormat& format, const void* vertices, i64 count) override
|
||||
{
|
||||
m_vertex_count = count;
|
||||
|
||||
gl.BindVertexArray(m_id);
|
||||
renderer->gl.BindVertexArray(m_id);
|
||||
{
|
||||
// Create Buffer if it doesn't exist yet
|
||||
if (m_vertex_buffer == 0)
|
||||
gl.GenBuffers(1, &(m_vertex_buffer));
|
||||
renderer->gl.GenBuffers(1, &(m_vertex_buffer));
|
||||
|
||||
// TODO:
|
||||
// Cache this
|
||||
m_vertex_size = gl_mesh_assign_attributes(m_vertex_buffer, GL_ARRAY_BUFFER, format, 0);
|
||||
|
||||
// Upload Buffer
|
||||
gl.BindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
|
||||
gl.BufferData(GL_ARRAY_BUFFER, m_vertex_size * count, vertices, GL_DYNAMIC_DRAW);
|
||||
renderer->gl.BindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
|
||||
renderer->gl.BufferData(GL_ARRAY_BUFFER, m_vertex_size * count, vertices, GL_DYNAMIC_DRAW);
|
||||
}
|
||||
gl.BindVertexArray(0);
|
||||
renderer->gl.BindVertexArray(0);
|
||||
}
|
||||
|
||||
virtual void instance_data(const VertexFormat& format, const void* instances, i64 count) override
|
||||
{
|
||||
m_instance_count = count;
|
||||
|
||||
gl.BindVertexArray(m_id);
|
||||
renderer->gl.BindVertexArray(m_id);
|
||||
{
|
||||
// Create Buffer if it doesn't exist yet
|
||||
if (m_instance_buffer == 0)
|
||||
gl.GenBuffers(1, &(m_instance_buffer));
|
||||
renderer->gl.GenBuffers(1, &(m_instance_buffer));
|
||||
|
||||
// TODO:
|
||||
// Cache this
|
||||
m_instance_size = gl_mesh_assign_attributes(m_instance_buffer, GL_ARRAY_BUFFER, format, 1);
|
||||
|
||||
// Upload Buffer
|
||||
gl.BindBuffer(GL_ARRAY_BUFFER, m_instance_buffer);
|
||||
gl.BufferData(GL_ARRAY_BUFFER, m_instance_size * count, instances, GL_DYNAMIC_DRAW);
|
||||
renderer->gl.BindBuffer(GL_ARRAY_BUFFER, m_instance_buffer);
|
||||
renderer->gl.BufferData(GL_ARRAY_BUFFER, m_instance_size * count, instances, GL_DYNAMIC_DRAW);
|
||||
}
|
||||
gl.BindVertexArray(0);
|
||||
renderer->gl.BindVertexArray(0);
|
||||
}
|
||||
|
||||
virtual i64 index_count() const override
|
||||
@ -1091,21 +1110,19 @@ namespace Blah
|
||||
}
|
||||
};
|
||||
|
||||
bool Graphics::init()
|
||||
bool Renderer_OpenGL::init()
|
||||
{
|
||||
gl = State();
|
||||
|
||||
// create gl context
|
||||
gl.context = Platform::gl_context_create();
|
||||
if (gl.context == nullptr)
|
||||
context = Platform::gl_context_create();
|
||||
if (context == nullptr)
|
||||
{
|
||||
Log::error("Failed to create OpenGL Context");
|
||||
return false;
|
||||
}
|
||||
Platform::gl_context_make_current(gl.context);
|
||||
Platform::gl_context_make_current(context);
|
||||
|
||||
// bind opengl functions
|
||||
#define GL_FUNC(name, ...) gl.name = (State::name ## Func)(Platform::gl_get_func("gl" #name));
|
||||
#define GL_FUNC(name, ...) gl.name = (Renderer_OpenGL::Bindings::name ## Func)(Platform::gl_get_func("gl" #name));
|
||||
GL_FUNCTIONS
|
||||
#undef GL_FUNC
|
||||
|
||||
@ -1118,13 +1135,13 @@ namespace Blah
|
||||
}
|
||||
|
||||
// get opengl info
|
||||
gl.GetIntegerv(0x8CDF, &gl.max_color_attachments);
|
||||
gl.GetIntegerv(0x80E9, &gl.max_element_indices);
|
||||
gl.GetIntegerv(0x80E8, &gl.max_element_vertices);
|
||||
gl.GetIntegerv(0x84E8, &gl.max_renderbuffer_size);
|
||||
gl.GetIntegerv(0x8D57, &gl.max_samples);
|
||||
gl.GetIntegerv(0x8872, &gl.max_texture_image_units);
|
||||
gl.GetIntegerv(0x0D33, &gl.max_texture_size);
|
||||
gl.GetIntegerv(0x8CDF, &max_color_attachments);
|
||||
gl.GetIntegerv(0x80E9, &max_element_indices);
|
||||
gl.GetIntegerv(0x80E8, &max_element_vertices);
|
||||
gl.GetIntegerv(0x84E8, &max_renderbuffer_size);
|
||||
gl.GetIntegerv(0x8D57, &max_samples);
|
||||
gl.GetIntegerv(0x8872, &max_texture_image_units);
|
||||
gl.GetIntegerv(0x0D33, &max_texture_size);
|
||||
|
||||
// log
|
||||
Log::info("OpenGL %s, %s",
|
||||
@ -1136,34 +1153,25 @@ namespace Blah
|
||||
gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
// assign info
|
||||
gl.features.instancing = true;
|
||||
gl.features.origin_bottom_left = true;
|
||||
gl.features.max_texture_size = gl.max_texture_size;
|
||||
features.type = RendererType::OpenGL;
|
||||
features.instancing = true;
|
||||
features.origin_bottom_left = true;
|
||||
features.max_texture_size = max_texture_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Renderer Graphics::renderer()
|
||||
void Renderer_OpenGL::shutdown()
|
||||
{
|
||||
return Renderer::OpenGL;
|
||||
Platform::gl_context_destroy(context);
|
||||
context = nullptr;
|
||||
}
|
||||
|
||||
void Graphics::shutdown()
|
||||
{
|
||||
Platform::gl_context_destroy(gl.context);
|
||||
gl.context = nullptr;
|
||||
}
|
||||
void Renderer_OpenGL::update() {}
|
||||
void Renderer_OpenGL::before_render() {}
|
||||
void Renderer_OpenGL::after_render() {}
|
||||
|
||||
const RendererFeatures& Graphics::features()
|
||||
{
|
||||
return gl.features;
|
||||
}
|
||||
|
||||
void Graphics::update() {}
|
||||
void Graphics::before_render() {}
|
||||
void Graphics::after_render() {}
|
||||
|
||||
TextureRef Graphics::create_texture(int width, int height, TextureFormat format)
|
||||
TextureRef Renderer_OpenGL::create_texture(int width, int height, TextureFormat format)
|
||||
{
|
||||
auto resource = new OpenGL_Texture(width, height, format);
|
||||
|
||||
@ -1176,7 +1184,7 @@ namespace Blah
|
||||
return TextureRef(resource);
|
||||
}
|
||||
|
||||
TargetRef Graphics::create_target(int width, int height, const TextureFormat* attachments, int attachmentCount)
|
||||
TargetRef Renderer_OpenGL::create_target(int width, int height, const TextureFormat* attachments, int attachmentCount)
|
||||
{
|
||||
auto resource = new OpenGL_Target(width, height, attachments, attachmentCount);
|
||||
|
||||
@ -1189,7 +1197,7 @@ namespace Blah
|
||||
return TargetRef(resource);
|
||||
}
|
||||
|
||||
ShaderRef Graphics::create_shader(const ShaderData* data)
|
||||
ShaderRef Renderer_OpenGL::create_shader(const ShaderData* data)
|
||||
{
|
||||
auto resource = new OpenGL_Shader(data);
|
||||
|
||||
@ -1202,7 +1210,7 @@ namespace Blah
|
||||
return ShaderRef(resource);
|
||||
}
|
||||
|
||||
MeshRef Graphics::create_mesh()
|
||||
MeshRef Renderer_OpenGL::create_mesh()
|
||||
{
|
||||
auto resource = new OpenGL_Mesh();
|
||||
|
||||
@ -1215,24 +1223,20 @@ namespace Blah
|
||||
return MeshRef(resource);
|
||||
}
|
||||
|
||||
void Graphics::render(const RenderPass& pass)
|
||||
void Renderer_OpenGL::render(const RenderPass& pass)
|
||||
{
|
||||
// Bind the Target
|
||||
Point size;
|
||||
if (pass.target == App::backbuffer)
|
||||
if (pass.target == App::backbuffer())
|
||||
{
|
||||
gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
size.x = App::draw_width();
|
||||
size.y = App::draw_height();
|
||||
renderer->gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
else if (pass.target)
|
||||
{
|
||||
auto framebuffer = (OpenGL_Target*)pass.target.get();
|
||||
gl.BindFramebuffer(GL_FRAMEBUFFER, framebuffer->gl_id());
|
||||
size.x = pass.target->width();
|
||||
size.y = pass.target->height();
|
||||
renderer->gl.BindFramebuffer(GL_FRAMEBUFFER, framebuffer->gl_id());
|
||||
}
|
||||
|
||||
auto size = Point(pass.target->width(), pass.target->height());
|
||||
auto shader_ref = pass.material->shader();
|
||||
auto shader = (OpenGL_Shader*)shader_ref.get();
|
||||
auto mesh = (OpenGL_Mesh*)pass.mesh.get();
|
||||
@ -1241,7 +1245,7 @@ namespace Blah
|
||||
// TODO: I don't love how material values are assigned or set here
|
||||
// TODO: this should be cached?
|
||||
{
|
||||
gl.UseProgram(shader->gl_id());
|
||||
renderer->gl.UseProgram(shader->gl_id());
|
||||
|
||||
int texture_slot = 0;
|
||||
int gl_texture_slot = 0;
|
||||
@ -1266,24 +1270,24 @@ namespace Blah
|
||||
auto tex = pass.material->get_texture(texture_slot, n);
|
||||
auto sampler = pass.material->get_sampler(texture_slot, n);
|
||||
|
||||
gl.ActiveTexture(GL_TEXTURE0 + gl_texture_slot);
|
||||
renderer->gl.ActiveTexture(GL_TEXTURE0 + gl_texture_slot);
|
||||
|
||||
if (!tex)
|
||||
{
|
||||
gl.BindTexture(GL_TEXTURE_2D, 0);
|
||||
renderer->gl.BindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto gl_tex = ((OpenGL_Texture*)tex.get());
|
||||
gl_tex->update_sampler(sampler);
|
||||
gl.BindTexture(GL_TEXTURE_2D, gl_tex->gl_id());
|
||||
renderer->gl.BindTexture(GL_TEXTURE_2D, gl_tex->gl_id());
|
||||
}
|
||||
|
||||
texture_ids[n] = gl_texture_slot;
|
||||
gl_texture_slot++;
|
||||
}
|
||||
|
||||
gl.Uniform1iv(location, (GLint)uniform.array_length, &texture_ids[0]);
|
||||
renderer->gl.Uniform1iv(location, (GLint)uniform.array_length, &texture_ids[0]);
|
||||
texture_slot++;
|
||||
continue;
|
||||
}
|
||||
@ -1291,37 +1295,37 @@ namespace Blah
|
||||
// Float
|
||||
if (uniform.type == UniformType::Float)
|
||||
{
|
||||
gl.Uniform1fv(location, (GLint)uniform.array_length, data);
|
||||
renderer->gl.Uniform1fv(location, (GLint)uniform.array_length, data);
|
||||
data += uniform.array_length;
|
||||
}
|
||||
// Float2
|
||||
else if (uniform.type == UniformType::Float2)
|
||||
{
|
||||
gl.Uniform2fv(location, (GLint)uniform.array_length, data);
|
||||
renderer->gl.Uniform2fv(location, (GLint)uniform.array_length, data);
|
||||
data += 2 * uniform.array_length;
|
||||
}
|
||||
// Float3
|
||||
else if (uniform.type == UniformType::Float3)
|
||||
{
|
||||
gl.Uniform3fv(location, (GLint)uniform.array_length, data);
|
||||
renderer->gl.Uniform3fv(location, (GLint)uniform.array_length, data);
|
||||
data += 3 * uniform.array_length;
|
||||
}
|
||||
// Float4
|
||||
else if (uniform.type == UniformType::Float4)
|
||||
{
|
||||
gl.Uniform4fv(location, (GLint)uniform.array_length, data);
|
||||
renderer->gl.Uniform4fv(location, (GLint)uniform.array_length, data);
|
||||
data += 4 * uniform.array_length;
|
||||
}
|
||||
// Matrix3x2
|
||||
else if (uniform.type == UniformType::Mat3x2)
|
||||
{
|
||||
gl.UniformMatrix3x2fv(location, (GLint)uniform.array_length, 0, data);
|
||||
renderer->gl.UniformMatrix3x2fv(location, (GLint)uniform.array_length, 0, data);
|
||||
data += 6 * uniform.array_length;
|
||||
}
|
||||
// Matrix4x4
|
||||
else if (uniform.type == UniformType::Mat4x4)
|
||||
{
|
||||
gl.UniformMatrix4fv(location, (GLint)uniform.array_length, 0, data);
|
||||
renderer->gl.UniformMatrix4fv(location, (GLint)uniform.array_length, 0, data);
|
||||
data += 16 * uniform.array_length;
|
||||
}
|
||||
}
|
||||
@ -1336,11 +1340,11 @@ namespace Blah
|
||||
GLenum alphaSrc = gl_get_blend_factor(pass.blend.alpha_src);
|
||||
GLenum alphaDst = gl_get_blend_factor(pass.blend.alpha_dst);
|
||||
|
||||
gl.Enable(GL_BLEND);
|
||||
gl.BlendEquationSeparate(colorOp, alphaOp);
|
||||
gl.BlendFuncSeparate(colorSrc, colorDst, alphaSrc, alphaDst);
|
||||
renderer->gl.Enable(GL_BLEND);
|
||||
renderer->gl.BlendEquationSeparate(colorOp, alphaOp);
|
||||
renderer->gl.BlendFuncSeparate(colorSrc, colorDst, alphaSrc, alphaDst);
|
||||
|
||||
gl.ColorMask(
|
||||
renderer->gl.ColorMask(
|
||||
((int)pass.blend.mask & (int)BlendMask::Red),
|
||||
((int)pass.blend.mask & (int)BlendMask::Green),
|
||||
((int)pass.blend.mask & (int)BlendMask::Blue),
|
||||
@ -1351,7 +1355,7 @@ namespace Blah
|
||||
unsigned char b = pass.blend.rgba >> 8;
|
||||
unsigned char a = pass.blend.rgba;
|
||||
|
||||
gl.BlendColor(
|
||||
renderer->gl.BlendColor(
|
||||
r / 255.0f,
|
||||
g / 255.0f,
|
||||
b / 255.0f,
|
||||
@ -1362,38 +1366,38 @@ namespace Blah
|
||||
{
|
||||
if (pass.depth == Compare::None)
|
||||
{
|
||||
gl.Disable(GL_DEPTH_TEST);
|
||||
renderer->gl.Disable(GL_DEPTH_TEST);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.Enable(GL_DEPTH_TEST);
|
||||
renderer->gl.Enable(GL_DEPTH_TEST);
|
||||
|
||||
switch (pass.depth)
|
||||
{
|
||||
case Compare::None: break;
|
||||
case Compare::Always:
|
||||
gl.DepthFunc(GL_ALWAYS);
|
||||
renderer->gl.DepthFunc(GL_ALWAYS);
|
||||
break;
|
||||
case Compare::Equal:
|
||||
gl.DepthFunc(GL_EQUAL);
|
||||
renderer->gl.DepthFunc(GL_EQUAL);
|
||||
break;
|
||||
case Compare::Greater:
|
||||
gl.DepthFunc(GL_GREATER);
|
||||
renderer->gl.DepthFunc(GL_GREATER);
|
||||
break;
|
||||
case Compare::GreatorOrEqual:
|
||||
gl.DepthFunc(GL_GEQUAL);
|
||||
renderer->gl.DepthFunc(GL_GEQUAL);
|
||||
break;
|
||||
case Compare::Less:
|
||||
gl.DepthFunc(GL_LESS);
|
||||
renderer->gl.DepthFunc(GL_LESS);
|
||||
break;
|
||||
case Compare::LessOrEqual:
|
||||
gl.DepthFunc(GL_LEQUAL);
|
||||
renderer->gl.DepthFunc(GL_LEQUAL);
|
||||
break;
|
||||
case Compare::Never:
|
||||
gl.DepthFunc(GL_NEVER);
|
||||
renderer->gl.DepthFunc(GL_NEVER);
|
||||
break;
|
||||
case Compare::NotEqual:
|
||||
gl.DepthFunc(GL_NOTEQUAL);
|
||||
renderer->gl.DepthFunc(GL_NOTEQUAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1403,18 +1407,18 @@ namespace Blah
|
||||
{
|
||||
if (pass.cull == Cull::None)
|
||||
{
|
||||
gl.Disable(GL_CULL_FACE);
|
||||
renderer->gl.Disable(GL_CULL_FACE);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.Enable(GL_CULL_FACE);
|
||||
renderer->gl.Enable(GL_CULL_FACE);
|
||||
|
||||
if (pass.cull == Cull::Back)
|
||||
gl.CullFace(GL_BACK);
|
||||
renderer->gl.CullFace(GL_BACK);
|
||||
else if (pass.cull == Cull::Front)
|
||||
gl.CullFace(GL_FRONT);
|
||||
renderer->gl.CullFace(GL_FRONT);
|
||||
else
|
||||
gl.CullFace(GL_FRONT_AND_BACK);
|
||||
renderer->gl.CullFace(GL_FRONT_AND_BACK);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1423,14 +1427,14 @@ namespace Blah
|
||||
Rectf viewport = pass.viewport;
|
||||
viewport.y = size.y - viewport.y - viewport.h;
|
||||
|
||||
gl.Viewport((GLint)viewport.x, (GLint)viewport.y, (GLint)viewport.w, (GLint)viewport.h);
|
||||
renderer->gl.Viewport((GLint)viewport.x, (GLint)viewport.y, (GLint)viewport.w, (GLint)viewport.h);
|
||||
}
|
||||
|
||||
// Scissor
|
||||
{
|
||||
if (!pass.has_scissor)
|
||||
{
|
||||
gl.Disable(GL_SCISSOR_TEST);
|
||||
renderer->gl.Disable(GL_SCISSOR_TEST);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1442,21 +1446,21 @@ namespace Blah
|
||||
if (scissor.h < 0)
|
||||
scissor.h = 0;
|
||||
|
||||
gl.Enable(GL_SCISSOR_TEST);
|
||||
gl.Scissor((GLint)scissor.x, (GLint)scissor.y, (GLint)scissor.w, (GLint)scissor.h);
|
||||
renderer->gl.Enable(GL_SCISSOR_TEST);
|
||||
renderer->gl.Scissor((GLint)scissor.x, (GLint)scissor.y, (GLint)scissor.w, (GLint)scissor.h);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the Mesh
|
||||
{
|
||||
gl.BindVertexArray(mesh->gl_id());
|
||||
renderer->gl.BindVertexArray(mesh->gl_id());
|
||||
|
||||
GLenum index_format = mesh->gl_index_format();
|
||||
int index_size = mesh->gl_index_size();
|
||||
|
||||
if (pass.instance_count > 0)
|
||||
{
|
||||
gl.DrawElementsInstanced(
|
||||
renderer->gl.DrawElementsInstanced(
|
||||
GL_TRIANGLES,
|
||||
(GLint)(pass.index_count),
|
||||
index_format,
|
||||
@ -1465,18 +1469,18 @@ namespace Blah
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.DrawElements(
|
||||
renderer->gl.DrawElements(
|
||||
GL_TRIANGLES,
|
||||
(GLint)(pass.index_count),
|
||||
index_format,
|
||||
(void*)(index_size * pass.index_start));
|
||||
}
|
||||
|
||||
gl.BindVertexArray(0);
|
||||
renderer->gl.BindVertexArray(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask)
|
||||
void Renderer_OpenGL::clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask)
|
||||
{
|
||||
int clear = 0;
|
||||
|
||||
@ -1487,14 +1491,28 @@ namespace Blah
|
||||
if (((int)mask & (int)ClearMask::Stencil) == (int)ClearMask::Stencil)
|
||||
clear |= GL_STENCIL_BUFFER_BIT;
|
||||
|
||||
gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
gl.Disable(GL_SCISSOR_TEST);
|
||||
gl.ColorMask(true, true, true, true);
|
||||
gl.ClearColor(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f);
|
||||
gl.ClearDepth(depth);
|
||||
gl.ClearStencil(stencil);
|
||||
gl.Clear(clear);
|
||||
renderer->gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
renderer->gl.Disable(GL_SCISSOR_TEST);
|
||||
renderer->gl.ColorMask(true, true, true, true);
|
||||
renderer->gl.ClearColor(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f);
|
||||
renderer->gl.ClearDepth(depth);
|
||||
renderer->gl.ClearStencil(stencil);
|
||||
renderer->gl.Clear(clear);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BLAH_GRAPHICS_OPENGL
|
||||
Blah::Renderer* Blah::Renderer::try_make_opengl()
|
||||
{
|
||||
return new Blah::Renderer_OpenGL();
|
||||
}
|
||||
|
||||
#else // BLAH_RENDERER_OPENGL
|
||||
|
||||
#include "renderer.h"
|
||||
Blah::Renderer* Blah::Renderer::try_make_opengl()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user