Skip to content

Commit

Permalink
PCMockup: Migrate to imgui (#39)
Browse files Browse the repository at this point in the history
* cmake: Add cimgui and glad dependencies

* pcmockup: Add imgui WindowContainer

* pcmockup: Add imgui ImageWindow

* pcmockup: Migrate PebbleWindow to imgui

* pcmockup: Migrate debugWindow to imgui

* pcmockup: add initial menubar

* pcmockup: Improve ImageWindow content alignment

* pcmockup: add extra include for travis

* pcmockup: work around missing header guard

* cmake: Update cimgui and ignore warnings

* PCMockup: Add Window module

* pcmockup: Migrate ImageWindow and consumers to Window

* pcmockup: Readd debug dragging

* pcmockup: Readd debug zooming

* pcmockup: fix slight misalignment

* pcmockup: fix logical merge conflict

* pcmockup: replace dragging with key controls
because imgui really does not like other people knowing what it does

* pcmockup: reintroduce dragging with MMB

* pcmockup: tweaks
  • Loading branch information
Helco committed Dec 7, 2018
1 parent 72e9491 commit fd73bd9
Show file tree
Hide file tree
Showing 19 changed files with 918 additions and 195 deletions.
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
[submodule "external/stb"]
path = external/stb
url = https://github.com/nothings/stb.git
[submodule "external/cimgui"]
path = external/cimgui
url = https://github.com/cimgui/cimgui.git
[submodule "external/glad"]
path = external/glad
url = https://github.com/Dav1dde/glad.git
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ include(CTest)
include(GoogleTest)
include("${CMAKE_SOURCE_DIR}/cmake/GTest.cmake")
include("${CMAKE_SOURCE_DIR}/cmake/stb.cmake")
include("${CMAKE_SOURCE_DIR}/cmake/glad.cmake")
include("${CMAKE_SOURCE_DIR}/cmake/cimgui.cmake")

if (MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC")
message(FATAL_ERROR " Microsoft C Compiler is not supported, please use GCC or Clang")
Expand Down
49 changes: 49 additions & 0 deletions cmake/cimgui.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Configures cimgui for use in PebbleOfDoom

set(CIMGUI_DIR "${CMAKE_SOURCE_DIR}/external/cimgui/")
set(IMGUI_DIR "${CIMGUI_DIR}/imgui/")
if (NOT EXISTS "${CIMGUI_DIR}/cimgui.h")
message(FATAL_ERROR "Could not find cimgui, did you clone the submodules?")
endif()
if (NOT EXISTS "${IMGUI_DIR}/imgui.h")
message(FATAL_ERROR "Could not find imgui, did you clone the submodules *recursively*?")
endif()

set(sources_cimgui
${CIMGUI_DIR}/cimgui.h
${CIMGUI_DIR}/cimgui.cpp

${IMGUI_DIR}/imgui.h
${IMGUI_DIR}/imgui.cpp
${IMGUI_DIR}/imgui_draw.cpp
${IMGUI_DIR}/imgui_demo.cpp
${IMGUI_DIR}/imgui_widgets.cpp

${IMGUI_DIR}/examples/imgui_impl_sdl.h
${IMGUI_DIR}/examples/imgui_impl_sdl.cpp
${IMGUI_DIR}/examples/imgui_impl_opengl3.h
${IMGUI_DIR}/examples/imgui_impl_opengl3.cpp
)

add_library(cimgui ${sources_cimgui})
target_include_directories(cimgui
PRIVATE ${IMGUI_DIR}
PRIVATE ${SDL2_INCLUDE_DIR}
INTERFACE ${CIMGUI_DIR}
INTERFACE ${IMGUI_DIR}/examples
)
target_link_libraries(cimgui
PUBLIC ${SDL2_LIBRARY}
PUBLIC glad
)
target_compile_definitions(cimgui
PRIVATE "-DIMGUI_IMPL_API=extern \"C\""
PRIVATE IMGUI_IMPL_OPENGL_LOADER_GLAD
INTERFACE CIMGUI_DEFINE_ENUMS_AND_STRUCTS
)
target_compile_options(cimgui PRIVATE
"-Wno-pragma-pack"
"-Wno-return-type-c-linkage"
"-Wno-unused-const-variable"
"-Wno-macro-redefined"
)
14 changes: 14 additions & 0 deletions cmake/glad.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Configures glad for use in PebbleOfDoom

set(GLAD_DIR "${CMAKE_SOURCE_DIR}/external/glad")
if (NOT EXISTS "${GLAD_DIR}/CMakeLists.txt")
message(FATAL_ERROR "Could not find glad, did you clone the submodules?")
endif()

set(GLAD_PROFILE "core" CACHE STRING "" FORCE)
set(GLAD_API "gl=3.0" CACHE STRING "" FORCE)
set(GLAD_GENERATOR "c" CACHE STRING "" FORCE)
set(GLAD_EXTENSIONS "" CACHE STRING "" FORCE)
set(GLAD_SPEC "gl" CACHE STRING "" FORCE)
option(GLAD_NO_LOADER "" ON)
add_subdirectory(${GLAD_DIR})
1 change: 1 addition & 0 deletions external/cimgui
Submodule cimgui added at 204f28
1 change: 1 addition & 0 deletions external/glad
Submodule glad added at ea3386
11 changes: 10 additions & 1 deletion pcmockup/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ set(sources_pcmockup
pebble.h
sdl.include.h
stb.include.h
cimgui.include.h

window.h
window_internal.h
window.c
windowcontainer.c

pcmockup.h
pcmockup.c
pebblewindow.c
Expand All @@ -15,13 +22,15 @@ set(sources_pcmockup
safeframebuffer.c
rendererinterface.c
texturemanager.c
windowcontainer.c
imagewindow.c
)
assign_source_group(${sources_pcmockup})

add_executable(pcmockup ${sources_pcmockup})
target_link_libraries(pcmockup
${SDL2_LIBRARY}
${STB_LIBRARY}
stb
podrenderer
)
target_include_directories(pcmockup
Expand Down
12 changes: 12 additions & 0 deletions pcmockup/cimgui.include.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef CIMGUI_INCLUDE_H
#define CIMGUI_INCLUDE_H

#pragma GCC diagnostic push
#ifdef __clang__
#pragma GCC diagnostic ignored "-Wpragma-pack"
#pragma GCC diagnostic ignored "-Wmacro-redefined"
#endif
#include<cimgui.h>
#pragma GCC diagnostic pop

#endif
164 changes: 94 additions & 70 deletions pcmockup/debugwindow.c
Original file line number Diff line number Diff line change
@@ -1,42 +1,67 @@
#include "pcmockup.h"
#include "renderer.h"
#include "platform.h"

#include <string.h>

struct DebugWindow
{
SDL_Window* window;
ImageWindow* window;
SDL_Renderer* renderer;
SDL_Texture* texture;
SDL_Rect texturePos;
SDL_Surface* surface;
Renderer* podRenderer;
const DebugView* view;
xz_t position, offset;
real_t zoom;
};

DebugWindow* debugWindow_init(SDL_Rect bounds, const DebugView* view, Renderer* podRenderer)
SDL_Surface* createSDLSurface(int w, int h, Uint32 format)
{
SDL_PixelFormat* formatInfo = SDL_AllocFormat(format);
if (formatInfo == NULL)
return NULL;
SDL_Surface* surface = SDL_CreateRGBSurface(
SDL_SWSURFACE, w, h, formatInfo->BitsPerPixel,
formatInfo->Rmask, formatInfo->Gmask, formatInfo->Bmask, formatInfo->Amask
);
SDL_FreeFormat(formatInfo);
return surface;
}

void debugWindow_onDrag(Window* window, int button, ImVec2 delta, void* userdata);
void debugWindow_onKeyDown(Window* window, SDL_Keysym sym, void* userdata);

DebugWindow* debugWindow_init(WindowContainer* parent, SDL_Rect bounds, const DebugView* view, Renderer* podRenderer)
{
DebugWindow* me = (DebugWindow*)malloc(sizeof(DebugWindow));
if (me == NULL)
return NULL;
memset(me, 0, sizeof(DebugWindow));

me->window = SDL_CreateWindow(view->name,
bounds.x, bounds.y,
bounds.w, bounds.h,
SDL_WINDOW_RESIZABLE);
GRect b = { { bounds.x, bounds.y }, { bounds.w, bounds.h} };
me->window = imageWindow_init(parent, view->name, b, false);
if (me->window == NULL)
{
fprintf(stderr, "SDL_CreateWindow: %s\n", SDL_GetError());
debugWindow_free(me);
return NULL;
}
window_setDragCallback(imageWindow_asWindow(me->window), debugWindow_onDrag, me);
window_setKeyCallbacks(imageWindow_asWindow(me->window), (WindowKeyCallbacks) {
.down = debugWindow_onKeyDown,
.userdata = me
});

me->surface = createSDLSurface(bounds.w, bounds.h, SDL_PIXELFORMAT_ABGR8888);
if (me->surface == NULL)
{
fprintf(stderr, "createSDLSurface: %s\n", SDL_GetError());
debugWindow_free(me);
return NULL;
}

me->renderer = SDL_CreateRenderer(me->window, -1, SDL_RENDERER_TARGETTEXTURE);
me->renderer = SDL_CreateSoftwareRenderer(me->surface);
if (me->renderer == NULL)
{
fprintf(stderr, "SDL_CreateRenderer: %s\n", SDL_GetError());
debugWindow_free(me);
return NULL;
}
Expand All @@ -53,56 +78,26 @@ void debugWindow_free(DebugWindow* me)
{
if (me == NULL)
return;
if (me->texture != NULL)
SDL_DestroyTexture(me->texture);
if (me->window != NULL)
imageWindow_free(me->window);
if (me->surface != NULL)
SDL_FreeSurface(me->surface);
if (me->renderer != NULL)
SDL_DestroyRenderer(me->renderer);
if (me->window != NULL)
SDL_DestroyWindow(me->window);
free(me);
}

void debugWindow_startUpdate(DebugWindow* me)
{
SDL_Rect src;
int textureW = -1, textureH = -1;
SDL_GetWindowSize(me->window, &src.w, &src.h);
if (me->texture != NULL)
SDL_QueryTexture(me->texture, NULL, NULL, &textureW, &textureH);
me->texturePos = findBestFit(src, 1.0f);

if (me->texturePos.w != textureW || me->texturePos.h != textureH)
{
if (me->texture != NULL)
SDL_DestroyTexture(me->texture);
me->texture = SDL_CreateTexture(me->renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_TARGET,
me->texturePos.w, me->texturePos.h);
if (me->texture == NULL)
{
fprintf(stderr, "SDL_CreateTexture: %s\n", SDL_GetError());
exit(-1);
}
}

SDL_SetRenderTarget(me->renderer, me->texture);
float scale = real_to_float(me->zoom);
SDL_SetRenderDrawColor(me->renderer, 0, 0, 0, 255);
SDL_RenderClear(me->renderer);

float scale = real_to_float(me->zoom);
SDL_RenderSetScale(me->renderer, scale, scale);
}

void debugWindow_endUpdate(DebugWindow* me)
{
SDL_RenderSetScale(me->renderer, 1.0f, 1.0f);
SDL_SetRenderTarget(me->renderer, NULL);
SDL_SetRenderDrawColor(me->renderer, 255, 0, 255, 255);
SDL_RenderClear(me->renderer);
SDL_SetRenderDrawColor(me->renderer, 255, 255, 255, 255);
SDL_RenderCopy(me->renderer, me->texture, NULL, &me->texturePos);
SDL_RenderPresent(me->renderer);
imageWindow_setImageData(me->window, GSize(me->surface->w, me->surface->h), (SDL_Color*)me->surface->pixels);
}

void debugWindow_update(DebugWindow* me)
Expand All @@ -112,32 +107,61 @@ void debugWindow_update(DebugWindow* me)
debugWindow_endUpdate(me);
}

void debugWindow_handleEvent(DebugWindow* me, const SDL_Event* ev)
void debugWindow_updateOffset(DebugWindow* me)
{
Uint32 windowID = SDL_GetWindowID(me->window);
if (ev->type == SDL_MOUSEMOTION && ev->motion.windowID == windowID && (ev->motion.state & SDL_BUTTON_LMASK) > 0)
{
xz_t move = xz(real_from_int(ev->motion.xrel), real_from_int(ev->motion.yrel));
move = xz_invScale(move, me->zoom);
me->position = xz_sub(me->position, move);
}
if (ev->type == SDL_MOUSEWHEEL && ev->wheel.windowID == windowID)
{
real_t zoom = real_from_int(ev->wheel.y);
zoom = real_mul(real_div(zoom, real_from_int(10)), me->zoom);
me->zoom = real_add(me->zoom, zoom);
}
if (ev->type == SDL_KEYDOWN && ev->key.windowID == windowID && ev->key.keysym.sym == SDLK_r)
{
me->position = xz(real_zero, real_zero);
}

// update render offset
int textureW, textureH;
SDL_QueryTexture(me->texture, NULL, NULL, &textureW, &textureH);
xz_t halfSize = xz(real_from_int(textureW / 2), real_from_int(textureH / 2));
xz_t halfSize = xz(real_from_int(me->surface->w / 2), real_from_int(me->surface->h / 2));
me->offset = xz_sub(
xz_invScale(halfSize, me->zoom),
me->position
);
}

void debugWindow_onDrag(Window* window, int button, ImVec2 delta, void* userdata)
{
UNUSED(window);
if (button != 2) // middle mouse button
return;
DebugWindow* me = (DebugWindow*)userdata;
xz_t move = xz_invScale((xz_t) { real_from_int(delta.x), real_from_int(delta.y) }, me->zoom);
me->position = xz_sub(me->position, move);
debugWindow_updateOffset(me);
}

void debugWindow_onKeyDown(Window* window, SDL_Keysym sym, void* userdata)
{
UNUSED(window);
static const float zoomSpeed = 0.1f;
static const float moveSpeed = 8.0f;
real_t zoomDelta = real_zero;
xz_t moveDelta = xz_zero;
switch (sym.sym)
{
case (SDLK_PLUS):
case (SDLK_KP_PLUS): zoomDelta = real_from_float(zoomSpeed); break;
case (SDLK_MINUS):
case (SDLK_KP_MINUS): zoomDelta = real_from_float(-zoomSpeed); break;
case (SDLK_w):
case (SDLK_UP): moveDelta = xz(real_zero, real_from_float(-moveSpeed)); break;
case (SDLK_s):
case (SDLK_DOWN): moveDelta = xz(real_zero, real_from_float(moveSpeed)); break;
case (SDLK_a):
case (SDLK_LEFT): moveDelta = xz(real_from_float(-moveSpeed), real_zero); break;
case (SDLK_d):
case (SDLK_RIGHT): moveDelta = xz(real_from_float(moveSpeed), real_zero); break;
default: return;
}
DebugWindow* me = (DebugWindow*)userdata;
me->position = xz_sub(me->position, xz_invScale(moveDelta, me->zoom));
me->zoom = real_add(me->zoom, real_mul(me->zoom, zoomDelta));
debugWindow_updateOffset(me);
}

const DebugView* debugWindow_getDebugView(const DebugWindow* me)
{
return me->view;
}

ImageWindow* debugWindow_asImageWindow(DebugWindow* me)
{
return me->window;
}
Loading

0 comments on commit fd73bd9

Please sign in to comment.