Merge pull request #21 from audetto/sdlimgui
Integrate Dear ImGui as a renderer over SDL2
This commit is contained in:
commit
f3d5cb3f10
18 changed files with 505 additions and 72 deletions
|
@ -28,3 +28,4 @@ matrix:
|
|||
- libevdev-dev
|
||||
- libsdl2-dev
|
||||
- libsdl2-image-dev
|
||||
- libgles-dev
|
||||
|
|
|
@ -24,6 +24,7 @@ bool getEmulatorOptions(int argc, const char * argv [], const std::string & edit
|
|||
("multi-threaded,m", "Multi threaded")
|
||||
("loose-mutex,l", "Loose mutex")
|
||||
("sdl-driver", po::value<int>()->default_value(options.sdlDriver), "SDL driver")
|
||||
("imgui", "Render with Dear ImGui")
|
||||
("timer-interval,i", po::value<int>()->default_value(options.timerInterval), "Timer interval in ms");
|
||||
|
||||
po::options_description configDesc("configuration");
|
||||
|
@ -82,6 +83,7 @@ bool getEmulatorOptions(int argc, const char * argv [], const std::string & edit
|
|||
options.looseMutex = vm.count("loose-mutex");
|
||||
options.timerInterval = vm["timer-interval"].as<int>();
|
||||
options.sdlDriver = vm["sdl-driver"].as<int>();
|
||||
options.imgui = vm.count("imgui");
|
||||
|
||||
if (vm.count("config"))
|
||||
{
|
||||
|
|
|
@ -36,6 +36,7 @@ struct EmulatorOptions
|
|||
bool fixedSpeed = false; // default adaptive
|
||||
|
||||
int sdlDriver = -1; // default = -1 to let SDL choose
|
||||
bool imgui = false; // use imgui renderer
|
||||
|
||||
std::vector<std::string> registryOptions;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
include(FindPkgConfig)
|
||||
|
||||
add_executable(sa2)
|
||||
|
||||
set(SOURCE_FILES
|
||||
main.cpp
|
||||
emulator.cpp
|
||||
|
@ -7,6 +9,7 @@ set(SOURCE_FILES
|
|||
sdirectsound.cpp
|
||||
utils.cpp
|
||||
sdlframe.cpp
|
||||
renderer/sdlrendererframe.cpp
|
||||
)
|
||||
|
||||
set(HEADER_FILES
|
||||
|
@ -15,11 +18,7 @@ set(HEADER_FILES
|
|||
sdirectsound.h
|
||||
utils.h
|
||||
sdlframe.h
|
||||
)
|
||||
|
||||
add_executable(sa2
|
||||
${SOURCE_FILES}
|
||||
${HEADER_FILES}
|
||||
renderer/sdlrendererframe.h
|
||||
)
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
|
@ -39,5 +38,52 @@ target_link_libraries(sa2 PRIVATE
|
|||
common2
|
||||
)
|
||||
|
||||
target_sources(sa2 PRIVATE
|
||||
${SOURCE_FILES}
|
||||
${HEADER_FILES}
|
||||
)
|
||||
|
||||
set(IMGUI_PATH NONE CACHE PATH "path to imgui")
|
||||
|
||||
if (EXISTS ${IMGUI_PATH}/imgui.h)
|
||||
message("Using IMGUI_PATH=${IMGUI_PATH}")
|
||||
|
||||
pkg_search_module(GLES2 REQUIRED glesv2)
|
||||
|
||||
target_sources(sa2 PRIVATE
|
||||
imgui/sdlimguiframe.cpp
|
||||
imgui/image.cpp
|
||||
imgui/imconfig.h
|
||||
imgui/gles.h
|
||||
imgui/image.h
|
||||
imgui/sdlimguiframe.h
|
||||
${IMGUI_PATH}/imgui.cpp
|
||||
${IMGUI_PATH}/imgui_demo.cpp
|
||||
${IMGUI_PATH}/imgui_draw.cpp
|
||||
${IMGUI_PATH}/imgui_tables.cpp
|
||||
${IMGUI_PATH}/imgui_widgets.cpp
|
||||
${IMGUI_PATH}/backends/imgui_impl_sdl.cpp
|
||||
${IMGUI_PATH}/backends/imgui_impl_opengl3.cpp
|
||||
)
|
||||
|
||||
target_include_directories(sa2 PRIVATE
|
||||
${IMGUI_PATH}
|
||||
${IMGUI_PATH}/backends
|
||||
)
|
||||
|
||||
target_link_libraries(sa2 PRIVATE
|
||||
${GLES2_LIBRARIES}
|
||||
)
|
||||
|
||||
target_compile_definitions(sa2 PRIVATE
|
||||
SA2_IMGUI
|
||||
IMGUI_IMPL_OPENGL_ES2
|
||||
IMGUI_USER_CONFIG="frontends/sdl/imgui/imconfig.h"
|
||||
)
|
||||
else()
|
||||
message("Bad IMGUI_PATH=${IMGUI_PATH}, skipping imgui code")
|
||||
endif()
|
||||
|
||||
|
||||
install(TARGETS sa2
|
||||
DESTINATION bin)
|
||||
|
|
|
@ -19,6 +19,14 @@ It is possible to run the CPU in a separate thread to keep the emulator running
|
|||
- ``sa2 -m``
|
||||
- optionally add ``-l``
|
||||
|
||||
## Dear ImGui
|
||||
|
||||
Rendering with [Dear ImGui](https://github.com/ocornut/imgui) is possible, although no fancy features are used.
|
||||
|
||||
Must be configured in ``cmake`` via the external path ``IMGUI_PATH``, and enabled at runtime with ``--imgui``. It requires a working OpenGL ES2.0 implementation (works on Pi3 and Pi4).
|
||||
|
||||
Output mentions the Dear ImGui version, e.g.: ``IMGUI_VERSION: 1.81 WIP``.
|
||||
|
||||
## Hotkeys
|
||||
|
||||
``F2``, ``F5``, ``F6``, ``F9``, ``F11``, ``F12`` and ``Pause`` have the same meaning as in AppleWin.
|
||||
|
|
33
source/frontends/sdl/imgui/gles.h
Normal file
33
source/frontends/sdl/imgui/gles.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
|
||||
// Pi3 with Fake KMS
|
||||
// "OpenGL ES 2.0 Mesa 19.3.2"
|
||||
// "Supported versions are: 1.00 ES"
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
#define SDL_CONTEXT_MAJOR 2
|
||||
|
||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
|
||||
// Pi4 with Fake KMS
|
||||
// "OpenGL ES 3.1 Mesa 19.3.2"
|
||||
// "Supported versions are: 1.00 ES, 3.00 ES, and 3.10 ES"
|
||||
|
||||
// On my desktop
|
||||
// "OpenGL ES 3.1 Mesa 20.2.6"
|
||||
// "Supported versions are: 1.00 ES, 3.00 ES, and 3.10 ES"
|
||||
|
||||
#include <GLES3/gl3.h>
|
||||
#define SDL_CONTEXT_MAJOR 3
|
||||
// "310 es" is accepted on a Pi4, but the imgui shaders do not compile
|
||||
|
||||
#endif
|
||||
|
||||
// this is used in all cases for GL_BGRA_EXT
|
||||
#include <GLES2/gl2ext.h>
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include "imgui_impl_opengl3.h"
|
43
source/frontends/sdl/imgui/image.cpp
Normal file
43
source/frontends/sdl/imgui/image.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "frontends/sdl/imgui/image.h"
|
||||
|
||||
#ifdef GL_UNPACK_ROW_LENGTH
|
||||
// GLES3: defined in gl3.h
|
||||
#define UGL_UNPACK_LENGTH GL_UNPACK_ROW_LENGTH
|
||||
#else
|
||||
// GLES2: defined in gl2ext.h as an extension GL_EXT_unpack_subimage
|
||||
#define UGL_UNPACK_LENGTH GL_UNPACK_ROW_LENGTH_EXT
|
||||
#endif
|
||||
|
||||
/*
|
||||
2 extensions are used here
|
||||
|
||||
ES2: GL_UNPACK_ROW_LENGTH_EXT and GL_BGRA_EXT
|
||||
ES3: GL_BGRA_EXT
|
||||
|
||||
They both work on Pi3/4 and my Intel Haswell card.
|
||||
|
||||
What does SDL do about it?
|
||||
|
||||
GL_UNPACK_ROW_LENGTH_EXT: it uses instead texture coordinates
|
||||
GL_BGRA_EXT: it uses a shader to swap the color bytes
|
||||
|
||||
For simplicity (and because it just works) here we are using these 2 extensions.
|
||||
*/
|
||||
|
||||
void LoadTextureFromData(GLuint texture, const uint8_t * data, size_t width, size_t height, size_t pitch)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glPixelStorei(UGL_UNPACK_LENGTH, pitch); // in pixels
|
||||
|
||||
// Setup filtering parameters for display
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
const GLenum format = GL_BGRA_EXT; // this is defined in gl2ext.h and nowhere in gl3.h
|
||||
const GLenum type = GL_UNSIGNED_BYTE;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
|
||||
// reset to default state
|
||||
glPixelStorei(UGL_UNPACK_LENGTH, 0);
|
||||
}
|
6
source/frontends/sdl/imgui/image.h
Normal file
6
source/frontends/sdl/imgui/image.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include "frontends/sdl/imgui/gles.h"
|
||||
|
||||
void LoadTextureFromData(GLuint texture, const uint8_t * data, size_t width, size_t height, size_t pitch);
|
121
source/frontends/sdl/imgui/imconfig.h
Normal file
121
source/frontends/sdl/imgui/imconfig.h
Normal file
|
@ -0,0 +1,121 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||
//-----------------------------------------------------------------------------
|
||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows.
|
||||
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
|
||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
|
||||
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty.
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow.
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||
//#define IMGUI_USE_WCHAR32
|
||||
|
||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
|
||||
//---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||
// Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf.
|
||||
// #define IMGUI_USE_STB_SPRINTF
|
||||
|
||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
|
||||
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
//#define ImDrawIdx unsigned int
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
//struct ImDrawCmd;
|
||||
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||
//#define ImDrawCallback MyImDrawCallback
|
||||
|
||||
//---- Debug Tools: Macro to break in Debugger
|
||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||
//#define IM_DEBUG_BREAK __debugbreak()
|
||||
|
||||
//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(),
|
||||
// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.)
|
||||
// This adds a small runtime cost which is why it is not enabled by default.
|
||||
//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
|
||||
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
//#define IMGUI_DEBUG_PARANOID
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, const MyMatrix44& v);
|
||||
}
|
||||
*/
|
||||
|
||||
// can't easily use GLunit here (defines in gl2/3.h)
|
||||
#define ImTextureID unsigned int
|
105
source/frontends/sdl/imgui/sdlimguiframe.cpp
Normal file
105
source/frontends/sdl/imgui/sdlimguiframe.cpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
#include "StdAfx.h"
|
||||
#include "frontends/sdl/imgui/sdlimguiframe.h"
|
||||
#include "frontends/sdl/imgui/image.h"
|
||||
#include "frontends/sdl/utils.h"
|
||||
|
||||
#include "Interface.h"
|
||||
#include "Core.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
SDLImGuiFrame::SDLImGuiFrame()
|
||||
{
|
||||
Video & video = GetVideo();
|
||||
|
||||
myBorderlessWidth = video.GetFrameBufferBorderlessWidth();
|
||||
myBorderlessHeight = video.GetFrameBufferBorderlessHeight();
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, SDL_CONTEXT_MAJOR); // from local gles.h
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
|
||||
// Create window with graphics context
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
|
||||
SDL_WindowFlags windowFlags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||
myWindow.reset(SDL_CreateWindow(g_pAppTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, myBorderlessWidth, myBorderlessHeight, windowFlags), SDL_DestroyWindow);
|
||||
if (!myWindow)
|
||||
{
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
}
|
||||
|
||||
myGLContext = SDL_GL_CreateContext(myWindow.get());
|
||||
if (!myGLContext)
|
||||
{
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
}
|
||||
|
||||
SDL_GL_MakeCurrent(myWindow.get(), myGLContext);
|
||||
|
||||
// Setup Platform/Renderer backends
|
||||
std::cerr << "IMGUI_VERSION: " << IMGUI_VERSION << std::endl;
|
||||
std::cerr << "GL_VENDOR: " << glGetString(GL_VENDOR) << std::endl;
|
||||
std::cerr << "GL_RENDERER: " << glGetString(GL_RENDERER) << std::endl;
|
||||
std::cerr << "GL_VERSION: " << glGetString(GL_VERSION) << std::endl;
|
||||
std::cerr << "GL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
|
||||
// const char* runtime_gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
|
||||
// std::cerr << "GL_EXTENSIONS: " << runtime_gl_extensions << std::endl;
|
||||
|
||||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
ImGui_ImplSDL2_InitForOpenGL(myWindow.get(), myGLContext);
|
||||
|
||||
ImGui_ImplOpenGL3_Init();
|
||||
|
||||
glGenTextures(1, &myTexture);
|
||||
|
||||
const int width = video.GetFrameBufferWidth();
|
||||
const size_t borderWidth = video.GetFrameBufferBorderWidth();
|
||||
const size_t borderHeight = video.GetFrameBufferBorderHeight();
|
||||
|
||||
myPitch = width;
|
||||
myOffset = (width * borderHeight + borderWidth) * sizeof(bgra_t);
|
||||
}
|
||||
|
||||
SDLImGuiFrame::~SDLImGuiFrame()
|
||||
{
|
||||
glDeleteTextures(1, &myTexture);
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
SDL_GL_DeleteContext(myGLContext);
|
||||
}
|
||||
|
||||
void SDLImGuiFrame::UpdateTexture()
|
||||
{
|
||||
LoadTextureFromData(myTexture, myFramebuffer.data() + myOffset, myBorderlessWidth, myBorderlessHeight, myPitch);
|
||||
}
|
||||
|
||||
void SDLImGuiFrame::RenderPresent()
|
||||
{
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame(myWindow.get());
|
||||
ImGui::NewFrame();
|
||||
|
||||
// need to flip the texture vertically
|
||||
const ImVec2 uv0(0, 1);
|
||||
const ImVec2 uv1(1, 0);
|
||||
const ImVec2 zero(0, 0);
|
||||
// draw on the background
|
||||
ImGui::GetBackgroundDrawList()->AddImage(myTexture, zero, ImGui::GetIO().DisplaySize, uv0, uv1);
|
||||
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
SDL_GL_SwapWindow(myWindow.get());
|
||||
}
|
24
source/frontends/sdl/imgui/sdlimguiframe.h
Normal file
24
source/frontends/sdl/imgui/sdlimguiframe.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "frontends/sdl/sdlframe.h"
|
||||
#include "frontends/sdl/imgui/gles.h"
|
||||
|
||||
class SDLImGuiFrame : public SDLFrame
|
||||
{
|
||||
public:
|
||||
SDLImGuiFrame();
|
||||
|
||||
~SDLImGuiFrame() override;
|
||||
|
||||
void UpdateTexture() override;
|
||||
void RenderPresent() override;
|
||||
|
||||
private:
|
||||
size_t myPitch;
|
||||
size_t myOffset;
|
||||
size_t myBorderlessWidth;
|
||||
size_t myBorderlessHeight;
|
||||
|
||||
SDL_GLContext myGLContext;
|
||||
ImTextureID myTexture;
|
||||
};
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <iomanip>
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "linux/interface.h"
|
||||
|
@ -16,7 +17,12 @@
|
|||
#include "frontends/sdl/gamepad.h"
|
||||
#include "frontends/sdl/sdirectsound.h"
|
||||
#include "frontends/sdl/utils.h"
|
||||
#include "frontends/sdl/sdlframe.h"
|
||||
|
||||
#include "frontends/sdl/renderer/sdlrendererframe.h"
|
||||
|
||||
#ifdef SA2_IMGUI
|
||||
#include "frontends/sdl/imgui/sdlimguiframe.h"
|
||||
#endif
|
||||
|
||||
#include "Core.h"
|
||||
#include "Log.h"
|
||||
|
@ -69,6 +75,8 @@ namespace
|
|||
|
||||
void run_sdl(int argc, const char * argv [])
|
||||
{
|
||||
std::cerr << std::fixed << std::setprecision(2);
|
||||
|
||||
EmulatorOptions options;
|
||||
options.memclear = g_nMemoryClearType;
|
||||
const bool run = getEmulatorOptions(argc, argv, "SDL2", options);
|
||||
|
@ -76,7 +84,21 @@ void run_sdl(int argc, const char * argv [])
|
|||
if (!run)
|
||||
return;
|
||||
|
||||
const std::shared_ptr<SDLFrame> frame(new SDLFrame(options));
|
||||
std::shared_ptr<SDLFrame> frame;
|
||||
|
||||
#ifdef SA2_IMGUI
|
||||
if (options.imgui)
|
||||
{
|
||||
frame.reset(new SDLImGuiFrame());
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.reset(new SDLRendererFrame(options));
|
||||
}
|
||||
#else
|
||||
frame.reset(new SDLRendererFrame(options));
|
||||
#endif
|
||||
|
||||
SetFrame(frame);
|
||||
|
||||
if (options.log)
|
||||
|
|
55
source/frontends/sdl/renderer/sdlrendererframe.cpp
Normal file
55
source/frontends/sdl/renderer/sdlrendererframe.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include "StdAfx.h"
|
||||
#include "frontends/sdl/renderer/sdlrendererframe.h"
|
||||
#include "frontends/sdl/utils.h"
|
||||
#include "frontends/common2/programoptions.h"
|
||||
|
||||
#include "Interface.h"
|
||||
#include "Core.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
SDLRendererFrame::SDLRendererFrame(const EmulatorOptions & options)
|
||||
{
|
||||
Video & video = GetVideo();
|
||||
|
||||
const int width = video.GetFrameBufferWidth();
|
||||
const int height = video.GetFrameBufferHeight();
|
||||
const int sw = video.GetFrameBufferBorderlessWidth();
|
||||
const int sh = video.GetFrameBufferBorderlessHeight();
|
||||
|
||||
myWindow.reset(SDL_CreateWindow(g_pAppTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sw, sh, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE), SDL_DestroyWindow);
|
||||
if (!myWindow)
|
||||
{
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
}
|
||||
|
||||
SetApplicationIcon();
|
||||
|
||||
myRenderer.reset(SDL_CreateRenderer(myWindow.get(), options.sdlDriver, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), SDL_DestroyRenderer);
|
||||
if (!myRenderer)
|
||||
{
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
}
|
||||
|
||||
const Uint32 format = SDL_PIXELFORMAT_ARGB8888;
|
||||
printRendererInfo(std::cerr, myRenderer, format, options.sdlDriver);
|
||||
|
||||
myTexture.reset(SDL_CreateTexture(myRenderer.get(), format, SDL_TEXTUREACCESS_STATIC, width, height), SDL_DestroyTexture);
|
||||
|
||||
myRect.x = video.GetFrameBufferBorderWidth();
|
||||
myRect.y = video.GetFrameBufferBorderHeight();
|
||||
myRect.w = sw;
|
||||
myRect.h = sw;
|
||||
myPitch = width * sizeof(bgra_t);
|
||||
}
|
||||
|
||||
void SDLRendererFrame::UpdateTexture()
|
||||
{
|
||||
SDL_UpdateTexture(myTexture.get(), nullptr, myFramebuffer.data(), myPitch);
|
||||
}
|
||||
|
||||
void SDLRendererFrame::RenderPresent()
|
||||
{
|
||||
SDL_RenderCopyEx(myRenderer.get(), myTexture.get(), &myRect, nullptr, 0.0, nullptr, SDL_FLIP_VERTICAL);
|
||||
SDL_RenderPresent(myRenderer.get());
|
||||
}
|
21
source/frontends/sdl/renderer/sdlrendererframe.h
Normal file
21
source/frontends/sdl/renderer/sdlrendererframe.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "frontends/sdl/sdlframe.h"
|
||||
|
||||
class EmulatorOptions;
|
||||
|
||||
class SDLRendererFrame : public SDLFrame
|
||||
{
|
||||
public:
|
||||
SDLRendererFrame(const EmulatorOptions & options);
|
||||
|
||||
void UpdateTexture() override;
|
||||
void RenderPresent() override;
|
||||
|
||||
private:
|
||||
SDL_Rect myRect;
|
||||
int myPitch;
|
||||
|
||||
std::shared_ptr<SDL_Renderer> myRenderer;
|
||||
std::shared_ptr<SDL_Texture> myTexture;
|
||||
};
|
|
@ -1,56 +1,16 @@
|
|||
#include "StdAfx.h"
|
||||
#include "frontends/sdl/sdlframe.h"
|
||||
#include "frontends/sdl/utils.h"
|
||||
#include "frontends/common2/programoptions.h"
|
||||
|
||||
#include "Interface.h"
|
||||
#include "Core.h"
|
||||
#include "Utilities.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
|
||||
#include <SDL_image.h>
|
||||
|
||||
SDLFrame::SDLFrame(const EmulatorOptions & options)
|
||||
SDLFrame::SDLFrame()
|
||||
{
|
||||
Video & video = GetVideo();
|
||||
|
||||
const int width = video.GetFrameBufferWidth();
|
||||
const int height = video.GetFrameBufferHeight();
|
||||
const int sw = video.GetFrameBufferBorderlessWidth();
|
||||
const int sh = video.GetFrameBufferBorderlessHeight();
|
||||
|
||||
std::cerr << std::fixed << std::setprecision(2);
|
||||
|
||||
myWindow.reset(SDL_CreateWindow(g_pAppTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sw, sh, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE), SDL_DestroyWindow);
|
||||
if (!myWindow)
|
||||
{
|
||||
std::cerr << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
SetApplicationIcon();
|
||||
|
||||
myRenderer.reset(SDL_CreateRenderer(myWindow.get(), options.sdlDriver, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), SDL_DestroyRenderer);
|
||||
if (!myRenderer)
|
||||
{
|
||||
std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
const Uint32 format = SDL_PIXELFORMAT_ARGB8888;
|
||||
printRendererInfo(std::cerr, myRenderer, format, options.sdlDriver);
|
||||
|
||||
myTexture.reset(SDL_CreateTexture(myRenderer.get(), format, SDL_TEXTUREACCESS_STATIC, width, height), SDL_DestroyTexture);
|
||||
|
||||
myRect.x = video.GetFrameBufferBorderWidth();
|
||||
myRect.y = video.GetFrameBufferBorderHeight();
|
||||
myRect.w = video.GetFrameBufferBorderlessWidth();
|
||||
myRect.h = video.GetFrameBufferBorderlessHeight();
|
||||
myPitch = video.GetFrameBufferWidth() * sizeof(bgra_t);
|
||||
}
|
||||
|
||||
void SDLFrame::FrameRefreshStatus(int drawflags)
|
||||
|
@ -72,17 +32,6 @@ void SDLFrame::SetApplicationIcon()
|
|||
}
|
||||
}
|
||||
|
||||
void SDLFrame::UpdateTexture()
|
||||
{
|
||||
SDL_UpdateTexture(myTexture.get(), nullptr, myFramebuffer.data(), myPitch);
|
||||
}
|
||||
|
||||
void SDLFrame::RenderPresent()
|
||||
{
|
||||
SDL_RenderCopyEx(myRenderer.get(), myTexture.get(), &myRect, nullptr, 0.0, nullptr, SDL_FLIP_VERTICAL);
|
||||
SDL_RenderPresent(myRenderer.get());
|
||||
}
|
||||
|
||||
void SDLFrame::VideoPresentScreen()
|
||||
{
|
||||
UpdateTexture();
|
||||
|
|
|
@ -3,30 +3,23 @@
|
|||
#include "frontends/common2/commonframe.h"
|
||||
#include <SDL.h>
|
||||
|
||||
class EmulatorOptions;
|
||||
|
||||
class SDLFrame : public CommonFrame
|
||||
{
|
||||
public:
|
||||
SDLFrame(const EmulatorOptions & options);
|
||||
SDLFrame();
|
||||
|
||||
void VideoPresentScreen() override;
|
||||
void FrameRefreshStatus(int drawflags) override;
|
||||
int FrameMessageBox(LPCSTR lpText, LPCSTR lpCaption, UINT uType) override;
|
||||
void GetBitmap(LPCSTR lpBitmapName, LONG cb, LPVOID lpvBits) override;
|
||||
|
||||
void UpdateTexture();
|
||||
void RenderPresent();
|
||||
virtual void UpdateTexture() = 0;
|
||||
virtual void RenderPresent() = 0;
|
||||
|
||||
const std::shared_ptr<SDL_Window> & GetWindow() const;
|
||||
|
||||
private:
|
||||
protected:
|
||||
void SetApplicationIcon();
|
||||
|
||||
SDL_Rect myRect;
|
||||
int myPitch;
|
||||
|
||||
std::shared_ptr<SDL_Window> myWindow;
|
||||
std::shared_ptr<SDL_Renderer> myRenderer;
|
||||
std::shared_ptr<SDL_Texture> myTexture;
|
||||
};
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
set -euxo pipefail
|
||||
|
||||
wget https://raw.githubusercontent.com/libretro/RetroArch/master/libretro-common/include/libretro.h -P build/libretro-common/include
|
||||
wget https://raw.githubusercontent.com/libretro/RetroArch/master/libretro-common/include/libretro.h -P libretro-common/include
|
||||
|
||||
git clone --depth=1 https://github.com/ocornut/imgui.git
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE=RELEASE -DLIBRETRO_COMMON_PATH=libretro-common ..
|
||||
cmake -DCMAKE_BUILD_TYPE=RELEASE -DLIBRETRO_COMMON_PATH=../libretro-common -DIMGUI_PATH=../imgui ..
|
||||
make
|
||||
|
|
|
@ -10,3 +10,4 @@ libncurses-dev
|
|||
libevdev-dev
|
||||
libsdl2-image-dev
|
||||
libsdl2-dev
|
||||
libgles-dev
|
||||
|
|
Loading…
Add table
Reference in a new issue