blob: dc343fa64986e909f54fdb5b0337274528454332 [file] [log] [blame]
// Viewer & Rive
#include "viewer/viewer.hpp"
#include "viewer/viewer_content.hpp"
#include "viewer/viewer_host.hpp"
#include "rive/shapes/paint/color.hpp"
// Graphics and UI abstraction
#include "sokol_app.h"
#include "sokol_gfx.h"
#include "sokol_glue.h"
#include "imgui.h"
#include "util/sokol_imgui.h"
// Std lib
#include <stdio.h>
#include <memory>
#include <chrono>
std::unique_ptr<ViewerHost> g_Host = ViewerHost::Make();
std::unique_ptr<ViewerContent> g_Content = ViewerContent::TrimPath("");
static struct
{
sg_pass_action pass_action;
} state;
void displayStats();
static const int backgroundColor = rive::colorARGB(255, 22, 22, 22);
static std::chrono::time_point<std::chrono::high_resolution_clock> lastTime;
static const float billion = 1000000000.0;
static void init(void)
{
sg_desc descriptor = {
.context = sapp_sgcontext(),
.buffer_pool_size = 1024,
.pipeline_pool_size = 1024,
};
sg_setup(&descriptor);
simgui_desc_t imguiDescriptor = {
.write_alpha_channel = true,
};
simgui_setup(&imguiDescriptor);
// If the host doesn't overwrite this (in init()), Sokol is in full control,
// so let's clear to our bg color.
state.pass_action = (sg_pass_action){
.colors[0] =
{
.action = SG_ACTION_CLEAR,
.value =
{
rive::colorRed(backgroundColor) / 255.0f,
rive::colorGreen(backgroundColor) / 255.0f,
rive::colorBlue(backgroundColor) / 255.0f,
rive::colorOpacity(backgroundColor),
},
},
.stencil =
{
.action = SG_ACTION_CLEAR,
},
};
lastTime = std::chrono::high_resolution_clock::now();
if (!g_Host->init(&state.pass_action, sapp_width(), sapp_height()))
{
fprintf(stderr, "failed to initialize host\n");
sapp_quit();
}
}
static void frame(void)
{
auto newTime = std::chrono::high_resolution_clock::now();
auto dur =
std::chrono::duration_cast<std::chrono::nanoseconds>(newTime - lastTime).count() / billion;
lastTime = newTime;
g_Host->beforeDefaultPass(g_Content.get(), dur);
sg_begin_default_pass(&state.pass_action, sapp_width(), sapp_height());
g_Host->afterDefaultPass(g_Content.get(), dur);
simgui_frame_desc_t imguiDesc = {
.width = sapp_width(),
.height = sapp_height(),
.delta_time = sapp_frame_duration(),
.dpi_scale = sapp_dpi_scale(),
};
simgui_new_frame(&imguiDesc);
displayStats();
if (g_Content)
{
g_Content->handleImgui();
}
simgui_render();
sg_end_pass();
sg_commit();
}
static void cleanup(void)
{
g_Content = nullptr;
g_Host = nullptr;
simgui_shutdown();
sg_shutdown();
}
static void event(const sapp_event* ev)
{
simgui_handle_event(ev);
switch (ev->type)
{
case SAPP_EVENTTYPE_RESIZED:
if (g_Content)
{
g_Content->handleResize(ev->framebuffer_width, ev->framebuffer_height);
}
g_Host->handleResize(ev->framebuffer_width, ev->framebuffer_height);
break;
case SAPP_EVENTTYPE_FILES_DROPPED:
{
// Do this to make sure the graphics is bound.
bindGraphicsContext();
// get the number of files and their paths like this:
const int numDroppedFiles = sapp_get_num_dropped_files();
if (numDroppedFiles != 0)
{
const char* filename = sapp_get_dropped_file_path(numDroppedFiles - 1);
auto newContent = ViewerContent::findHandler(filename);
if (newContent)
{
g_Content = std::move(newContent);
g_Content->handleResize(ev->framebuffer_width, ev->framebuffer_height);
}
else
{
fprintf(stderr, "No handler found for %s\n", filename);
}
}
break;
}
case SAPP_EVENTTYPE_MOUSE_DOWN:
case SAPP_EVENTTYPE_TOUCHES_BEGAN:
if (g_Content)
{
g_Content->handlePointerDown(ev->mouse_x, ev->mouse_y);
}
break;
case SAPP_EVENTTYPE_MOUSE_UP:
case SAPP_EVENTTYPE_TOUCHES_ENDED:
if (g_Content)
{
g_Content->handlePointerUp(ev->mouse_x, ev->mouse_y);
break;
}
case SAPP_EVENTTYPE_MOUSE_MOVE:
case SAPP_EVENTTYPE_TOUCHES_MOVED:
if (g_Content)
{
g_Content->handlePointerMove(ev->mouse_x, ev->mouse_y);
}
break;
case SAPP_EVENTTYPE_KEY_UP:
switch (ev->key_code)
{
case SAPP_KEYCODE_ESCAPE:
sapp_quit();
break;
case SAPP_KEYCODE_T:
g_Content = ViewerContent::Text(".svg");
break;
case SAPP_KEYCODE_P:
g_Content = ViewerContent::TextPath("");
break;
default:
break;
}
break;
default:
break;
}
}
sapp_desc sokol_main(int argc, char* argv[])
{
(void)argc;
(void)argv;
return (sapp_desc)
{
.init_cb = init, .frame_cb = frame, .cleanup_cb = cleanup, .event_cb = event,
.enable_dragndrop = true, .high_dpi = true,
.window_title = "Rive Viewer "
#if defined(SOKOL_GLCORE33)
"(OpenGL 3.3)",
#elif defined(SOKOL_GLES2)
"(OpenGL ES 2)",
#elif defined(SOKOL_GLES3)
"(OpenGL ES 3)",
#elif defined(SOKOL_D3D11)
"(D3D11)",
#elif defined(SOKOL_METAL)
"(Metal)",
#elif defined(SOKOL_WGPU)
"(WebGPU)",
#endif
.width = 800, .height = 600, .icon.sokol_default = true, .gl_force_gles2 = true,
};
}