5 #include <GLFW/glfw3.h>
7 #include "GrBackendSurface.h"
8 #include "GrDirectContext.h"
10 #include "SkColorSpace.h"
11 #include "SkSurface.h"
13 #include "gl/GrGLInterface.h"
15 #include "rive/animation/linear_animation_instance.hpp"
16 #include "rive/animation/state_machine_instance.hpp"
17 #include "rive/animation/state_machine_input_instance.hpp"
18 #include "rive/animation/state_machine_number.hpp"
19 #include "rive/animation/state_machine_bool.hpp"
20 #include "rive/animation/state_machine_trigger.hpp"
21 #include "rive/artboard.hpp"
22 #include "rive/file.hpp"
23 #include "rive/layout.hpp"
24 #include "rive/math/aabb.hpp"
25 #include "skia_factory.hpp"
26 #include "skia_renderer.hpp"
31 rive::SkiaFactory skiaFactory;
34 std::unique_ptr<rive::File> currentFile;
35 std::unique_ptr<rive::ArtboardInstance> artboardInstance;
36 std::unique_ptr<rive::Scene> currentScene;
38 std::vector<std::string> animationNames;
39 std::vector<std::string> stateMachineNames;
42 double GetSecondsToday() {
46 gmtime_r(&m_time, &tstruct);
48 int hours = tstruct.tm_hour - 4;
51 } else if (hours >= 12) {
55 auto secs = (double)hours * 60 * 60 +
56 (double)tstruct.tm_min * 60 +
57 (double)tstruct.tm_sec;
58 // printf("%d %d %d\n", tstruct.tm_sec, tstruct.tm_min, hours);
59 // printf("%g %g %g\n", secs, secs/60, secs/60/60);
63 std::vector<uint8_t> fileBytes;
65 int animationIndex = 0;
66 int stateMachineIndex = -1;
68 static void loadNames(const rive::Artboard* ab) {
69 animationNames.clear();
70 stateMachineNames.clear();
72 for (size_t i = 0; i < ab->animationCount(); ++i) {
73 animationNames.push_back(ab->animationNameAt(i));
75 for (size_t i = 0; i < ab->stateMachineCount(); ++i) {
76 stateMachineNames.push_back(ab->stateMachineNameAt(i));
81 static void initAnimation(int index) {
82 animationIndex = index;
83 stateMachineIndex = -1;
84 assert(fileBytes.size() != 0);
85 auto file = rive::File::import(rive::toSpan(fileBytes), &skiaFactory);
88 fprintf(stderr, "failed to import file\n");
91 currentScene = nullptr;
92 artboardInstance = nullptr;
94 currentFile = std::move(file);
95 artboardInstance = currentFile->artboardDefault();
96 artboardInstance->advance(0.0f);
97 loadNames(artboardInstance.get());
99 if (index >= 0 && index < artboardInstance->animationCount()) {
100 currentScene = artboardInstance->animationAt(index);
101 currentScene->inputCount();
106 rive::Mat2D gInverseViewTransform;
107 rive::Vec2D lastWorldMouse;
108 static void glfwCursorPosCallback(GLFWwindow* window, double x, double y) {
109 float xscale, yscale;
110 glfwGetWindowContentScale(window, &xscale, &yscale);
111 lastWorldMouse = gInverseViewTransform * rive::Vec2D(x * xscale, y * yscale);
113 currentScene->pointerMove(lastWorldMouse);
116 static void glfwMouseButtonCallback(GLFWwindow* window, int button, int action, int mods) {
120 currentScene->pointerDown(lastWorldMouse);
123 currentScene->pointerUp(lastWorldMouse);
129 static void glfwErrorCallback(int error, const char* description) {
133 static void glfwDropCallback(GLFWwindow* window, int count, const char** paths) {
135 FILE* fp = fopen(filename.c_str(), "rb");
136 fseek(fp, 0, SEEK_END);
137 size_t size = ftell(fp);
138 fseek(fp, 0, SEEK_SET);
139 fileBytes.resize(size);
140 if (fread(fileBytes.data(), 1, size, fp) != size) {
142 fprintf(stderr, "failed to read all of %s\n", filename.c_str());
145 printf("Loaded %s file succesfully.\n", filename.c_str());
151 fprintf(stderr, "Failed to initialize glfw.\n");
154 glfwSetErrorCallback(glfwErrorCallback);
156 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
157 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
158 GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Rive-skia GPU Viewer", NULL, NULL);
159 if (window == nullptr) {
160 fprintf(stderr, "Failed to make window or GL.\n");
165 glfwSetDropCallback(window, glfwDropCallback);
166 glfwSetCursorPosCallback(window, glfwCursorPosCallback);
167 glfwSetMouseButtonCallback(window, glfwMouseButtonCallback);
168 glfwMakeContextCurrent(window);
174 GrContextOptions options;
175 sk_sp<GrDirectContext> context = GrDirectContext::MakeGL(nullptr, options);
176 GrGLFramebufferInfo framebufferInfo;
177 framebufferInfo.fFBOID = 0;
178 framebufferInfo.fFormat = GL_RGBA8;
180 sk_sp<SkSurface> surface;
181 SkCanvas* canvas = nullptr;
183 int width = 0, height = 0;
184 int lastScreenWidth = 0, lastScreenHeight = 0;
186 double lastTime = glfwGetTime();
188 static constexpr SkAlphaType at = kPremul_SkAlphaType;
189 const SkImageInfo info = SkImageInfo::MakeN32(WIDTH, HEIGHT, at);
191 printf("Viewer loaded. Drag and drop .riv file to load.\n");
193 while (!glfwWindowShouldClose(window)) {
194 glfwGetFramebufferSize(window, &width, &height);
196 if (!surface || width != lastScreenWidth || height != lastScreenHeight) {
197 lastScreenWidth = width;
198 lastScreenHeight = height;
200 SkColorType colorType = kRGBA_8888_SkColorType;
202 GrBackendRenderTarget backendRenderTarget(width,
208 surface = SkSurface::MakeFromBackendRenderTarget(context.get(),
210 kBottomLeft_GrSurfaceOrigin,
216 fprintf(stderr, "Failed to create Skia surface\n");
220 canvas = surface->getCanvas();
223 double time = glfwGetTime();
224 float elapsed = (float)(time - lastTime);
228 paint.setColor(SK_ColorGRAY);
229 canvas->drawPaint(paint);
232 if (auto num = currentScene->getNumber("isTime")) {
233 num->value(GetSecondsToday()/60/60);
236 currentScene->advanceAndApply(elapsed);
238 rive::SkiaRenderer renderer(canvas);
241 auto viewTransform = rive::computeAlignment(rive::Fit::contain,
242 rive::Alignment::center,
243 rive::AABB(0, 0, width, height),
244 currentScene->bounds());
245 renderer.transform(viewTransform);
246 gInverseViewTransform = viewTransform.invertOrIdentity();
248 currentScene->draw(&renderer);
253 glfwSwapBuffers(window);
257 glfwDestroyWindow(window);