diff --git a/selfdrive/common/spinner.c b/selfdrive/common/spinner.c new file mode 100644 index 00000000000000..c8bfde8c7d63a0 --- /dev/null +++ b/selfdrive/common/spinner.c @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "nanovg.h" +#define NANOVG_GLES3_IMPLEMENTATION +#include "nanovg_gl.h" +#include "nanovg_gl_utils.h" + +#include "framebuffer.h" +#include "spinner.h" + +// external resources linked in +extern const unsigned char _binary_opensans_semibold_ttf_start[]; +extern const unsigned char _binary_opensans_semibold_ttf_end[]; + +extern const unsigned char _binary_img_spinner_track_png_start[]; +extern const unsigned char _binary_img_spinner_track_png_end[]; + +extern const unsigned char _binary_img_spinner_comma_png_start[]; +extern const unsigned char _binary_img_spinner_comma_png_end[]; + +int spin(int argc, char** argv) { + int err; + + const char* spintext = NULL; + if (argc == 1) { + spintext = argv[0]; + } else if (argc >= 2) { + spintext = argv[1]; + } + + // spinner + int fb_w, fb_h; + EGLDisplay display; + EGLSurface surface; + FramebufferState *fb = framebuffer_init("spinner", 0x00001000, false, + &display, &surface, &fb_w, &fb_h); + assert(fb); + + NVGcontext *vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES); + assert(vg); + + int font = nvgCreateFontMem(vg, "Bold", (unsigned char*)_binary_opensans_semibold_ttf_start, _binary_opensans_semibold_ttf_end-_binary_opensans_semibold_ttf_start, 0); + assert(font >= 0); + + int spinner_img = nvgCreateImageMem(vg, 0, (unsigned char*)_binary_img_spinner_track_png_start, _binary_img_spinner_track_png_end - _binary_img_spinner_track_png_start); + assert(spinner_img >= 0); + int spinner_img_s = 360; + int spinner_img_x = ((fb_w/2)-(spinner_img_s/2)); + int spinner_img_y = 260; + int spinner_img_xc = (fb_w/2); + int spinner_img_yc = (fb_h/2)-100; + int spinner_comma_img = nvgCreateImageMem(vg, 0, (unsigned char*)_binary_img_spinner_comma_png_start, _binary_img_spinner_comma_png_end - _binary_img_spinner_comma_png_start); + assert(spinner_comma_img >= 0); + + for (int cnt = 0; ; cnt++) { + glClearColor(0.1, 0.1, 0.1, 1.0); + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + nvgBeginFrame(vg, fb_w, fb_h, 1.0f); + + // background + nvgBeginPath(vg); + NVGpaint bg = nvgLinearGradient(vg, fb_w, 0, fb_w, fb_h, + nvgRGBA(0, 0, 0, 175), nvgRGBA(0, 0, 0, 255)); + nvgFillPaint(vg, bg); + nvgRect(vg, 0, 0, fb_w, fb_h); + nvgFill(vg); + + // spin track + nvgSave(vg); + nvgTranslate(vg, spinner_img_xc, spinner_img_yc); + nvgRotate(vg, (3.75*M_PI * cnt/120.0)); + nvgTranslate(vg, -spinner_img_xc, -spinner_img_yc); + NVGpaint spinner_imgPaint = nvgImagePattern(vg, spinner_img_x, spinner_img_y, + spinner_img_s, spinner_img_s, 0, spinner_img, 0.6f); + nvgBeginPath(vg); + nvgFillPaint(vg, spinner_imgPaint); + nvgRect(vg, spinner_img_x, spinner_img_y, spinner_img_s, spinner_img_s); + nvgFill(vg); + nvgRestore(vg); + + // comma + NVGpaint comma_imgPaint = nvgImagePattern(vg, spinner_img_x, spinner_img_y, + spinner_img_s, spinner_img_s, 0, spinner_comma_img, 1.0f); + nvgBeginPath(vg); + nvgFillPaint(vg, comma_imgPaint); + nvgRect(vg, spinner_img_x, spinner_img_y, spinner_img_s, spinner_img_s); + nvgFill(vg); + + // message + if (spintext) { + nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_TOP); + nvgFontSize(vg, 96.0f); + nvgText(vg, fb_w/2, (fb_h*2/3)+24, spintext, NULL); + } + + nvgEndFrame(vg); + eglSwapBuffers(display, surface); + assert(glGetError() == GL_NO_ERROR); + } + + return 0; +} diff --git a/selfdrive/common/spinner.h b/selfdrive/common/spinner.h new file mode 100644 index 00000000000000..fd35dcc7d48c31 --- /dev/null +++ b/selfdrive/common/spinner.h @@ -0,0 +1,14 @@ +#ifndef COMMON_SPINNER_H +#define COMMON_SPINNER_H + +#ifdef __cplusplus +extern "C" { +#endif + +int spin(int argc, char** argv); + +#ifdef __cplusplus +} +#endif + +#endif