diff --git a/scripts/gen_build.py b/scripts/gen_build.py index 24b06a7..c8d15bf 100644 --- a/scripts/gen_build.py +++ b/scripts/gen_build.py @@ -18,10 +18,10 @@ if len(sys.argv) > 1: sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/" + pilotlight_location) -import pl_build.core as pl -import pl_build.backend_win32 as win32 -import pl_build.backend_linux as linux -import pl_build.backend_macos as apple +import build.core as pl +import build.backend_win32 as win32 +import build.backend_linux as linux +import build.backend_macos as apple #----------------------------------------------------------------------------- # [SECTION] project diff --git a/src/app.c b/src/app.c index 9a5d775..02c792f 100644 --- a/src/app.c +++ b/src/app.c @@ -1,20 +1,64 @@ /* - app.c - - template app - - loads only stable APIs + example_basic_2.c + - demonstrates loading APIs + - demonstrates loading extensions + - demonstrates hot reloading + - demonstrates starter extension + - demonstrates basic drawing extension (2D) + - demonstrates basic screen log extension + - demonstrates basic console extension + - demonstrates basic UI extension */ /* Index of this file: +// [SECTION] quick notes // [SECTION] includes // [SECTION] structs // [SECTION] apis -// [SECTION] helper functions forward declarations // [SECTION] pl_app_load // [SECTION] pl_app_shutdown // [SECTION] pl_app_resize // [SECTION] pl_app_update -// [SECTION] helper functions implementations +*/ + +//----------------------------------------------------------------------------- +// [SECTION] quick notes +//----------------------------------------------------------------------------- + +/* + This example is the first to introduce extensions. Extensions are just + shared libraries that export a "load" and "unload" function. The default + being: + + * void pl_load_ext (plApiRegistryI*, bool reload) + * void pl_unload_ext(plApiRegistryI*, bool reload) + + Later examples will explain more about the details of creating an extension + but the important thing to understand now is that an extension just provides + an implementation of an API. The "load" function allows an extension to + request APIs it depends on and to register any API it provides. The unload + function just allows an extension the opportunity to unregister and perform + any required cleanup. + + This example is also the first to introduce the "starter" extension. This + extension acts a bit as a helper extension to remove some common boilerplate + but is also just useful in general for most applications only needing to use + UI, plotting, drawing, etc. Or even to just experiment with the lower level + graphics extension in an isolated manner. Later examples will gradually peel + away at this extension and others. For this example, we will just demonstrate + some of the smaller helpful extensions. These include: + + * log + * profile + * stat + * console + * screen log + * ui + + This will be very light introductions with later examples going into more + detail. Feel free to open the header file for the extension for more + information and functionality. */ //----------------------------------------------------------------------------- @@ -24,32 +68,21 @@ Index of this file: #include // malloc, free #include // memset #include "pl.h" -#include "pl_memory.h" -#define PL_MATH_INCLUDE_FUNCTIONS + +#define PL_MATH_INCLUDE_FUNCTIONS // required to expose some of the color helpers #include "pl_math.h" // extensions -#include "pl_log_ext.h" -#include "pl_window_ext.h" -#include "pl_shader_ext.h" #include "pl_draw_ext.h" +#include "pl_starter_ext.h" #include "pl_ui_ext.h" -#include "pl_graphics_ext.h" -#include "pl_draw_backend_ext.h" -#include "pl_profile_ext.h" -#include "pl_stats_ext.h" -#include "pl_job_ext.h" -#include "pl_string_intern_ext.h" -#include "pl_library_ext.h" -#include "pl_rect_pack_ext.h" -#include "pl_gpu_allocators_ext.h" -#include "pl_image_ext.h" -#include "pl_console_ext.h" #include "pl_screen_log_ext.h" -#include "pl_tools_ext.h" -#include "pl_platform_ext.h" +#include "pl_profile_ext.h" +#include "pl_log_ext.h" +#include "pl_stats_ext.h" +#include "pl_console_ext.h" -// example extensions +// out extension #include "pl_example_ext.h" //----------------------------------------------------------------------------- @@ -61,83 +94,34 @@ typedef struct _plAppData // window plWindow* ptWindow; - // drawing stuff - plDrawList2D* ptDrawlist; - plDrawLayer2D* ptFGLayer; - plDrawLayer2D* ptBGLayer; - plFont* ptDefaultFont; - - // ui options - bool bShowUiDebug; - bool bShowUiStyle; - bool* pbShowDeviceMemoryAnalyzer; - bool* pbShowMemoryAllocations; - bool* pbShowProfiling; - bool* pbShowStats; - bool* pbShowLogging; - - // graphics & sync objects - plDevice* ptDevice; - plSurface* ptSurface; - plSwapchain* ptSwapchain; - plTimelineSemaphore* aptSemaphores[PL_MAX_FRAMES_IN_FLIGHT]; - uint64_t aulNextTimelineValue[PL_MAX_FRAMES_IN_FLIGHT]; - plCommandPool* atCmdPools[PL_MAX_FRAMES_IN_FLIGHT]; - plRenderPassHandle tMainRenderPass; - plRenderPassLayoutHandle tMainRenderPassLayout; + // log channel + uint64_t uExampleLogChannel; + // console variable + bool bShowHelpWindow; } plAppData; //----------------------------------------------------------------------------- // [SECTION] apis //----------------------------------------------------------------------------- -const plDataRegistryI* gptDataRegistry = NULL; -const plMemoryI* gptMemory = NULL; -const plIOI* gptIO = NULL; -const plWindowI* gptWindows = NULL; -const plGraphicsI* gptGfx = NULL; -const plDrawI* gptDraw = NULL; -const plUiI* gptUi = NULL; -const plShaderI* gptShader = NULL; -const plDrawBackendI* gptDrawBackend = NULL; -const plProfileI* gptProfile = NULL; -const plExampleI* gptExample = NULL; -const plStatsI* gptStats = NULL; -const plToolsI* gptTools = NULL; -const plImageI* gptImage = NULL; -const plGPUAllocatorsI* gptGpuAllocators = NULL; -const plJobI* gptJob = NULL; -const plThreadsI* gptThreads = NULL; -const plAtomicsI* gptAtomics = NULL; -const plRectPackI* gptRect = NULL; -const plFileI* gptFile = NULL; -const plNetworkI* gptNetwork = NULL; -const plStringInternI* gptString = NULL; -const plLibraryI* gptLibrary = NULL; -const plLogI* gptLog = NULL; -const plVirtualMemoryI* gptVirtualMemory = NULL; -const plConsoleI* gptConsole = NULL; -const plScreenLogI* gptScreenLog = NULL; +const plIOI* gptIO = NULL; +const plWindowI* gptWindows = NULL; +const plDrawI* gptDraw = NULL; +const plStarterI* gptStarter = NULL; +const plUiI* gptUI = NULL; +const plScreenLogI* gptScreenLog = NULL; +const plProfileI* gptProfile = NULL; +const plStatsI* gptStats = NULL; +const plMemoryI* gptMemory = NULL; +const plLogI* gptLog = NULL; +const plConsoleI* gptConsole = NULL; +const plExampleI* gptExample = NULL; -// helpers #define PL_ALLOC(x) gptMemory->tracked_realloc(NULL, (x), __FILE__, __LINE__) #define PL_REALLOC(x, y) gptMemory->tracked_realloc((x), (y), __FILE__, __LINE__) #define PL_FREE(x) gptMemory->tracked_realloc((x), 0, __FILE__, __LINE__) -#define PL_DS_ALLOC(x) gptMemory->tracked_realloc(NULL, (x), __FILE__, __LINE__) -#define PL_DS_ALLOC_INDIRECT(x, FILE, LINE) gptMemory->tracked_realloc(NULL, (x), FILE, LINE) -#define PL_DS_FREE(x) gptMemory->tracked_realloc((x), 0, __FILE__, __LINE__) -#include "pl_ds.h" - -//----------------------------------------------------------------------------- -// [SECTION] helper functions forward declarations -//----------------------------------------------------------------------------- - -void pl__setup_graphics_extensions (plAppData*); -void pl__resize_graphics_extensions(plAppData*); -void pl__resize_graphics_extensions(plAppData*); - //----------------------------------------------------------------------------- // [SECTION] pl_app_load //----------------------------------------------------------------------------- @@ -145,13 +129,9 @@ void pl__resize_graphics_extensions(plAppData*); PL_EXPORT void* pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData) { - // NOTE: on first load, "ptAppData" will be NULL but on reloads + // NOTE: on first load, "pAppData" will be NULL but on reloads // it will be the value returned from this function - // retrieve the data registry API, this is the API used for sharing data - // between extensions & the runtime - gptDataRegistry = pl_get_api_latest(ptApiRegistry, plDataRegistryI); - // if "ptAppData" is a valid pointer, then this function is being called // during a hot reload. if(ptAppData) @@ -159,140 +139,86 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData) // re-retrieve the apis since we are now in // a different dll/so - gptMemory = pl_get_api_latest(ptApiRegistry, plMemoryI); - gptIO = pl_get_api_latest(ptApiRegistry, plIOI); - gptWindows = pl_get_api_latest(ptApiRegistry, plWindowI); - gptGfx = pl_get_api_latest(ptApiRegistry, plGraphicsI); - gptDraw = pl_get_api_latest(ptApiRegistry, plDrawI); - gptShader = pl_get_api_latest(ptApiRegistry, plShaderI); - gptDrawBackend = pl_get_api_latest(ptApiRegistry, plDrawBackendI); - gptUi = pl_get_api_latest(ptApiRegistry, plUiI); - gptProfile = pl_get_api_latest(ptApiRegistry, plProfileI); - gptStats = pl_get_api_latest(ptApiRegistry, plStatsI); - gptExample = pl_get_api_latest(ptApiRegistry, plExampleI); - gptTools = pl_get_api_latest(ptApiRegistry, plToolsI); - gptImage = pl_get_api_latest(ptApiRegistry, plImageI); - gptGpuAllocators = pl_get_api_latest(ptApiRegistry, plGPUAllocatorsI); - gptJob = pl_get_api_latest(ptApiRegistry, plJobI); - gptThreads = pl_get_api_latest(ptApiRegistry, plThreadsI); - gptAtomics = pl_get_api_latest(ptApiRegistry, plAtomicsI); - gptRect = pl_get_api_latest(ptApiRegistry, plRectPackI); - gptFile = pl_get_api_latest(ptApiRegistry, plFileI); - gptNetwork = pl_get_api_latest(ptApiRegistry, plNetworkI); - gptString = pl_get_api_latest(ptApiRegistry, plStringInternI); - gptLibrary = pl_get_api_latest(ptApiRegistry, plLibraryI); - gptLog = pl_get_api_latest(ptApiRegistry, plLogI); - gptVirtualMemory = pl_get_api_latest(ptApiRegistry, plVirtualMemoryI); - gptConsole = pl_get_api_latest(ptApiRegistry, plConsoleI); - gptScreenLog = pl_get_api_latest(ptApiRegistry, plScreenLogI); + gptIO = pl_get_api_latest(ptApiRegistry, plIOI); + gptWindows = pl_get_api_latest(ptApiRegistry, plWindowI); + gptDraw = pl_get_api_latest(ptApiRegistry, plDrawI); + gptStarter = pl_get_api_latest(ptApiRegistry, plStarterI); + gptUI = pl_get_api_latest(ptApiRegistry, plUiI); + gptScreenLog = pl_get_api_latest(ptApiRegistry, plScreenLogI); + gptProfile = pl_get_api_latest(ptApiRegistry, plProfileI); + gptStats = pl_get_api_latest(ptApiRegistry, plStatsI); + gptMemory = pl_get_api_latest(ptApiRegistry, plMemoryI); + gptLog = pl_get_api_latest(ptApiRegistry, plLogI); + gptConsole = pl_get_api_latest(ptApiRegistry, plConsoleI); + gptExample = pl_get_api_latest(ptApiRegistry, plExampleI); return ptAppData; } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~apis & extensions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // retrieve extension registry const plExtensionRegistryI* ptExtensionRegistry = pl_get_api_latest(ptApiRegistry, plExtensionRegistryI); // load extensions - ptExtensionRegistry->load("pl_unity_ext", NULL, NULL, false); - ptExtensionRegistry->load("pl_platform_ext", NULL, NULL, false); + // * first argument is the shared library name WITHOUT the extension + // * second & third argument is the load/unload functions names (use NULL for the default of "pl_load_ext" & + // "pl_unload_ext") + // * fourth argument indicates if the extension is reloadable (should we check for changes and reload if changed) + ptExtensionRegistry->load("pl_unity_ext", NULL, NULL, true); + ptExtensionRegistry->load("pl_platform_ext", NULL, NULL, false); // provides the file API used by the drawing ext ptExtensionRegistry->load("pl_example_ext", NULL, NULL, true); - // load apis - gptMemory = pl_get_api_latest(ptApiRegistry, plMemoryI); - gptIO = pl_get_api_latest(ptApiRegistry, plIOI); - gptWindows = pl_get_api_latest(ptApiRegistry, plWindowI); - gptGfx = pl_get_api_latest(ptApiRegistry, plGraphicsI); - gptDraw = pl_get_api_latest(ptApiRegistry, plDrawI); - gptShader = pl_get_api_latest(ptApiRegistry, plShaderI); - gptDrawBackend = pl_get_api_latest(ptApiRegistry, plDrawBackendI); - gptUi = pl_get_api_latest(ptApiRegistry, plUiI); - gptProfile = pl_get_api_latest(ptApiRegistry, plProfileI); - gptStats = pl_get_api_latest(ptApiRegistry, plStatsI); - gptExample = pl_get_api_latest(ptApiRegistry, plExampleI); - gptTools = pl_get_api_latest(ptApiRegistry, plToolsI); - gptImage = pl_get_api_latest(ptApiRegistry, plImageI); - gptGpuAllocators = pl_get_api_latest(ptApiRegistry, plGPUAllocatorsI); - gptJob = pl_get_api_latest(ptApiRegistry, plJobI); - gptThreads = pl_get_api_latest(ptApiRegistry, plThreadsI); - gptAtomics = pl_get_api_latest(ptApiRegistry, plAtomicsI); - gptRect = pl_get_api_latest(ptApiRegistry, plRectPackI); - gptFile = pl_get_api_latest(ptApiRegistry, plFileI); - gptNetwork = pl_get_api_latest(ptApiRegistry, plNetworkI); - gptString = pl_get_api_latest(ptApiRegistry, plStringInternI); - gptLibrary = pl_get_api_latest(ptApiRegistry, plLibraryI); - gptLog = pl_get_api_latest(ptApiRegistry, plLogI); - gptVirtualMemory = pl_get_api_latest(ptApiRegistry, plVirtualMemoryI); - gptConsole = pl_get_api_latest(ptApiRegistry, plConsoleI); - gptScreenLog = pl_get_api_latest(ptApiRegistry, plScreenLogI); + // load required apis + gptIO = pl_get_api_latest(ptApiRegistry, plIOI); + gptWindows = pl_get_api_latest(ptApiRegistry, plWindowI); + + // load required apis (these are provided though extensions) + gptDraw = pl_get_api_latest(ptApiRegistry, plDrawI); + gptStarter = pl_get_api_latest(ptApiRegistry, plStarterI); + gptUI = pl_get_api_latest(ptApiRegistry, plUiI); + gptScreenLog = pl_get_api_latest(ptApiRegistry, plScreenLogI); + gptProfile = pl_get_api_latest(ptApiRegistry, plProfileI); + gptStats = pl_get_api_latest(ptApiRegistry, plStatsI); + gptMemory = pl_get_api_latest(ptApiRegistry, plMemoryI); + gptLog = pl_get_api_latest(ptApiRegistry, plLogI); + gptConsole = pl_get_api_latest(ptApiRegistry, plConsoleI); + + // out extension + gptExample = pl_get_api_latest(ptApiRegistry, plExampleI); + + gptExample->print_to_console("Hello from example extension"); // this path is taken only during first load, so we // allocate app memory here ptAppData = PL_ALLOC(sizeof(plAppData)); memset(ptAppData, 0, sizeof(plAppData)); - // add console variables - gptConsole->initialize((plConsoleSettings){.tFlags = PL_CONSOLE_FLAGS_POPUP}); + // default values + ptAppData->bShowHelpWindow = true; // use window API to create a window plWindowDesc tWindowDesc = { - .pcTitle = "App Template", + .pcTitle = "Template App", .iXPos = 200, .iYPos = 200, - .uWidth = 500, - .uHeight = 500, + .uWidth = 600, + .uHeight = 600, }; - gptWindows->create_window(tWindowDesc, &ptAppData->ptWindow); + gptWindows->create(tWindowDesc, &ptAppData->ptWindow); + gptWindows->show(ptAppData->ptWindow); - // setup graphics extension - pl__setup_graphics_extensions(ptAppData); + // initialize the starter API (handles alot of boilerplate) + plStarterInit tStarterInit = { + .tFlags = PL_STARTER_FLAGS_ALL_EXTENSIONS, + .ptWindow = ptAppData->ptWindow + }; + gptStarter->initialize(tStarterInit); + gptStarter->finalize(); - // initialize APIs that require it - gptTools->initialize((plToolsInit){.ptDevice = ptAppData->ptDevice}); + // add a log channel + ptAppData->uExampleLogChannel = gptLog->add_channel("Example 2", (plLogExtChannelInit){.tType = PL_LOG_CHANNEL_TYPE_BUFFER}); - // retrieve some console variables - ptAppData->pbShowLogging = (bool*)gptConsole->get_variable("t.LogTool", NULL, NULL); - ptAppData->pbShowStats = (bool*)gptConsole->get_variable("t.StatTool", NULL, NULL); - ptAppData->pbShowProfiling = (bool*)gptConsole->get_variable("t.ProfileTool", NULL, NULL); - ptAppData->pbShowMemoryAllocations = (bool*)gptConsole->get_variable("t.MemoryAllocationTool", NULL, NULL); - ptAppData->pbShowDeviceMemoryAnalyzer = (bool*)gptConsole->get_variable("t.DeviceMemoryAnalyzerTool", NULL, NULL); - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~setup draw extensions~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - // initialize - gptDraw->initialize(NULL); - gptDrawBackend->initialize(ptAppData->ptDevice); - - // create font atlas - plFontAtlas* ptAtlas = gptDraw->create_font_atlas(); - gptDraw->set_font_atlas(ptAtlas); - ptAppData->ptDefaultFont = gptDraw->add_default_font(ptAtlas); - - // build font atlas - plCommandPool* ptCmdPool = ptAppData->atCmdPools[gptGfx->get_current_frame_index()]; - plCommandBuffer* ptCmdBuffer = gptGfx->request_command_buffer(ptCmdPool); - gptDrawBackend->build_font_atlas(ptCmdBuffer, ptAtlas); - gptGfx->return_command_buffer(ptCmdBuffer); - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~message extension~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - gptScreenLog->initialize((plScreenLogSettings){.ptFont = ptAppData->ptDefaultFont}); - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ui extension~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - gptUi->initialize(); - gptUi->set_default_font(ptAppData->ptDefaultFont); - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~app stuff~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - // create drawlist and some layers to draw to - ptAppData->ptDrawlist = gptDraw->request_2d_drawlist(); - ptAppData->ptFGLayer = gptDraw->request_2d_layer(ptAppData->ptDrawlist); - ptAppData->ptBGLayer = gptDraw->request_2d_layer(ptAppData->ptDrawlist); - - // demonstrate example extension - gptExample->print_to_console("From example extension!"); + // add a console variable + gptConsole->add_toggle_variable("a.HelpWindow", &ptAppData->bShowHelpWindow, "toggle help window", PL_CONSOLE_VARIABLE_FLAGS_NONE); // return app memory return ptAppData; @@ -305,23 +231,8 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData) PL_EXPORT void pl_app_shutdown(plAppData* ptAppData) { - // ensure GPU is finished before cleanup - gptGfx->flush_device(ptAppData->ptDevice); - for(uint32_t i = 0; i < gptGfx->get_frames_in_flight(); i++) - { - gptGfx->cleanup_command_pool(ptAppData->atCmdPools[i]); - gptGfx->cleanup_semaphore(ptAppData->aptSemaphores[i]); - } - gptDrawBackend->cleanup_font_atlas(NULL); - gptUi->cleanup(); - gptDrawBackend->cleanup(); - gptScreenLog->cleanup(); - gptConsole->cleanup(); - gptGfx->cleanup_swapchain(ptAppData->ptSwapchain); - gptGfx->cleanup_surface(ptAppData->ptSurface); - gptGfx->cleanup_device(ptAppData->ptDevice); - gptGfx->cleanup(); - gptWindows->destroy_window(ptAppData->ptWindow); + gptStarter->cleanup(); + gptWindows->destroy(ptAppData->ptWindow); PL_FREE(ptAppData); } @@ -332,7 +243,7 @@ pl_app_shutdown(plAppData* ptAppData) PL_EXPORT void pl_app_resize(plAppData* ptAppData) { - pl__resize_graphics_extensions(ptAppData); + gptStarter->resize(); } //----------------------------------------------------------------------------- @@ -342,284 +253,88 @@ pl_app_resize(plAppData* ptAppData) PL_EXPORT void pl_app_update(plAppData* ptAppData) { - gptProfile->begin_frame(); - pl_begin_cpu_sample(gptProfile, 0, __FUNCTION__); - - // for convience - plIO* ptIO = gptIO->get_io(); - - // new frame stuff - gptIO->new_frame(); - gptDrawBackend->new_frame(); - gptUi->new_frame(); - gptStats->new_frame(); - gptGfx->begin_frame(ptAppData->ptDevice); - plCommandPool* ptCmdPool = ptAppData->atCmdPools[gptGfx->get_current_frame_index()]; - gptGfx->reset_command_pool(ptCmdPool, 0); - - // update statistics - static double* pdFrameTimeCounter = NULL; - if(!pdFrameTimeCounter) - pdFrameTimeCounter = gptStats->get_counter("frametime (ms)"); - *pdFrameTimeCounter = (double)ptIO->fDeltaTime * 1000.0; - - // acquire swapchain image - if(!gptGfx->acquire_swapchain_image(ptAppData->ptSwapchain)) - { - pl_app_resize(ptAppData); - pl_end_cpu_sample(gptProfile, 0); - gptProfile->end_frame(); + // this needs to be the first call when using the starter + // extension. You must return if it returns false (usually a swapchain recreation). + if(!gptStarter->begin_frame()) return; - } - // just some drawing - gptDraw->add_circle(ptAppData->ptFGLayer, (plVec2){100.0f, 100.0f}, 50.0f, 12, (plDrawLineOptions){.fThickness = 2.0f, .uColor = PL_COLOR_32_RGBA(1.0f, 0.0f, 1.0f, 1.0f)}); - - if(gptIO->is_key_pressed(PL_KEY_F1, false)) - gptConsole->open(); - - gptConsole->update(); - - if(gptUi->begin_window("Pilot Light", NULL, false)) - { - - const float pfRatios[] = {1.0f}; - gptUi->layout_row(PL_UI_LAYOUT_ROW_TYPE_DYNAMIC, 0.0f, 1, pfRatios); - if(gptUi->begin_collapsing_header("Information", 0)) - { - - gptUi->text("Pilot Light %s", PILOT_LIGHT_VERSION_STRING); - gptUi->end_collapsing_header(); - } - if(gptUi->begin_collapsing_header("Tools", 0)) - { - gptUi->checkbox("Device Memory Analyzer", ptAppData->pbShowDeviceMemoryAnalyzer); - gptUi->checkbox("Memory Allocations", ptAppData->pbShowMemoryAllocations); - gptUi->checkbox("Profiling", ptAppData->pbShowProfiling); - gptUi->checkbox("Statistics", ptAppData->pbShowStats); - gptUi->checkbox("Logging", ptAppData->pbShowLogging); - gptUi->end_collapsing_header(); - } - if(gptUi->begin_collapsing_header("User Interface", 0)) - { - gptUi->checkbox("UI Debug", &ptAppData->bShowUiDebug); - gptUi->checkbox("UI Style", &ptAppData->bShowUiStyle); - gptUi->end_collapsing_header(); - } - gptUi->end_window(); - } - - if(ptAppData->bShowUiStyle) - gptUi->show_style_editor_window(&ptAppData->bShowUiStyle); - - if(ptAppData->bShowUiDebug) - gptUi->show_debug_window(&ptAppData->bShowUiDebug); - - gptTools->update(); - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~graphics work~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - const uint32_t uCurrentFrameIndex = gptGfx->get_current_frame_index(); - - plCommandBuffer* ptCommandBuffer = gptGfx->request_command_buffer(ptCmdPool); - - const plBeginCommandInfo tBeginInfo = { - .uWaitSemaphoreCount = 1, - .atWaitSempahores = {ptAppData->aptSemaphores[uCurrentFrameIndex]}, - .auWaitSemaphoreValues = {ptAppData->aulNextTimelineValue[uCurrentFrameIndex]}, - }; - gptGfx->begin_command_recording(ptCommandBuffer, &tBeginInfo); - - // begin main renderpass (directly to swapchain) - plRenderEncoder* ptEncoder = gptGfx->begin_render_pass(ptCommandBuffer, ptAppData->tMainRenderPass, NULL); - - // submit our layers & drawlist - gptDraw->submit_2d_layer(ptAppData->ptBGLayer); - gptDraw->submit_2d_layer(ptAppData->ptFGLayer); - gptDrawBackend->submit_2d_drawlist(ptAppData->ptDrawlist, ptEncoder, ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y, gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount); + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~stats API~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // submits UI layers - gptUi->end_frame(); + // rather than have to lookup the counter every frame, its best to "store" it + // like this. To update it, just deference it and set the value. + static double* pdExample2Counter = NULL; + if(!pdExample2Counter) + pdExample2Counter = gptStats->get_counter("example 2 counter"); - // submit UI drawlists - gptDrawBackend->submit_2d_drawlist(gptUi->get_draw_list(), ptEncoder, ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y, gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount); - gptDrawBackend->submit_2d_drawlist(gptUi->get_debug_draw_list(), ptEncoder, ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y, gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount); + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~drawing & profile API~~~~~~~~~~~~~~~~~~~~~~~~~~~ - plDrawList2D* ptMessageDrawlist = gptScreenLog->get_drawlist(ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y); - gptDrawBackend->submit_2d_drawlist(ptMessageDrawlist, ptEncoder, ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y, gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount); + gptProfile->begin_sample(0, "example drawing"); + + plDrawLayer2D* ptFGLayer = gptStarter->get_foreground_layer(); + gptDraw->add_line(ptFGLayer, + (plVec2){0.0f, 0.0f}, + (plVec2){500.0f, 500.0f}, (plDrawLineOptions){ .fThickness = 1.0f, .uColor = PL_COLOR_32_MAGENTA}); + plDrawLayer2D* ptBGLayer = gptStarter->get_background_layer(); + gptDraw->add_triangle_filled(ptBGLayer, + (plVec2){50.0f, 100.0f}, + (plVec2){200.0f}, + (plVec2){100.0f, 200.0f}, (plDrawSolidOptions){.uColor = PL_COLOR_32_RGBA(0.0f, 0.5f, 1.0f, 0.5f)}); - // end render pass - gptGfx->end_render_pass(ptEncoder); + gptProfile->end_sample(0); - // end recording - gptGfx->end_command_recording(ptCommandBuffer); + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~UI & Screen Log API~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - //~~~~~~~~~~~~~~~~~~~~~~~~~~submit work to GPU & present~~~~~~~~~~~~~~~~~~~~~~~ - - const plSubmitInfo tSubmitInfo = { - .uSignalSemaphoreCount = 1, - .atSignalSempahores = {ptAppData->aptSemaphores[uCurrentFrameIndex]}, - .auSignalSemaphoreValues = {++ptAppData->aulNextTimelineValue[uCurrentFrameIndex]}, - }; - - if(!gptGfx->present(ptCommandBuffer, &tSubmitInfo, &ptAppData->ptSwapchain, 1)) - pl_app_resize(ptAppData); - - gptGfx->return_command_buffer(ptCommandBuffer); - - pl_end_cpu_sample(gptProfile, 0); - gptProfile->end_frame(); -} - -//----------------------------------------------------------------------------- -// [SECTION] helper functions implementations -//----------------------------------------------------------------------------- - -void -pl__setup_graphics_extensions(plAppData* ptAppData) -{ - // initialize shader extension (shader compiler) - static const plShaderOptions tDefaultShaderOptions = { - .apcIncludeDirectories = { - "../shaders/" - }, - .apcDirectories = { - "../shaders/" - }, - .tFlags = PL_SHADER_FLAGS_AUTO_OUTPUT - }; - gptShader->initialize(&tDefaultShaderOptions); - - // initialize graphics system - const plGraphicsInit tGraphicsInit = { - .tFlags = PL_GRAPHICS_INIT_FLAGS_VALIDATION_ENABLED | PL_GRAPHICS_INIT_FLAGS_SWAPCHAIN_ENABLED - }; - gptGfx->initialize(&tGraphicsInit); - ptAppData->ptSurface = gptGfx->create_surface(ptAppData->ptWindow); - - // find suitable device - uint32_t uDeviceCount = 16; - plDeviceInfo atDeviceInfos[16] = {0}; - gptGfx->enumerate_devices(atDeviceInfos, &uDeviceCount); - - // we will prefer discrete, then integrated - int iBestDvcIdx = 0; - int iDiscreteGPUIdx = -1; - int iIntegratedGPUIdx = -1; - for(uint32_t i = 0; i < uDeviceCount; i++) + // creating a window + if(ptAppData->bShowHelpWindow) { - - if(atDeviceInfos[i].tType == PL_DEVICE_TYPE_DISCRETE) - iDiscreteGPUIdx = i; - else if(atDeviceInfos[i].tType == PL_DEVICE_TYPE_INTEGRATED) - iIntegratedGPUIdx = i; - } - - if(iDiscreteGPUIdx > -1) - iBestDvcIdx = iDiscreteGPUIdx; - else if(iIntegratedGPUIdx > -1) - iBestDvcIdx = iIntegratedGPUIdx; - - // create device - const plDeviceInit tDeviceInit = { - .uDeviceIdx = iBestDvcIdx, - .ptSurface = ptAppData->ptSurface - }; - ptAppData->ptDevice = gptGfx->create_device(&tDeviceInit); - - // create command pools - for(uint32_t i = 0; i < gptGfx->get_frames_in_flight(); i++) - ptAppData->atCmdPools[i] = gptGfx->create_command_pool(ptAppData->ptDevice, NULL); - - // create swapchain - plSwapchainInit tSwapInit = { - .tSampleCount = PL_SAMPLE_COUNT_1 - }; - ptAppData->ptSwapchain = gptGfx->create_swapchain(ptAppData->ptDevice, ptAppData->ptSurface, &tSwapInit); - - uint32_t uImageCount = 0; - plTextureHandle* atSwapchainImages = gptGfx->get_swapchain_images(ptAppData->ptSwapchain, &uImageCount); - - // create main render pass layout - const plRenderPassLayoutDesc tMainRenderPassLayoutDesc = { - .atRenderTargets = { - { .tFormat = gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tFormat }, // swapchain - }, - .atSubpasses = { - { - .uRenderTargetCount = 1, - .auRenderTargets = {0} - } - }, - .atSubpassDependencies = { - { - .uSourceSubpass = UINT32_MAX, - .uDestinationSubpass = 0, - .tSourceStageMask = PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS | PL_PIPELINE_STAGE_COMPUTE_SHADER, - .tDestinationStageMask = PL_PIPELINE_STAGE_FRAGMENT_SHADER | PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS, - .tSourceAccessMask = PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ, - .tDestinationAccessMask = PL_ACCESS_SHADER_READ | PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ, - }, - { - .uSourceSubpass = 0, - .uDestinationSubpass = UINT32_MAX, - .tSourceStageMask = PL_PIPELINE_STAGE_FRAGMENT_SHADER | PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS, - .tDestinationStageMask = PL_PIPELINE_STAGE_FRAGMENT_SHADER | PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS | PL_PIPELINE_STAGE_COMPUTE_SHADER, - .tSourceAccessMask = PL_ACCESS_SHADER_READ | PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ, - .tDestinationAccessMask = PL_ACCESS_SHADER_READ | PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ, - }, + if(gptUI->begin_window("Help", NULL, PL_UI_WINDOW_FLAGS_AUTO_SIZE | PL_UI_WINDOW_FLAGS_NO_COLLAPSE)) + { + gptUI->layout_static(0.0f, 500.0f, 1); + gptUI->text("Press F1 to bring up console."); + gptUI->text("Look for t.StatsTool (we added a stat)"); + gptUI->text("Look for t.LogTool (we added a log channel)"); + gptUI->text("Look for t.ProfileTool"); + gptUI->text("Look for t.MemoryAllocationTool and look for example 2!"); + gptUI->text("Look for a.HelpWindow (console variable we added)"); + gptUI->end_window(); } - }; - ptAppData->tMainRenderPassLayout = gptGfx->create_render_pass_layout(ptAppData->ptDevice, &tMainRenderPassLayoutDesc); - - // create main render pass - const plRenderPassDesc tMainRenderPassDesc = { - .tLayout = ptAppData->tMainRenderPassLayout, - .atColorTargets = { - { - .tLoadOp = PL_LOAD_OP_CLEAR, - .tStoreOp = PL_STORE_OP_STORE, - .tCurrentUsage = PL_TEXTURE_USAGE_UNSPECIFIED, - .tNextUsage = PL_TEXTURE_USAGE_PRESENT, - .tClearColor = {0.0f, 0.0f, 0.0f, 1.0f} - } - }, - .tDimensions = {(float)gptGfx->get_swapchain_info(ptAppData->ptSwapchain).uWidth, (float)gptGfx->get_swapchain_info(ptAppData->ptSwapchain).uHeight}, - .ptSwapchain = ptAppData->ptSwapchain - }; - - plRenderPassAttachments atMainAttachmentSets[16] = {0}; - for(uint32_t i = 0; i < uImageCount; i++) - { - atMainAttachmentSets[i].atViewAttachments[0] = atSwapchainImages[i]; } - ptAppData->tMainRenderPass = gptGfx->create_render_pass(ptAppData->ptDevice, &tMainRenderPassDesc, atMainAttachmentSets); - // create timeline semaphores to syncronize GPU work submission - for(uint32_t i = 0; i < gptGfx->get_frames_in_flight(); i++) - ptAppData->aptSemaphores[i] = gptGfx->create_semaphore(ptAppData->ptDevice, false); -} - -void -pl__resize_graphics_extensions(plAppData* ptAppData) -{ - plIO* ptIO = gptIO->get_io(); - plSwapchainInit tDesc = { - .bVSync = true, - .uWidth = (uint32_t)ptIO->tMainViewportSize.x, - .uHeight = (uint32_t)ptIO->tMainViewportSize.y, - .tSampleCount = gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount, - }; - gptGfx->recreate_swapchain(ptAppData->ptSwapchain, &tDesc); - - uint32_t uImageCount = 0; - plTextureHandle* atSwapchainImages = gptGfx->get_swapchain_images(ptAppData->ptSwapchain, &uImageCount); - - plRenderPassAttachments atMainAttachmentSets[16] = {0}; - for(uint32_t i = 0; i < uImageCount; i++) + // creating another window + if(gptUI->begin_window("Pilot Light", NULL, PL_UI_WINDOW_FLAGS_NONE)) { - atMainAttachmentSets[i].atViewAttachments[0] = atSwapchainImages[i]; + gptUI->text("Pilot Light %s", PILOT_LIGHT_VERSION_STRING); + + if(gptUI->button("Log")) + { + gptLog->trace(ptAppData->uExampleLogChannel, "Log"); + gptLog->debug(ptAppData->uExampleLogChannel, "Log"); + gptLog->info(ptAppData->uExampleLogChannel, "Log"); + gptLog->warn(ptAppData->uExampleLogChannel, "Log"); + gptLog->error(ptAppData->uExampleLogChannel, "Log"); + gptLog->fatal(ptAppData->uExampleLogChannel, "Log"); + } + + static int iCounter = 0; + gptUI->slider_int("Stat Counter Example", &iCounter, -10, 10, 0); + *pdExample2Counter = iCounter; // setting our stat variable + + gptUI->layout_row_begin(PL_UI_LAYOUT_ROW_TYPE_DYNAMIC, 0.0f, 2); // got to pl_ui_ext.h to see layout systems + + gptUI->layout_row_push(0.3f); + if(gptUI->button("Log To Screen")) + gptScreenLog->add_message(5.0, "Cool Message!"); + + gptUI->layout_row_push(0.3f); + if(gptUI->button("Big Log To Screen")) + gptScreenLog->add_message_ex(0, 5, PL_COLOR_32_GREEN, 3.0f, "%s", "Bigger & Greener!"); + + gptUI->layout_row_end(); + + gptUI->end_window(); } - gptGfx->update_render_pass_attachments(ptAppData->ptDevice, ptAppData->tMainRenderPass, gptIO->get_io()->tMainViewportSize, atMainAttachmentSets); + + // must be the last function called when using the starter extension + gptStarter->end_frame(); }