From d0c88590a3f23facb7d7de7e1be8989b045f2695 Mon Sep 17 00:00:00 2001 From: Helco Date: Fri, 23 Nov 2018 10:35:34 +0100 Subject: [PATCH] Refactoring of PCMockup/CMake (#41) * pcmockup: refactor main into module * pcmockup: fix incorrect name for debugWindowSet * cmake: enable many warnings as errors * cmake: extract dependency setup code * cmake: disable gtest update step * cmake: extract sub-projects setup code * pcmockup: remove relative paths to renderer * remove unnecessary submodules * CMake: fix semantic merge errors due to rebase * Renderer: inversion of control for debug rendering * pcmockup: fix clang warnings being ignored on gcc build --- CMakeLists.txt | 154 ++++----------------- README.md | 2 +- cmake/GTest.cmake | 41 ++++++ cmake/stb.cmake | 22 +++ external/GTest.CMakeLists.txt.in | 17 +-- pcmockup/CMakeLists.txt | 27 ++++ pcmockup/debugwindow.c | 31 +++-- pcmockup/debugwindowset.c | 11 +- pcmockup/pcmockup.c | 223 ++++++++++++++++++++----------- pcmockup/pcmockup.h | 16 ++- pcmockup/sdl.include.h | 2 + pcmockup/stb.include.h | 7 + pcmockup/stb_impl.c | 6 +- renderer/CMakeLists.txt | 27 ++++ renderer/platform.h | 20 +++ renderer/renderer.h | 29 ++-- renderer/renderer_debug.c | 90 ++++++++----- test/CMakeLists.txt | 22 +++ test/fixtures.h | 2 +- 19 files changed, 459 insertions(+), 290 deletions(-) create mode 100644 cmake/GTest.cmake create mode 100644 cmake/stb.cmake create mode 100644 pcmockup/CMakeLists.txt create mode 100644 pcmockup/stb.include.h create mode 100644 renderer/CMakeLists.txt create mode 100644 renderer/platform.h create mode 100644 test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 422f6b6..054dedb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,27 +1,6 @@ cmake_minimum_required (VERSION 3.9.2) project(pebbleofdoom) -################################################################### -# Dependencies -################################################################### - -set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/external/" ${CMAKE_MODULE_PATH}) - -find_package(SDL2 REQUIRED) -set(CMAKE_C_STANDARD 11) -set(CMAKE_CXX_STANDARD 11) - -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - link_libraries(m) -endif() - -include(CTest) -include(GoogleTest) - -if (MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC") - message(FATAL_ERROR " Microsoft C Compiler is not supported, please use GCC or Clang") -endif() - ################################################################### # Utilities ################################################################### @@ -40,123 +19,46 @@ function(assign_source_group) endforeach() endfunction(assign_source_group) -# To add googletests in the best way regarding cmake version -function(add_googletest TARGET PREFIX) - if (CMAKE_VERSION VERSION_LESS "3.10.0") - gtest_add_tests(TARGET ${TARGET} TEST_PREFIX ${PREFIX}) +# To enable many many warnings and treat them as errors (portable across msvc/gcc) +function(enable_warnings TARGET) + if (MSVC) + target_compile_options(${TARGET} PRIVATE "/W4" "/WX") else() - gtest_discover_tests(${TARGET} TEST_PREFIX ${PREFIX}) + target_compile_options(${TARGET} PRIVATE + "-Werror" "-Wall" "-Wextra" + "-Wpointer-arith" "-Wlogical-op" + "-Wdisabled-optimization" "-Wunsafe-loop-optimizations" + ) endif() -endfunction(add_googletest) +endfunction(enable_warnings) ################################################################### -# googletest +# Dependencies ################################################################### -configure_file(external/GTest.CMakeLists.txt.in googletest-download/CMakeLists.txt) -execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . - RESULT_VARIABLE result - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) -if(result) - message(FATAL_ERROR "CMake step for googletest failed: ${result}") -endif() -execute_process(COMMAND ${CMAKE_COMMAND} --build . - RESULT_VARIABLE result - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) -if(result) - message(FATAL_ERROR "Build step for googletest failed: ${result}") -endif() - -# Prevent overriding the parent project's compiler/linker -# settings on Windows -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/external/" ${CMAKE_MODULE_PATH}) -# Add googletest directly to our build. This defines -# the gtest and gtest_main targets. -add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src - ${CMAKE_BINARY_DIR}/googletest-build - EXCLUDE_FROM_ALL) +find_package(SDL2 REQUIRED) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 11) -# The gtest/gtest_main targets carry header search path -# dependencies automatically when using CMake 2.8.11 or -# later. Otherwise we have to add them here ourselves. -if (CMAKE_VERSION VERSION_LESS 2.8.11) - include_directories("${gtest_SOURCE_DIR}/include") +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + link_libraries(m) endif() -################################################################### -# PoD renderer -################################################################### - -set(sources_podrenderer - renderer/renderer.h - renderer/renderer.c - renderer/renderer_debug.c - renderer/algebra_float.c - renderer/algebra.h - renderer/algebra.c - - pcmockup/pebble.c -) -assign_source_group(${sources_podrenderer}) - -add_library(podrenderer ${sources_podrenderer}) -target_include_directories(podrenderer PUBLIC - "pcmockup/" # to access pebble.h - ${SDL2_INCLUDE_DIR} # for debug output -) -target_compile_definitions(podrenderer - PUBLIC REAL_USE_FLOAT - PUBLIC DEBUG_WINDOWS -) - -################################################################### -# tests -################################################################### - -set(sources_test_podrenderer - test/fixtures.h - test/test_real.cpp - test/test_vector.cpp - test/test_intersection.cpp - test/test_integer.cpp -) -assign_source_group(${sources_test_podrenderer}) +include(CTest) +include(GoogleTest) +include("${CMAKE_SOURCE_DIR}/cmake/GTest.cmake") +include("${CMAKE_SOURCE_DIR}/cmake/stb.cmake") -add_executable(test_podrenderer ${sources_test_podrenderer}) -target_link_libraries(test_podrenderer - podrenderer - gtest_main -) -add_googletest(test_podrenderer "def.") +if (MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC") + message(FATAL_ERROR " Microsoft C Compiler is not supported, please use GCC or Clang") +endif() ################################################################### -# PC Mockup +# sub-directories ################################################################### -set(sources_pcmockup - pcmockup/pebble.h - pcmockup/sdl.include.h - pcmockup/stb_impl.c - - pcmockup/pcmockup.h - pcmockup/pcmockup.c - pcmockup/pebblewindow.c - pcmockup/debugwindow.c - pcmockup/debugwindowset.c - pcmockup/windowgrid.c -) -assign_source_group(${sources_pcmockup}) - -add_executable(pcmockup ${sources_pcmockup}) -add_dependencies(pcmockup - podrenderer -) -target_link_libraries(pcmockup - ${SDL2_LIBRARY} - podrenderer -) -target_include_directories(pcmockup PUBLIC - "external/stb/" - "renderer/" -) +add_subdirectory("renderer") +add_subdirectory("test") +add_subdirectory("pcmockup") diff --git a/README.md b/README.md index b622b1d..fb5e3c3 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ As such a typical CMake call on Windows to develop this project looks like this: cmake -DSDL2_PATH="C:/libs/SDL2-2.0.5/" -T llvm .. ``` -You might have to copy your `SDL.dll` in the `build/Debug` or `build/Release` directory to start pcmockup. +You might have to copy your `SDL.dll` in the `build/pcmockup/Debug` or `build/pcmockup/Release` directory to start pcmockup. ### With make/gcc diff --git a/cmake/GTest.cmake b/cmake/GTest.cmake new file mode 100644 index 0000000..4214569 --- /dev/null +++ b/cmake/GTest.cmake @@ -0,0 +1,41 @@ +# Configures googletest for use in PebbleOfDoom + +configure_file(external/GTest.CMakeLists.txt.in googletest-download/CMakeLists.txt) +execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) +if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") +endif() +execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) +if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") +endif() + +# Prevent overriding the parent project's compiler/linker +# settings on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# Add googletest directly to our build. This defines +# the gtest and gtest_main targets. +add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src + ${CMAKE_BINARY_DIR}/googletest-build + EXCLUDE_FROM_ALL) + +# The gtest/gtest_main targets carry header search path +# dependencies automatically when using CMake 2.8.11 or +# later. Otherwise we have to add them here ourselves. +if (CMAKE_VERSION VERSION_LESS 2.8.11) + include_directories("${gtest_SOURCE_DIR}/include") +endif() + +# To add googletests in the best way regarding cmake version +function(add_googletest TARGET PREFIX) + if (CMAKE_VERSION VERSION_LESS "3.10.0") + gtest_add_tests(TARGET ${TARGET} TEST_PREFIX ${PREFIX}) + else() + gtest_discover_tests(${TARGET} TEST_PREFIX ${PREFIX}) + endif() +endfunction(add_googletest) diff --git a/cmake/stb.cmake b/cmake/stb.cmake new file mode 100644 index 0000000..69098bc --- /dev/null +++ b/cmake/stb.cmake @@ -0,0 +1,22 @@ +# Configures stb for use in PebbleOfDoom + +set(STB_DIR "${CMAKE_SOURCE_DIR}/external/stb") +if (NOT EXISTS "${STB_DIR}/stb_image.h") + message(FATAL_ERROR "Could not find stb_image, did you clone the submodules?") +endif() + +set(sources_stb + pcmockup/stb_impl.c + ${STB_DIR}/stb_image.h + ${STB_DIR}/stb_image_write.h +) +assign_source_group(${sources_stb}) + +add_library(stb ${sources_stb}) +target_include_directories(stb PUBLIC + ${STB_DIR} + "pcmockup" +) + +set(STB_LIBRARY "stb") +set(STB_INCLUDE_DIR ${STB_DIR}) diff --git a/external/GTest.CMakeLists.txt.in b/external/GTest.CMakeLists.txt.in index 1e03063..02e3ac9 100644 --- a/external/GTest.CMakeLists.txt.in +++ b/external/GTest.CMakeLists.txt.in @@ -5,12 +5,13 @@ project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG master - SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" - BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + UPDATE_DISCONNECTED 1 ) diff --git a/pcmockup/CMakeLists.txt b/pcmockup/CMakeLists.txt new file mode 100644 index 0000000..eff23a5 --- /dev/null +++ b/pcmockup/CMakeLists.txt @@ -0,0 +1,27 @@ +################################################################### +# PC Mockup +################################################################### + +set(sources_pcmockup + pebble.h + sdl.include.h + stb.include.h + pcmockup.h + pcmockup.c + pebblewindow.c + debugwindow.c + debugwindowset.c + windowgrid.c +) +assign_source_group(${sources_pcmockup}) + +add_executable(pcmockup ${sources_pcmockup}) +target_link_libraries(pcmockup + ${SDL2_LIBRARY} + ${STB_LIBRARY} + podrenderer +) +target_include_directories(pcmockup + PRIVATE ${SDL2_INCLUDE_DIR} +) +enable_warnings(pcmockup) diff --git a/pcmockup/debugwindow.c b/pcmockup/debugwindow.c index 641e0b5..1211bd5 100644 --- a/pcmockup/debugwindow.c +++ b/pcmockup/debugwindow.c @@ -1,5 +1,5 @@ #include "pcmockup.h" -#include "../renderer/renderer.h" +#include "renderer.h" #include @@ -9,19 +9,20 @@ struct DebugWindow SDL_Renderer* renderer; SDL_Texture* texture; SDL_Rect texturePos; - DebugInfo info; - xz_t position; + Renderer* podRenderer; + const DebugView* view; + xz_t position, offset; real_t zoom; }; -DebugWindow* debugWindow_init(SDL_Rect bounds, int index, const char* title) +DebugWindow* debugWindow_init(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(title, + me->window = SDL_CreateWindow(view->name, bounds.x, bounds.y, bounds.w, bounds.h, SDL_WINDOW_RESIZABLE); @@ -42,9 +43,9 @@ DebugWindow* debugWindow_init(SDL_Rect bounds, int index, const char* title) me->position = xz(real_zero, real_zero); me->zoom = real_one; - me->info.index = index; - me->info.offset = xz(real_from_int(bounds.w / 2), real_from_int(bounds.h / 2)); - me->info.ren = me->renderer; + me->offset = xz(real_from_int(bounds.w / 2), real_from_int(bounds.h / 2)); + me->podRenderer = podRenderer; + me->view = view; return me; } @@ -104,6 +105,13 @@ void debugWindow_endUpdate(DebugWindow* me) SDL_RenderPresent(me->renderer); } +void debugWindow_update(DebugWindow* me) +{ + debugWindow_startUpdate(me); + me->view->callback.sdl(me->podRenderer, me->renderer, me->offset, me->view->userdata); + debugWindow_endUpdate(me); +} + void debugWindow_handleEvent(DebugWindow* me, const SDL_Event* ev) { Uint32 windowID = SDL_GetWindowID(me->window); @@ -128,13 +136,8 @@ void debugWindow_handleEvent(DebugWindow* me, const SDL_Event* ev) 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)); - me->info.offset = xz_sub( + me->offset = xz_sub( xz_invScale(halfSize, me->zoom), me->position ); } - -const DebugInfo* debugWindow_getDebugInfo(DebugWindow* me) -{ - return &me->info; -} diff --git a/pcmockup/debugwindowset.c b/pcmockup/debugwindowset.c index 55b6fb0..6ce4bb0 100644 --- a/pcmockup/debugwindowset.c +++ b/pcmockup/debugwindowset.c @@ -32,8 +32,8 @@ DebugWindowSet* debugWindowSet_init(const WindowGrid* grid, Renderer* renderer) { me->windows[i] = debugWindow_init( windowGrid_getSingleBounds(grid, -1 - i), - i, - renderer_getDebugName(renderer, i) + &renderer_getDebugViews(renderer)[i], + renderer ); if (me->windows[i] == NULL) { @@ -68,15 +68,12 @@ void debugWindowSet_update(DebugWindowSet* me) #ifdef DEBUG_WINDOWS for (int i = 0; i < me->count; i++) { - debugWindow_startUpdate(me->windows[i]); - const DebugInfo* info = debugWindow_getDebugInfo(me->windows[i]); - renderer_renderDebug(me->renderer, info); - debugWindow_endUpdate(me->windows[i]); + debugWindow_update(me->windows[i]); } #endif } -void debugWindowSet_handleUpdate(DebugWindowSet* me, const SDL_Event* ev) +void debugWindowSet_handleEvent(DebugWindowSet* me, const SDL_Event* ev) { for (int i = 0; i < me->count; i++) debugWindow_handleEvent(me->windows[i], ev); diff --git a/pcmockup/pcmockup.c b/pcmockup/pcmockup.c index 2b85c61..41be223 100644 --- a/pcmockup/pcmockup.c +++ b/pcmockup/pcmockup.c @@ -1,119 +1,180 @@ #include #include "pcmockup.h" -#include "../renderer/renderer.h" +#include "renderer.h" +#include "platform.h" -static const int START_WINDOW_WIDTH = RENDERER_WIDTH * 2; -static const int START_WINDOW_HEIGHT = RENDERER_HEIGHT * 2; static const int MAX_FRAMERATE = 60; -#undef main -int main(int argc, char* argv[]) +struct PCMockup { - if (SDL_Init(SDL_INIT_VIDEO) < 0) + Renderer *renderer; + PebbleWindow *pebbleWindow; + DebugWindowSet *debugWindowSet; + bool_t isRunning; +}; + +PCMockup *pcmockup_init() +{ + PCMockup *me = (PCMockup *)malloc(sizeof(PCMockup)); + if (me == NULL) { - fprintf(stderr, "SDL_Init: %s\n", SDL_GetError()); - return -1; + fprintf(stderr, "Could not allocate PCMockup context\n"); + return NULL; + } + memset(me, 0, sizeof(PCMockup)); + + me->renderer = renderer_init(); + if (me->renderer == NULL) + { + pcmockup_free(me); + return NULL; } - Renderer* renderer = renderer_init(); - if (renderer == NULL) - return -1; SDL_DisplayMode displayMode; SDL_GetCurrentDisplayMode(0, &displayMode); WindowGrid windowGrid; - windowGrid.windowCount = 1 + renderer_getDebugCount(renderer); + windowGrid.windowCount = 1 + renderer_getDebugCount(me->renderer); windowGrid.totalSize = GSize(displayMode.w, displayMode.h); - PebbleWindow* pebbleWindow = pebbleWindow_init( + me->pebbleWindow = pebbleWindow_init( windowGrid_getSingleBounds(&windowGrid, 0), GSize(RENDERER_WIDTH, RENDERER_HEIGHT) ); - if (pebbleWindow == NULL) - return -1; + if (me->pebbleWindow == NULL) + return NULL; - DebugWindowSet* debugWindowSet = debugWindowSet_init( + me->debugWindowSet = debugWindowSet_init( &windowGrid, - renderer + me->renderer ); - if (debugWindowSet == NULL) - return -1; + if (me->debugWindowSet == NULL) + return NULL; - GColor* framebuffer = pebbleWindow_getPebbleFramebuffer(pebbleWindow); + me->isRunning = true; + return me; +} - int isRunning = 1; - while (isRunning) - { - const uint32_t frameStart = SDL_GetTicks(); +void pcmockup_free(PCMockup *me) +{ + if (me == NULL) + return; + if (me->debugWindowSet == NULL) + debugWindowSet_free(me->debugWindowSet); + if (me->pebbleWindow == NULL) + pebbleWindow_free(me->pebbleWindow); + if (me->renderer == NULL) + renderer_free(me->renderer); + free(me); +} - renderer_render(renderer, framebuffer); - pebbleWindow_update(pebbleWindow); - debugWindowSet_update(debugWindowSet); +void pcmockup_update(PCMockup *me) +{ + GColor *framebuffer = pebbleWindow_getPebbleFramebuffer(me->pebbleWindow); + renderer_render(me->renderer, framebuffer); + pebbleWindow_update(me->pebbleWindow); + debugWindowSet_update(me->debugWindowSet); - SDL_Event event; - while (SDL_PollEvent(&event)) + SDL_Event event; + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT) + me->isRunning = 0; + else if (event.type == SDL_KEYDOWN) { - if (event.type == SDL_QUIT) - isRunning = 0; - else if (event.type == SDL_KEYDOWN) + switch (event.key.keysym.sym) + { + case (SDLK_ESCAPE): + { + me->isRunning = 0; + } + break; + case (SDLK_w): + { + renderer_moveForward(me->renderer); + } + break; + case (SDLK_s): + { + renderer_moveBackwards(me->renderer); + } + break; + case (SDLK_a): + { + renderer_moveLeft(me->renderer); + } + break; + case (SDLK_d): + { + renderer_moveRight(me->renderer); + } + break; + case (SDLK_RIGHT): + { + renderer_rotateRight(me->renderer); + } + break; + case (SDLK_LEFT): + { + renderer_rotateLeft(me->renderer); + } + break; + case (SDLK_UP): + { + renderer_moveUp(me->renderer); + } + break; + case (SDLK_DOWN): { - switch(event.key.keysym.sym) - { - case (SDLK_ESCAPE): { isRunning = 0; }break; - case (SDLK_w): - { - renderer_moveForward(renderer); - }break; - case (SDLK_s): - { - renderer_moveBackwards(renderer); - }break; - case (SDLK_a): - { - renderer_moveLeft(renderer); - }break; - case (SDLK_d): - { - renderer_moveRight(renderer); - }break; - case (SDLK_RIGHT): - { - renderer_rotateRight(renderer); - }break; - case (SDLK_LEFT): - { - renderer_rotateLeft(renderer); - }break; - case (SDLK_UP): - { - renderer_moveUp(renderer); - }break; - case (SDLK_DOWN): - { - renderer_moveDown(renderer); - }break; - case (SDLK_SPACE): - { - Location playerLocation; - playerLocation.angle = real_degToRad(real_from_int(0)); - playerLocation.height = real_zero; - playerLocation.position = xz(real_from_int(20), real_from_int(20)); - - renderer_moveTo(renderer, playerLocation); - }break; - } + renderer_moveDown(me->renderer); + } + break; + case (SDLK_SPACE): + { + Location playerLocation; + playerLocation.angle = real_degToRad(real_from_int(0)); + playerLocation.height = real_zero; + playerLocation.position = xz(real_from_int(20), real_from_int(20)); + + renderer_moveTo(me->renderer, playerLocation); + } + break; } - debugWindowSet_handleUpdate(debugWindowSet, &event); } + debugWindowSet_handleEvent(me->debugWindowSet, &event); + } +} + +void pcmockup_mainLoop(PCMockup *me) +{ + while (me->isRunning) + { + const uint32_t frameStart = SDL_GetTicks(); + + pcmockup_update(me); const uint32_t frameEnd = SDL_GetTicks(); const int delay = (1000 / MAX_FRAMERATE) - (int)(frameEnd - frameStart); if (delay > 0) SDL_Delay(delay); } +} + +#undef main +int main(int argc, char *argv[]) +{ + UNUSED(argc, argv); + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + fprintf(stderr, "SDL_Init: %s\n", SDL_GetError()); + return -1; + } + PCMockup* pcmockup = pcmockup_init(); + if (pcmockup == NULL) + return -1; + + pcmockup_mainLoop(pcmockup); - renderer_free(renderer); - pebbleWindow_free(pebbleWindow); - debugWindowSet_free(debugWindowSet); + pcmockup_free(pcmockup); SDL_Quit(); return 0; } diff --git a/pcmockup/pcmockup.h b/pcmockup/pcmockup.h index 3add02f..500dde8 100644 --- a/pcmockup/pcmockup.h +++ b/pcmockup/pcmockup.h @@ -2,7 +2,7 @@ #define PCMOCKUP_H #include "sdl.include.h" #include "pebble.h" -#include "../renderer/renderer.h" +#include "renderer.h" SDL_Rect findBestFit(SDL_Rect target, float aspect); SDL_Rect padRect(SDL_Rect rect, GSize amount); @@ -23,17 +23,21 @@ SDL_Rect pebbleWindow_getBounds(PebbleWindow* window); GColor* pebbleWindow_getPebbleFramebuffer(PebbleWindow* window); typedef struct DebugWindow DebugWindow; -DebugWindow* debugWindow_init(SDL_Rect bounds, int index, const char* title); +DebugWindow* debugWindow_init(SDL_Rect bounds, const DebugView* debugView, Renderer* renderer); void debugWindow_free(DebugWindow* window); -void debugWindow_startUpdate(DebugWindow* window); -void debugWindow_endUpdate(DebugWindow* window); +void debugWindow_update(DebugWindow* window); void debugWindow_handleEvent(DebugWindow* window, const SDL_Event* ev); -const DebugInfo* debugWindow_getDebugInfo(DebugWindow* window); typedef struct DebugWindowSet DebugWindowSet; DebugWindowSet* debugWindowSet_init(const WindowGrid* grid, Renderer* renderer); void debugWindowSet_free(DebugWindowSet* set); void debugWindowSet_update(DebugWindowSet* set); -void debugWindowSet_handleUpdate(DebugWindowSet* set, const SDL_Event* ev); +void debugWindowSet_handleEvent(DebugWindowSet* set, const SDL_Event* ev); + +typedef struct PCMockup PCMockup; +PCMockup* pcmockup_init(); +void pcmockup_free(PCMockup* me); +void pcmockup_update(PCMockup* me); +void pcmockup_mainLoop(PCMockup* me); #endif diff --git a/pcmockup/sdl.include.h b/pcmockup/sdl.include.h index d5eee2a..c2dc260 100644 --- a/pcmockup/sdl.include.h +++ b/pcmockup/sdl.include.h @@ -18,7 +18,9 @@ */ #pragma GCC diagnostic push +#ifdef __clang__ #pragma GCC diagnostic ignored "-Wpragma-pack" #pragma GCC diagnostic ignored "-Wmacro-redefined" +#endif #include #pragma GCC diagnostic pop diff --git a/pcmockup/stb.include.h b/pcmockup/stb.include.h new file mode 100644 index 0000000..1ea2b52 --- /dev/null +++ b/pcmockup/stb.include.h @@ -0,0 +1,7 @@ +// see sdl.include.h for the reason of this file + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#include +#pragma GCC diagnostic pop diff --git a/pcmockup/stb_impl.c b/pcmockup/stb_impl.c index 033dfaa..449dca7 100644 --- a/pcmockup/stb_impl.c +++ b/pcmockup/stb_impl.c @@ -9,10 +9,8 @@ #endif #define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_WRITE_IMPLEMENTATION #define STBI_ONLY_PNG #define STBI_ONLY_BMP #define STBI_NO_SIMD // SIMD build crashes clang on windows -#include - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include +#include "stb.include.h" diff --git a/renderer/CMakeLists.txt b/renderer/CMakeLists.txt new file mode 100644 index 0000000..7abdd81 --- /dev/null +++ b/renderer/CMakeLists.txt @@ -0,0 +1,27 @@ +################################################################### +# PoD renderer +################################################################### + +set(sources_podrenderer + renderer.h + renderer.c + renderer_debug.c + algebra_float.c + algebra.h + algebra.c + + ../pcmockup/pebble.c +) +assign_source_group(${sources_podrenderer}) + +add_library(podrenderer ${sources_podrenderer}) +target_include_directories(podrenderer + INTERFACE "." + PRIVATE "../pcmockup/" # to access pebble.h + PRIVATE ${SDL2_INCLUDE_DIR} # for debug output +) +target_compile_definitions(podrenderer + PUBLIC REAL_USE_FLOAT + PUBLIC DEBUG_WINDOWS +) +enable_warnings(podrenderer) diff --git a/renderer/platform.h b/renderer/platform.h new file mode 100644 index 0000000..8a28b25 --- /dev/null +++ b/renderer/platform.h @@ -0,0 +1,20 @@ +#ifndef PLATFORM_H +#define PLATFORM_H + +// Platform/Compiler-specific utilities + +/* Declare unused parameter, to be used like + * ``` + * void bla(int foo, int bar) { + * UNUSED(foo, bar); + * } + * ``` + */ +#define UNUSED(...) do { \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wunused-value\"") \ + (void)(__VA_ARGS__); \ + _Pragma("GCC diagnostic pop") \ + } while(0) + +#endif diff --git a/renderer/renderer.h b/renderer/renderer.h index 01d83f2..77ed9f1 100644 --- a/renderer/renderer.h +++ b/renderer/renderer.h @@ -33,18 +33,27 @@ void renderer_moveForward(Renderer* renderer); void renderer_moveBackwards(Renderer* renderer); #ifdef DEBUG_WINDOWS -#include +struct SDL_Renderer; // no need to include SDL here -typedef struct DebugInfo +typedef enum DebugViewType { - int index; - SDL_Renderer* ren; - xz_t offset; -} DebugInfo; - -int renderer_getDebugCount(Renderer* renderer); -const char* renderer_getDebugName(Renderer* renderer, int index); -void renderer_renderDebug(Renderer* me, const DebugInfo* debug); + DebugViewType_SDL +} DebugViewType; + +typedef void (*DebugViewCallback_SDL)(Renderer* me, struct SDL_Renderer* sdlRenderer, xz_t offset, const void* userdata); + +typedef struct DebugView +{ + const char* name; + DebugViewType type; + union { + DebugViewCallback_SDL sdl; + } callback; + const void* userdata; // given to the callbacks +} DebugView; + +int renderer_getDebugCount(const Renderer* renderer); +const DebugView* renderer_getDebugViews(const Renderer* renderer); #endif #endif diff --git a/renderer/renderer_debug.c b/renderer/renderer_debug.c index b2585f3..41a8439 100644 --- a/renderer/renderer_debug.c +++ b/renderer/renderer_debug.c @@ -1,56 +1,53 @@ #ifdef DEBUG_WINDOWS #include "renderer_internal.h" +#include "platform.h" +#include "sdl.include.h" -int renderer_getDebugCount(Renderer* renderer) +typedef struct { - return 2; -} - -const char* renderer_getDebugName(Renderer* renderer, int index) -{ - if (index < 0 || index > 1) - return ""; - static const char* const NAMES[] = { - "world-space", - "player-space" - }; - return NAMES[index]; -} + bool_t transform; +} RenderWorldOptions; +static const RenderWorldOptions worldSpaceOptions = { + .transform = false +}; +static const RenderWorldOptions playerSpaceOptions = { + .transform = true +}; -void renderer_setDebugColor(const DebugInfo* debug, GColor color) +void renderer_setDebugColor(SDL_Renderer* sdlRenderer, GColor color) { - SDL_SetRenderDrawColor(debug->ren, color.r * (255 / 3), color.g * (255 / 3), color.b * (255 / 3), 255); + SDL_SetRenderDrawColor(sdlRenderer, color.r * (255 / 3), color.g * (255 / 3), color.b * (255 / 3), 255); } -void renderer_renderDebugLine(Renderer* me, const DebugInfo* debug, lineSeg_t line) +void renderer_renderSDLDebugLine(Renderer* me, SDL_Renderer* sdlRenderer, xz_t offset, lineSeg_t line, const RenderWorldOptions* opts) { lineSeg_t transformed = line; - if (debug->index == 1) + if (opts->transform) renderer_transformLine(me, &line, &transformed); - xz_t start = xz_add(transformed.start.xz, debug->offset); - xz_t end = xz_add(transformed.end.xz, debug->offset); - SDL_RenderDrawLine(debug->ren, + xz_t start = xz_add(transformed.start.xz, offset); + xz_t end = xz_add(transformed.end.xz, offset); + SDL_RenderDrawLine(sdlRenderer, real_to_int(start.x), real_to_int(start.z), real_to_int(end.x), real_to_int(end.z)); } -void renderer_renderDebugVector(Renderer* me, const DebugInfo* debug, xz_t origin, xz_t direction) +void renderer_renderDebugVector(Renderer* me, SDL_Renderer* sdlRenderer, xz_t offset, xz_t origin, xz_t direction, const RenderWorldOptions* opts) { lineSeg_t seg; seg.start.xz = origin; seg.end.xz = xz_add(origin, direction); - renderer_renderDebugLine(me, debug, seg); + renderer_renderSDLDebugLine(me, sdlRenderer, offset, seg, opts); real_t arrowLength = real_div(xz_length(direction), real_from_int(3)); direction = xz_normalize(direction); xz_t arrow = xz_scale(xz_rotate(direction, real_degToRad(160)), arrowLength); seg.start.xz = seg.end.xz; seg.end.xz = xz_add(seg.start.xz, arrow); - renderer_renderDebugLine(me, debug, seg); + renderer_renderSDLDebugLine(me, sdlRenderer, offset, seg, opts); arrow = xz_scale(xz_rotate(direction, real_degToRad(-160)), arrowLength); seg.end.xz = xz_add(seg.start.xz, arrow); - renderer_renderDebugLine(me, debug, seg); + renderer_renderSDLDebugLine(me, sdlRenderer, offset, seg, opts); } xz_t angleToVector(real_t angle, real_t length) @@ -61,8 +58,10 @@ xz_t angleToVector(real_t angle, real_t length) ), length); } -void renderer_renderDebug(Renderer* me, const DebugInfo* debug) +void renderer_debug_renderWorld(Renderer* me, SDL_Renderer* sdlRenderer, xz_t offset, const void* userdata) { + const RenderWorldOptions* opts = (const RenderWorldOptions*)userdata; + const Wall* walls[] = { &me->wall, &me->wall2, @@ -75,20 +74,47 @@ void renderer_renderDebug(Renderer* me, const DebugInfo* debug) lineSeg_t wallLine; wallLine.start.xz = (*curWall)->start; wallLine.end.xz = (*curWall)->end; - renderer_setDebugColor(debug, (*curWall)->wallColor); - renderer_renderDebugLine(me, debug, wallLine); + renderer_setDebugColor(sdlRenderer, (*curWall)->wallColor); + renderer_renderSDLDebugLine(me, sdlRenderer, offset, wallLine, opts); curWall++; } GColor red = GColorFromRGB(255, 0, 0); - renderer_setDebugColor(debug, red); - renderer_renderDebugVector(me, debug, me->location.position, angleToVector(me->location.angle, 30)); + renderer_setDebugColor(sdlRenderer, red); + renderer_renderDebugVector(me, sdlRenderer, offset, me->location.position, angleToVector(me->location.angle, 30), opts); lineSeg_t fovLine; fovLine.start.xz = me->location.position; fovLine.end.xz = xz_add(me->location.position, angleToVector(me->location.angle + me->halfFov, 70)); - renderer_renderDebugLine(me, debug, fovLine); + renderer_renderSDLDebugLine(me, sdlRenderer, offset, fovLine, opts); fovLine.end.xz = xz_add(me->location.position, angleToVector(me->location.angle - me->halfFov, 70)); - renderer_renderDebugLine(me, debug, fovLine); + renderer_renderSDLDebugLine(me, sdlRenderer, offset, fovLine, opts); +} + +static const DebugView debugViews[] = { + { + .name = "world-space", + .type = DebugViewType_SDL, + .callback = { .sdl = renderer_debug_renderWorld }, + .userdata = &worldSpaceOptions + }, + { + .name = "player-space", + .type = DebugViewType_SDL, + .callback = { .sdl = renderer_debug_renderWorld }, + .userdata = &playerSpaceOptions + } +}; + +int renderer_getDebugCount(const Renderer* renderer) +{ + UNUSED(renderer); + return sizeof(debugViews) / sizeof(DebugView); +} + +const DebugView* renderer_getDebugViews(const Renderer* renderer) +{ + UNUSED(renderer); + return debugViews; } #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..c7fe550 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,22 @@ +################################################################### +# tests +################################################################### + +set(sources_test_podrenderer + fixtures.h + test_real.cpp + test_vector.cpp + test_intersection.cpp + test_integer.cpp +) +assign_source_group(${sources_test_podrenderer}) + +add_executable(test_podrenderer ${sources_test_podrenderer}) +target_link_libraries(test_podrenderer + podrenderer + gtest_main +) +target_include_directories(test_podrenderer PUBLIC + "../renderer/" +) +add_googletest(test_podrenderer "def.") diff --git a/test/fixtures.h b/test/fixtures.h index cebadcb..7369691 100644 --- a/test/fixtures.h +++ b/test/fixtures.h @@ -2,7 +2,7 @@ // Ensure renderer functions are linked correctly extern "C" { -#include "../renderer/algebra.h" +#include "algebra.h" } class MathFixture : public testing::Test {