initial ui work

This commit is contained in:
Anthony Pesch 2017-10-05 22:27:44 -04:00
parent 47b600e2da
commit ce86c18abf
24 changed files with 44543 additions and 108 deletions

View File

@ -119,6 +119,9 @@ if(ARCH_X64)
list(APPEND RELIB_INCLUDES deps/xbyak)
endif()
# zlib, reused from libchdr
list(APPEND RELIB_INCLUDES deps/chdr/deps/zlib-1.2.11)
#--------------------------------------------------
# optional libs
#--------------------------------------------------
@ -245,7 +248,6 @@ set(RELIB_SOURCES
src/jit/jit.c
src/jit/pass_stats.c
src/render/gl_backend.c
src/imgui.cc
src/options.c
src/stats.c)
@ -345,14 +347,21 @@ endif()
#--------------------------------------------------
if(BUILD_LIBRETRO)
set(REDREAM_SOURCES ${RELIB_SOURCES} src/host/retro_host.c src/emulator.c)
set(REDREAM_SOURCES ${RELIB_SOURCES}
src/host/retro_host.c
src/emulator.c)
set(REDREAM_INCLUDES ${RELIB_INCLUDES} deps/libretro/include)
set(REDREAM_LIBS ${RELIB_LIBS})
set(REDREAM_DEFS ${RELIB_DEFS})
set(REDREAM_FLAGS ${RELIB_FLAGS})
else()
set(REDREAM_SOURCES ${RELIB_SOURCES} src/host/sdl_host.c src/emulator.c src/tracer.c)
set(REDREAM_INCLUDES ${RELIB_INCLUDES})
set(REDREAM_SOURCES ${RELIB_SOURCES}
src/host/sdl_host.c
src/emulator.c
src/imgui.cc
src/tracer.c
src/ui.c)
set(REDREAM_INCLUDES ${RELIB_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR})
set(REDREAM_LIBS ${RELIB_LIBS} ${IMGUI_LIBS} ${SDL_LIBS})
set(REDREAM_DEFS ${RELIB_DEFS} HAVE_GDBSERVER HAVE_IMGUI)
set(REDREAM_FLAGS ${RELIB_FLAGS})

18
assets/README.md Normal file
View File

@ -0,0 +1,18 @@
All of the assets here are compressed with zlib and #include'd as code in the project.
For png files, the data is first converted into raw rgb / rgba data with GraphicMagick:
```
gm convert image.png image.rgb
```
The data is then compressed with:
```
openssl zlib -e < image.rgb > image.gz
```
The data is finally transformed into a C-style array with:
```
xxd -i image.gz
```
Note, the width, height and uncompressed sizes are all filled in manually alongside the xxd output.

19548
assets/clouds.inc Normal file

File diff suppressed because it is too large Load Diff

BIN
assets/clouds.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

1222
assets/disc.inc Normal file

File diff suppressed because it is too large Load Diff

BIN
assets/disc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

9491
assets/opensans-regular.inc Normal file

File diff suppressed because it is too large Load Diff

BIN
assets/opensans-regular.ttf Normal file

Binary file not shown.

3916
assets/oswald-medium.inc Normal file

File diff suppressed because it is too large Load Diff

BIN
assets/oswald-medium.ttf Normal file

Binary file not shown.

View File

@ -84,7 +84,7 @@ SOURCES_C := $(CORE_DIR)/src/core/assert.c \
$(CORE_DIR)/src/options.c \
$(CORE_DIR)/src/stats.c
SOURCES_CXX := $(CORE_DIR)/src/imgui.cc
SOURCES_CXX :=
SOURCES_CPP :=

View File

@ -33,9 +33,11 @@ const char *fs_appdir();
void fs_set_appdir(const char *path);
int fs_userdir(char *userdir, size_t size);
int fs_mediadirs(char *dirs, int num, size_t size);
void fs_dirname(const char *path, char *dir, size_t size);
void fs_basename(const char *path, char *base, size_t size);
void fs_realpath(const char *path, char *resolved, size_t size);
int fs_exists(const char *path);
int fs_isdir(const char *path);

View File

@ -4,8 +4,111 @@
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "core/core.h"
#include "core/filesystem.h"
int fs_mkdir(const char *path) {
int res = mkdir(path, 0755);
return res == 0 || errno == EEXIST;
}
int fs_isfile(const char *path) {
struct stat buffer;
if (stat(path, &buffer) != 0) {
return 0;
}
return (buffer.st_mode & S_IFREG) == S_IFREG;
}
int fs_isdir(const char *path) {
struct stat buffer;
if (stat(path, &buffer) != 0) {
return 0;
}
return (buffer.st_mode & S_IFDIR) == S_IFDIR;
}
int fs_exists(const char *path) {
struct stat buffer;
return stat(path, &buffer) == 0;
}
void fs_realpath(const char *path, char *resolved, size_t size) {
char tmp[PATH_MAX];
if (realpath(path, tmp)) {
strncpy(resolved, tmp, size);
} else {
strncpy(resolved, path, size);
}
}
int fs_mediadirs(char *dirs, int num, size_t size) {
char *ptr = dirs;
char *end = dirs + size * num;
/* search in the home directory */
static const char *home_search[] = {"Desktop", "Documents", "Downloads",
"Music", "Pictures", "Videos"};
char home[PATH_MAX];
int res = fs_userdir(home, sizeof(home));
if (res) {
for (int i = 0; i < ARRAY_SIZE(home_search); i++) {
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s" PATH_SEPARATOR "%s", home,
home_search[i]);
if (!fs_isdir(path)) {
continue;
}
if (ptr < end) {
strncpy(ptr, path, size);
ptr += size;
}
}
}
/* search for additional mounts */
const char *mnt_search[] = {
#if PLATFORM_DARWIN
"/Volumes",
#else
"/media",
"/mnt"
#endif
};
for (int i = 0; i < ARRAY_SIZE(mnt_search); i++) {
const char *path = mnt_search[i];
DIR *dir = opendir(path);
if (!dir) {
continue;
}
struct dirent *ent = NULL;
while ((ent = readdir(dir)) != NULL) {
const char *dname = ent->d_name;
/* ignore special directories */
if (!strcmp(dname, "..") || !strcmp(dname, ".")) {
continue;
}
if (ptr < end) {
snprintf(ptr, size, "%s" PATH_SEPARATOR "%s", path, dname);
ptr += size;
}
}
closedir(dir);
}
return (ptr - dirs) / size;
}
int fs_userdir(char *userdir, size_t size) {
const char *home = getenv("HOME");
@ -22,29 +125,3 @@ int fs_userdir(char *userdir, size_t size) {
return 0;
}
int fs_exists(const char *path) {
struct stat buffer;
return stat(path, &buffer) == 0;
}
int fs_isdir(const char *path) {
struct stat buffer;
if (stat(path, &buffer) != 0) {
return 0;
}
return (buffer.st_mode & S_IFDIR) == S_IFDIR;
}
int fs_isfile(const char *path) {
struct stat buffer;
if (stat(path, &buffer) != 0) {
return 0;
}
return (buffer.st_mode & S_IFREG) == S_IFREG;
}
int fs_mkdir(const char *path) {
int res = mkdir(path, 0755);
return res == 0 || errno == EEXIST;
}

View File

@ -1,3 +1,4 @@
#include <Windows.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@ -5,6 +6,61 @@
#include <userenv.h>
#include "core/filesystem.h"
int fs_mkdir(const char *path) {
int res = _mkdir(path);
return res == 0 || errno == EEXIST;
}
int fs_isfile(const char *path) {
struct _stat buffer;
if (_stat(path, &buffer) != 0) {
return 0;
}
return (buffer.st_mode & S_IFREG) == S_IFREG;
}
int fs_isdir(const char *path) {
struct _stat buffer;
if (_stat(path, &buffer) != 0) {
return 0;
}
return (buffer.st_mode & S_IFDIR) == S_IFDIR;
}
int fs_exists(const char *path) {
struct _stat buffer;
return _stat(path, &buffer) == 0;
}
void fs_realpath(const char *path, char *resolved, size_t size) {
if (!_fullpath(resolved, path, size)) {
strncpy(resolved, path, size);
}
}
int fs_mediadirs(char *dirs, int num, size_t size) {
char *ptr = dirs;
char *end = dirs + size * num;
char path[PATH_MAX];
DWORD drives = GetLogicalDrives();
int max_drives = (int)sizeof(drives) * 8;
for (int i = 0; i < max_drives; i++) {
if (!(drives & (1 << i))) {
continue;
}
if (ptr < end) {
snprintf(path, sizeof(path), "%c:" PATH_SEPARATOR, 'A' + i);
strncpy(ptr, path, size);
ptr += size;
}
}
return 1;
}
int fs_userdir(char *userdir, size_t size) {
HANDLE accessToken = NULL;
HANDLE processHandle = GetCurrentProcess();
@ -20,29 +76,3 @@ int fs_userdir(char *userdir, size_t size) {
CloseHandle(accessToken);
return 1;
}
int fs_exists(const char *path) {
struct _stat buffer;
return _stat(path, &buffer) == 0;
}
int fs_isdir(const char *path) {
struct _stat buffer;
if (_stat(path, &buffer) != 0) {
return 0;
}
return (buffer.st_mode & S_IFDIR) == S_IFDIR;
}
int fs_isfile(const char *path) {
struct _stat buffer;
if (_stat(path, &buffer) != 0) {
return 0;
}
return (buffer.st_mode & S_IFREG) == S_IFREG;
}
int fs_mkdir(const char *path) {
int res = _mkdir(path);
return res == 0 || errno == EEXIST;
}

View File

@ -11,5 +11,12 @@ void audio_push(struct host *host, const int16_t *data, int frames);
/* video */
/* input */
int input_max_controllers(struct host *host);
const char *input_controller_name(struct host *host, int port);
/* ui */
int ui_load_game(struct host *host, const char *path);
void ui_opened(struct host *host);
void ui_closed(struct host *host);
#endif

View File

@ -12,12 +12,13 @@
#include "options.h"
#include "render/render_backend.h"
#include "tracer.h"
#include "ui.h"
/*
* sdl host implementation
*/
#define AUDIO_FREQ 44100
#define VIDEO_DEFAULT_WIDTH 640
#define VIDEO_DEFAULT_WIDTH 853
#define VIDEO_DEFAULT_HEIGHT 480
#define INPUT_MAX_CONTROLLERS 4
@ -31,6 +32,7 @@ struct host {
struct SDL_Window *win;
int closed;
struct ui *ui;
struct emu *emu;
struct tracer *tracer;
struct imgui *imgui;
@ -284,6 +286,10 @@ static void video_shutdown(struct host *host) {
emu_vid_destroyed(host->emu);
}
if (host->ui) {
ui_vid_destroyed(host->ui);
}
r_destroy(host->video.r);
video_destroy_context(host, host->video.ctx);
}
@ -292,6 +298,10 @@ static int video_init(struct host *host) {
host->video.ctx = video_create_context(host);
host->video.r = r_create(host->video.width, host->video.height);
if (host->ui) {
ui_vid_created(host->ui, host->video.r);
}
if (host->emu) {
emu_vid_created(host->emu, host->video.r);
}
@ -505,6 +515,10 @@ static void input_keydown(struct host *host, int port, int key,
break;
}
if (host->ui && ui_keydown(host->ui, key, value)) {
continue;
}
if (host->emu && emu_keydown(host->emu, port, key, value)) {
continue;
}
@ -576,6 +590,28 @@ static int input_init(struct host *host) {
return 1;
}
int input_max_controllers(struct host *host) {
return INPUT_MAX_CONTROLLERS;
}
const char *input_controller_name(struct host *host, int port) {
CHECK(port >= 0 && port < INPUT_MAX_CONTROLLERS);
SDL_GameController *ctrl = host->input.controllers[port];
return SDL_GameControllerName(ctrl);
}
/*
* ui
*/
void ui_closed(struct host *host) {}
void ui_opened(struct host *host) {}
int ui_load_game(struct host *host, const char *path) {
return emu_load(host->emu, path);
}
/*
* internal
*/
@ -874,6 +910,7 @@ int main(int argc, char **argv) {
if (load && strstr(load, ".trace")) {
host->tracer = tracer_create(host);
} else {
host->ui = ui_create(host);
host->emu = emu_create(host);
}
@ -898,7 +935,17 @@ int main(int argc, char **argv) {
}
}
} else if (host->emu) {
if (emu_load(host->emu, load)) {
int success = 0;
if (load || OPTION_bios) {
success = emu_load(host->emu, load);
}
if (!success) {
/* if nothing is loaded, open the game select ui */
ui_set_page(host->ui, UI_PAGE_GAMES);
}
while (!host->closed) {
/* even though the emulator itself will poll for events when updating
controller input, the main loop needs to also poll to ensure the
@ -917,6 +964,7 @@ int main(int argc, char **argv) {
/* render emulator output and build up imgui buffers */
emu_render_frame(host->emu);
ui_build_menus(host->ui);
/* overlay imgui */
imgui_end_frame(host->imgui);
@ -929,10 +977,14 @@ int main(int argc, char **argv) {
}
}
}
}
host_shutdown(host);
if (host->ui) {
ui_destroy(host->ui);
host->ui = NULL;
}
if (host->emu) {
emu_destroy(host->emu);
}

View File

@ -1,12 +1,11 @@
#ifdef HAVE_IMGUI
#define IMGUI_IMPLEMENTATION
#define IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_PLACEMENT_NEW
#include <imgui/imgui.h>
#include <imgui/imgui_internal.h>
#endif
extern "C" {
#include <zlib.h>
#include "core/core.h"
#include "core/time.h"
#include "host/keycode.h"
@ -14,8 +13,11 @@ extern "C" {
#include "render/render_backend.h"
}
#define IMFONT_MAX_HEIGHT 128
struct imgui {
struct render_backend *r;
struct ImFont *fonts[IMFONT_NUM_FONTS][IMFONT_MAX_HEIGHT];
int64_t time;
int alt[2];
int ctrl[2];
@ -23,8 +25,210 @@ struct imgui {
uint16_t keys[K_NUM_KEYS];
};
/* maintain global pointer for ig* functions */
static struct imgui *g_imgui;
#include "assets/fontawesome-webfont.inc"
#include "assets/opensans-regular.inc"
#include "assets/oswald-medium.inc"
static ImFont *imgui_get_font(struct imgui *imgui, int id, int font_height);
/*
* imgui extensions
*/
using namespace ImGui;
namespace ImGui {
static ImRect ButtonBox(const ImVec2 &label_size, const ImVec2 &req_size) {
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
ImGuiWindow *window = GetCurrentWindow();
ImVec2 pos = window->DC.CursorPos;
ImVec2 size =
CalcItemSize(req_size, label_size.x + style.FramePadding.x * 2.0f,
label_size.y + style.FramePadding.y * 2.0f);
return ImRect(pos, pos + size);
}
static ImU32 SelectableColor(bool selected, bool hovered, bool held) {
if (selected || (hovered && held)) {
return ImGui::GetColorU32(ImGuiCol_ButtonActive);
}
if (hovered) {
return ImGui::GetColorU32(ImGuiCol_ButtonHovered);
}
return ImGui::GetColorU32(ImGuiCol_Button);
}
static void RenderCircularNavHighlight(const ImRect &bb, ImGuiID id) {
ImGuiContext &g = *GImGui;
if (id != g.NavId || g.NavDisableHighlight) {
return;
}
ImGuiWindow *window = GetCurrentWindow();
const float THICKNESS = 2.0f;
const float DISTANCE = 3.0f + THICKNESS * 0.5f;
ImRect display_rect(bb.Min - ImVec2(DISTANCE, DISTANCE),
bb.Max + ImVec2(DISTANCE, DISTANCE));
if (!window->ClipRect.Contains(display_rect)) {
window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
}
const ImRect draw_rect(
display_rect.Min + ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f),
display_rect.Max - ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f));
const ImVec2 center = draw_rect.GetCenter();
float radius = draw_rect.GetWidth() / 2.0f;
window->DrawList->AddCircle(
center, radius, GetColorU32(ImGuiCol_NavHighlight), 48, THICKNESS);
if (!window->ClipRect.Contains(display_rect)) {
window->DrawList->PopClipRect();
}
}
}
int igDiscButton(ImTextureID user_texture_id, float item_diameter,
float draw_diameter, const struct ImVec2 uv0,
const struct ImVec2 uv1) {
ImGuiWindow *window = GetCurrentWindow();
if (window->SkipItems) {
return 0;
}
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
ImGui::PushID((void *)user_texture_id);
const ImGuiID id = window->GetID("#image");
ImGui::PopID();
const ImVec2 item_size = {item_diameter, item_diameter};
const ImVec2 item_pos = window->DC.CursorPos;
const ImRect item_bb(item_pos, item_pos + item_size);
const ImVec2 draw_size = {draw_diameter, draw_diameter};
const ImVec2 draw_pos = {item_pos.x - (draw_diameter - item_diameter) / 2.0f,
item_pos.y - (draw_diameter - item_diameter) / 2.0f};
const ImRect draw_bb(draw_pos, draw_pos + draw_size);
ImGui::ItemSize(item_bb);
if (!ImGui::ItemAdd(item_bb, id)) {
return 0;
}
bool hovered, held;
bool pressed = ButtonBehavior(item_bb, id, &hovered, &held);
ImGui::RenderCircularNavHighlight(draw_bb, id);
window->DrawList->AddImage(user_texture_id, draw_bb.Min, draw_bb.Max, uv0,
uv1, 0xffffffff);
return (int)pressed;
}
int igOptionString(const char *label, const char *value, struct ImVec2 size) {
ImGuiWindow *window = ImGui::GetCurrentWindow();
if (window->SkipItems) {
return 0;
}
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);
const ImVec2 value_size = ImGui::CalcTextSize(value, NULL, true);
const ImVec2 total_size(label_size.x + value_size.x,
MAX(label_size.y, value_size.y));
const ImRect bb = ImGui::ButtonBox(total_size, size);
ImGui::ItemSize(bb, style.FramePadding.y);
if (!ImGui::ItemAdd(bb, id)) {
return 0;
}
ImGuiButtonFlags flags = 0;
if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) {
flags |= ImGuiButtonFlags_Repeat;
}
bool hovered, held;
bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, flags);
const ImU32 col = SelectableColor(false, hovered, held);
ImGui::RenderNavHighlight(bb, id);
ImGui::RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
ImGui::RenderTextClipped(bb.Min + style.FramePadding,
bb.Max - style.FramePadding, label, NULL,
&label_size, ImVec2(0.0f, 0.5f), &bb);
ImGui::RenderTextClipped(bb.Min + style.FramePadding,
bb.Max - style.FramePadding, value, NULL,
&value_size, ImVec2(1.0f, 0.5f), &bb);
return (int)pressed;
}
int igOptionInt(const char *label, int value, struct ImVec2 size) {
char value_str[128];
snprintf(value_str, sizeof(value_str), "%d", value);
return igOptionString(label, value_str, size);
}
int igTab(const char *label, struct ImVec2 size, int selected) {
ImGuiWindow *window = ImGui::GetCurrentWindow();
if (window->SkipItems) {
return 0;
}
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);
const ImRect bb = ImGui::ButtonBox(label_size, size);
ImGui::ItemSize(bb, style.FramePadding.y);
if (!ImGui::ItemAdd(bb, id)) {
return 0;
}
ImGuiButtonFlags flags = 0;
if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) {
flags |= ImGuiButtonFlags_Repeat;
}
bool hovered, held;
bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, flags);
const ImU32 col = SelectableColor(selected, hovered, held);
ImGui::RenderNavHighlight(bb, id);
ImGui::RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
ImGui::RenderTextClipped(bb.Min + style.FramePadding,
bb.Max - style.FramePadding, label, NULL,
&label_size, style.ButtonTextAlign, &bb);
return (int)pressed;
}
void igPushFontEx(int id, int font_height) {
ImGuiIO &io = ImGui::GetIO();
ImFont *font = imgui_get_font(g_imgui, id, font_height);
ImGui::PushFont(font);
}
/*
* imgui implementation
*/
static void imgui_update_font_tex(struct imgui *imgui) {
#ifdef HAVE_IMGUI
ImGuiIO &io = ImGui::GetIO();
/* destroy old texture first */
@ -48,11 +252,74 @@ static void imgui_update_font_tex(struct imgui *imgui) {
font_tex = r_create_texture(imgui->r, PXL_RGBA, FILTER_BILINEAR, WRAP_REPEAT,
WRAP_REPEAT, 0, width, height, pixels);
io.Fonts->TexID = (void *)(intptr_t)font_tex;
#endif
}
static ImFont *imgui_get_font(struct imgui *imgui, int id, int font_height) {
CHECK(id >= 0 && id < IMFONT_NUM_FONTS);
CHECK(font_height >= 0 && font_height < IMFONT_MAX_HEIGHT);
ImFont **font = &g_imgui->fonts[id][font_height];
if (*font) {
return *font;
}
int font_len = 0;
int font_gz_len = 0;
const uint8_t *font_gz = NULL;
switch (id) {
case IMFONT_OSWALD_MEDIUM:
font_len = oswald_medium_len;
font_gz_len = oswald_medium_gz_len;
font_gz = oswald_medium_gz;
break;
case IMFONT_OPENSANS_REGULAR:
font_len = opensans_regular_len;
font_gz_len = opensans_regular_len;
font_gz = opensans_regular_gz;
break;
default:
LOG_FATAL("igPushFontEx unsupported font %d", id);
break;
}
ImGuiIO &io = ImGui::GetIO();
/* load base font. note, AddFontFromMemoryTTF takes ownership of font_data, so
it doesn't need to be freed */
{
unsigned long tmp_len = font_len;
uint8_t *font_data = (uint8_t *)malloc(tmp_len);
int res = uncompress(font_data, &tmp_len, font_gz, font_gz_len);
CHECK_EQ(res, Z_OK);
*font = io.Fonts->AddFontFromMemoryTTF(font_data, tmp_len,
(float)font_height, NULL, NULL);
CHECK_NOTNULL(*font);
}
/* merge fontawesome icons */
{
static const ImWchar fa_ranges[] = {IMICON_RANGES, 0};
ImFontConfig config;
config.MergeMode = true;
unsigned long tmp_len = fontawesome_webfont_len;
uint8_t *font_data = (uint8_t *)malloc(tmp_len);
int res = uncompress(font_data, &tmp_len, fontawesome_webfont_gz,
fontawesome_webfont_gz_len);
CHECK_EQ(res, Z_OK);
*font = io.Fonts->AddFontFromMemoryTTF(
font_data, tmp_len, (float)font_height, &config, fa_ranges);
CHECK_NOTNULL(*font);
}
imgui_update_font_tex(imgui);
return *font;
}
void imgui_end_frame(struct imgui *imgui) {
#ifdef HAVE_IMGUI
ImGuiIO &io = ImGui::GetIO();
int width = (int)io.DisplaySize.x;
@ -103,7 +370,6 @@ void imgui_end_frame(struct imgui *imgui) {
r_end_ui_surfaces(imgui->r);
}
#endif
}
void imgui_begin_frame(struct imgui *imgui) {
@ -111,7 +377,6 @@ void imgui_begin_frame(struct imgui *imgui) {
int64_t delta_time = now - imgui->time;
imgui->time = now;
#ifdef HAVE_IMGUI
ImGuiIO &io = ImGui::GetIO();
int width = r_width(imgui->r);
@ -121,12 +386,22 @@ void imgui_begin_frame(struct imgui *imgui) {
io.MouseWheel = 0.0;
io.DisplaySize = ImVec2((float)width, (float)height);
/* update navigation inputs */
io.NavInputs[ImGuiNavInput_PadActivate] = imgui->keys[K_CONT_A];
io.NavInputs[ImGuiNavInput_PadCancel] = imgui->keys[K_CONT_B];
io.NavInputs[ImGuiNavInput_PadUp] =
imgui->keys[K_CONT_DPAD_UP] || imgui->keys[K_CONT_JOYY_NEG];
io.NavInputs[ImGuiNavInput_PadDown] =
imgui->keys[K_CONT_DPAD_DOWN] || imgui->keys[K_CONT_JOYY_POS];
io.NavInputs[ImGuiNavInput_PadLeft] =
imgui->keys[K_CONT_DPAD_LEFT] || imgui->keys[K_CONT_JOYX_NEG];
io.NavInputs[ImGuiNavInput_PadRight] =
imgui->keys[K_CONT_DPAD_RIGHT] || imgui->keys[K_CONT_JOYX_POS];
ImGui::NewFrame();
#endif
}
int imgui_keydown(struct imgui *imgui, int key, uint16_t value) {
#ifdef HAVE_IMGUI
ImGuiIO &io = ImGui::GetIO();
if (key == K_MWHEELUP) {
@ -152,40 +427,33 @@ int imgui_keydown(struct imgui *imgui, int key, uint16_t value) {
imgui->keys[key] = value;
io.KeysDown[key] = (bool)value;
}
#endif
return 0;
}
void imgui_mousemove(struct imgui *imgui, int x, int y) {
#ifdef HAVE_IMGUI
ImGuiIO &io = ImGui::GetIO();
io.MousePos = ImVec2((float)x, (float)y);
#endif
}
void imgui_destroy(struct imgui *imgui) {
#ifdef HAVE_IMGUI
ImGui::Shutdown();
free(imgui);
#endif
}
void imgui_vid_destroyed(struct imgui *imgui) {
#ifdef HAVE_IMGUI
ImGuiIO &io = ImGui::GetIO();
/* free up cached font data */
io.Fonts->Clear();
memset(imgui->fonts, 0, sizeof(imgui->fonts));
imgui_update_font_tex(imgui);
imgui->r = NULL;
#endif
}
void imgui_vid_created(struct imgui *imgui, struct render_backend *r) {
#ifdef HAVE_IMGUI
ImGuiIO &io = ImGui::GetIO();
imgui->r = r;
@ -193,11 +461,9 @@ void imgui_vid_created(struct imgui *imgui, struct render_backend *r) {
/* register default font */
io.Fonts->AddFontDefault();
imgui_update_font_tex(imgui);
#endif
}
struct imgui *imgui_create() {
#ifdef HAVE_IMGUI
struct imgui *imgui =
reinterpret_cast<struct imgui *>(calloc(1, sizeof(struct imgui)));
@ -212,8 +478,7 @@ struct imgui *imgui_create() {
io.SetClipboardTextFn = nullptr;
io.GetClipboardTextFn = nullptr;
g_imgui = imgui;
return imgui;
#else
return NULL;
#endif
}

View File

@ -1,18 +1,43 @@
#ifndef IMGUI_H
#define IMGUI_H
#include "host/keycode.h"
#ifdef HAVE_IMGUI
#ifndef IMGUI_IMPLEMENTATION
#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#include <cimgui/cimgui.h>
#endif
#endif
#include "host/keycode.h"
struct imgui;
struct render_backend;
/* imgui extensions */
enum {
IMFONT_OSWALD_MEDIUM,
IMFONT_OPENSANS_REGULAR,
IMFONT_NUM_FONTS,
};
#define IMICON_RANGES \
0xf00d, 0xf00d, 0xf028, 0xf028, 0xf067, 0xf067, 0xf07c, 0xf07c, 0xf0a0, \
0xf0a0, 0xf108, 0xf108, 0xf11b, 0xf11b
#define IMICON_TIMES u8"\uf00d"
#define IMICON_VOLUME_UP u8"\uf028"
#define IMICON_PLUS u8"\uf067"
#define IMICON_FOLDER_OPEN u8"\uf07c"
#define IMICON_HDD u8"\uf0a0"
#define IMICON_DESKTOP u8"\uf108"
#define IMICON_GAMEPAD u8"\uf11b"
void igPushFontEx(int id, int font_height);
int igTab(const char *label, struct ImVec2 size, int selected);
int igOptionInt(const char *label, int value, struct ImVec2 size);
int igOptionString(const char *label, const char *value, struct ImVec2 size);
int igDiscButton(ImTextureID user_texture_id, float item_diameter,
float draw_diameter, const struct ImVec2 uv0,
const struct ImVec2 uv1);
/* imgui implementation */
struct imgui *imgui_create();
void imgui_destroy(struct imgui *imgui);

View File

@ -37,6 +37,7 @@ struct button_map BUTTONS[] = {
const int NUM_BUTTONS = ARRAY_SIZE(BUTTONS);
/* host */
DEFINE_OPTION_INT(bios, 0, "Boot to bios");
DEFINE_OPTION_INT(audio, 1, "Enable audio");
DEFINE_PERSISTENT_OPTION_INT(latency, 50, "Preferred audio latency in ms");
DEFINE_PERSISTENT_OPTION_INT(fullscreen, 0, "Start window fullscreen");

View File

@ -18,6 +18,7 @@ extern struct button_map BUTTONS[];
extern const int NUM_BUTTONS;
/* host */
DECLARE_OPTION_INT(bios);
DECLARE_OPTION_INT(audio);
DECLARE_OPTION_INT(latency);
DECLARE_OPTION_INT(fullscreen);

1551
src/ui.c Normal file

File diff suppressed because it is too large Load Diff

34
src/ui.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef UI_H
#define UI_H
#include "host/keycode.h"
struct ui;
struct host;
struct render_backend;
enum {
UI_PAGE_NONE = -1,
UI_PAGE_GAMES = 0,
UI_PAGE_OPTIONS,
UI_PAGE_LIBRARY,
UI_PAGE_AUDIO,
UI_PAGE_VIDEO,
UI_PAGE_INPUT,
UI_PAGE_CONTROLLERS,
UI_PAGE_KEYBOARD,
UI_NUM_PAGES,
};
struct ui *ui_create(struct host *host);
void ui_destroy(struct ui *ui);
void ui_vid_created(struct ui *ui, struct render_backend *r);
void ui_vid_destroyed(struct ui *ui);
void ui_mousemove(struct ui *ui, int x, int y);
int ui_keydown(struct ui *ui, int key, int16_t value);
void ui_build_menus(struct ui *ui);
void ui_set_page(struct ui *ui, int page_index);
#endif