styluslabs / nanovgxc Goto Github PK
View Code? Open in Web Editor NEWLightweight vector graphics library implementing exact-coverage antialiasing in OpenGL
License: Other
Lightweight vector graphics library implementing exact-coverage antialiasing in OpenGL
License: Other
I was trying to compile skia-test on my mingw, but get linking errors like:
Those functions seems to be declared on src/webp/mux.h. And I don't know anything else.
I am not familiar with skia and just install it using pacman -S mingw-w64-x86_64-skia
(the skia version is mingw-w64-x86_64-skia-108.0.5359.95-2
).
Here's my compile command:
g++ glad.c SkiaSDLTest.cpp -lskia -lopengl32 -lglfw3 -lskia -lgdi32 -lSDL2 -lole32 -loleaut32 -ladvapi32 -lsetupapi -limm32 -lwebp -lpng -ljpeg -I./ -IC:\\Workspace\\msys64\\mingw64\\include\\skia g++ glad.c SkiaSDLTest.cpp -lskia -lopengl32 -lglfw3 -lskia -lgdi32 -lSDL2 -lole32 -loleaut32 -ladvapi32 -lsetupapi -limm32 -lwebp -lpng -ljpeg -I./ -IC:\\Workspace\\msys64\\mingw64\\include\\skia
Here's the look of the folder (I copied neccessary headers here):
# ls
glad.c GrGLDefines.h SkiaSDLTest.cpp SkTraceEventCommon.h
glad.h khrplatform.h nanosvg.h SkTraceEvent.h
How to compile it correctly ?
add repository skia-test
i tried this but i dont see anything
//
// Created by smallville7123 on 22/3/23.
//
#ifndef NANO_DAW_NANOVG_HOST_H
#define NANO_DAW_NANOVG_HOST_H
#if defined(__ANDROID__)
#include <EGL/egl.h>
#include <GLES3/gl31.h>
#include <GLES3/gl3ext.h>
#include <android/log.h>
#define NVG_LOG(...) __android_log_print(ANDROID_LOG_VERBOSE, "NanoVG", __VA_ARGS__)
#ifdef NANO_CPP
// software
#define NVGSWU_GLES3
// hardware
#define NANOVG_GLES3_IMPLEMENTATION
#endif
#define PLATFORM_MOBILE 1
#elif defined(__UNIX__)
#include <stdio.h>
#define NVG_LOG(...) { printf("nanovg: "); printf(__VA_ARGS__); }
#ifdef NANO_CPP
// software
#define NVGSWU_GL3
// hardware
#define NANOVG_GL3_IMPLEMENTATION
#endif
#define PLATFORM_MOBILE 0
#error unix OpenGL headers not yet found
#else
#error unknown platform
#endif
#include "nanovgXC/src/nanovg.h"
#include <mutex>
#include "nanovgXC/src/nanovg_gl.h"
#include "nanovgXC/src/nanovg_gl_utils.h"
#include "nanovgXC/src/nanovg_sw.h"
#include <nanovgXC/src/nanovg_sw_utils.h>
class nanovg_host {
protected:
void onDraw(NVGcontext* context, int w, int h, int pixelRatio);
public:
void resize(int w, int h);
void draw();
void switchRenderer(bool use_software_renderer);
private:
bool need_recreate = true;
bool is_software = true;
void recreate_locked(int w, int h);
std::mutex lock;
NVGcontext* context = nullptr;
NVGSWUblitter* software_renderer__blitter = nullptr;
void* software_renderer__framebuffer = nullptr;
NVGLUframebuffer* hardware_renderer__framebuffer = nullptr;
int hardware_renderer__previous_framebuffer = 0;
int w = 0, h = 0;
};
#endif //NANO_DAW_NANOVG_HOST_H
//
// Created by smallville7123 on 22/3/23.
//
#define NANO_CPP
#define NANOVG_SW_IMPLEMENTATION
#define NANOVG_GLES3_IMPLEMENTATION
#include "nanovg_host.h"
void nanovg_host::resize(int w, int h) {
lock.lock();
if (context == nullptr) {
need_recreate = true;
}
if (need_recreate || this->w != w || this->h != h) {
NVG_LOG("resizing");
if (need_recreate) {
recreate_locked(w, h);
NVG_LOG("recreated while resizing");
need_recreate = false;
}
if (is_software) {
if (!software_renderer__framebuffer || w != software_renderer__blitter->width ||
h != software_renderer__blitter->height) {
free(software_renderer__framebuffer);
software_renderer__framebuffer = malloc(w * h * 4);
}
#if __ANDROID__
// ARGB
memset(software_renderer__framebuffer, 0xFF000000, w * h * 4);
#else
// RGBA
memset(software_renderer__framebuffer, 0x00000000FF, w * h * 4);
#endif
nvgswSetFramebuffer(context, software_renderer__framebuffer, w, h, 0, 8, 16, 24);
} else {
hardware_renderer__previous_framebuffer = nvgluBindFramebuffer(
hardware_renderer__framebuffer);
nvgluSetFramebufferSize(hardware_renderer__framebuffer, w, h, 0);
}
nvgluSetViewport(0, 0, w, h);
this->w = w;
this->h = h;
}
lock.unlock();
}
void nanovg_host::recreate_locked(int w, int h) {
NVG_LOG("recreating");
if (context == nullptr) {
int flags = NVG_SRGB | NVG_ROTATED_TEXT_AS_PATHS | NVG_AUTOW | NVG_DEBUG;
if (is_software) {
software_renderer__blitter = nvgswuCreateBlitter();
context = nvgswCreate(flags | NVGSW_PATHS_XC);
// have to set pixel format before loading any images
nvgswSetFramebuffer(context, nullptr, w, h, 0, 8, 16, 24);
} else {
context = nvglCreate(flags);
hardware_renderer__framebuffer = nvgluCreateFramebuffer(context, 0, 0,
NVGLU_NO_NVG_IMAGE);
}
} else {
nvglDelete(context);
context = nullptr;
if (is_software) {
if (software_renderer__blitter) {
free(software_renderer__framebuffer);
software_renderer__framebuffer = nullptr;
nvgswuDeleteBlitter(software_renderer__blitter);
software_renderer__blitter = nullptr;
}
} else {
nvgluDeleteFramebuffer(hardware_renderer__framebuffer);
hardware_renderer__framebuffer = nullptr;
}
recreate_locked(w, h);
}
}
void nanovg_host::draw() {
lock.lock();
nvgluBindFBO(0);
nvgluSetViewport(0, 0, w, h);
glClearColor(0, 0, 0, 1);
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// ensure the framebuffer is always bound before we draw anything
if (is_software) {
nvgswSetFramebuffer(context, software_renderer__framebuffer, w, h, 0, 8, 16, 24);
} else {
nvgluBindFramebuffer(hardware_renderer__framebuffer);
}
auto vg = context;
nvgBeginFrame(vg, w, h, 1);
nvgBeginPath(vg);
nvgMoveTo(vg, 100, 100);
nvgLineTo(vg, 200, 100);
nvgLineTo(vg, 150, 50);
nvgClosePath(vg);
nvgFillColor(vg, nvgRGBA(255,192,0,255));
nvgFill(vg);
nvgEndFrame(vg);
//onDraw(context, this->w, this->h, 1); // pixelRatio = fb width / window width
if (is_software) {
nvgswuBlit(software_renderer__blitter, software_renderer__framebuffer, this->w, this->h, 0, 0, this->w, this->h);
} else {
nvgluBlitFramebuffer(hardware_renderer__framebuffer, 0);
}
lock.unlock();
}
void nanovg_host::switchRenderer(bool use_software_renderer) {
lock.lock();
need_recreate = use_software_renderer != is_software;
is_software = use_software_renderer;
lock.unlock();
}
void nanovg_host::onDraw(NVGcontext *context, int w, int h, int pixelRatio) {
nvgBeginFrame(context, w, h, pixelRatio);
nvgBeginPath(context);
nvgMoveTo(context, 100, 100);
nvgLineTo(context, 200, 100);
nvgLineTo(context, 150, 50);
nvgClosePath(context);
nvgFillColor(context, nvgRGBA(255,255,255,255));
nvgFill(context);
nvgEndFrame(context);
}
#include "Renderer.h"
#include <game-activity/native_app_glue/android_native_app_glue.h>
#include <GLES3/gl3.h>
#include <memory>
#include <vector>
#include <android/imagedecoder.h>
#include "AndroidOut.h"
#include "Shader.h"
#include "Utility.h"
#include "TextureAsset.h"
//! executes glGetString and outputs the result to logcat
#define PRINT_GL_STRING(s) {aout << #s": "<< glGetString(s) << std::endl;}
/*!
* @brief if glGetString returns a space separated list of elements, prints each one on a new line
*
* This works by creating an istringstream of the input c-style string. Then that is used to create
* a vector -- each element of the vector is a new element in the input string. Finally a foreach
* loop consumes this and outputs it to logcat using @a aout
*/
#define PRINT_GL_STRING_AS_LIST(s) { \
std::istringstream extensionStream((const char *) glGetString(s));\
std::vector<std::string> extensionList(\
std::istream_iterator<std::string>{extensionStream},\
std::istream_iterator<std::string>());\
aout << #s":\n";\
for (auto& extension: extensionList) {\
aout << extension << "\n";\
}\
aout << std::endl;\
}
//! Color for cornflower blue. Can be sent directly to glClearColor
#define CORNFLOWER_BLUE 100 / 255.f, 149 / 255.f, 237 / 255.f, 1
Renderer::Renderer(android_app *pApp) :
app_(pApp),
display_(EGL_NO_DISPLAY),
surface_(EGL_NO_SURFACE),
context_(EGL_NO_CONTEXT)
{
initRenderer();
}
void Renderer::initRenderer() {
// Choose your render attributes
constexpr EGLint attribs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_STENCIL_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_NONE
};
// The default display is probably what you want on Android
auto display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, nullptr, nullptr);
// figure out how many configs there are
EGLint numConfigs;
eglChooseConfig(display, attribs, nullptr, 0, &numConfigs);
aout << "found " << numConfigs << " configs" << std::endl;
aout << "listing configs..." << std::endl;
// get the list of configurations
auto * supportedConfigs = new EGLConfig[numConfigs];
eglChooseConfig(display, attribs, supportedConfigs, numConfigs, &numConfigs);
for (int i = 0; i < numConfigs; ++i) {
EGLConfig config = supportedConfigs[i];
EGLint alpha, red, green, blue, depth, stencil;
if (eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red)
&& eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green)
&& eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue)
&& eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha)
&& eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depth)
&& eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencil)
) {
aout << "config[" << i << "] = RED: " << red << ", GREEN: " << green << ", BLUE: " << blue << ", ALPHA: "
<< alpha << ", DEPTH: " << depth << ", STENCIL: " << stencil << std::endl;
}
}
// Find a config we like.
// Could likely just grab the first if we don't care about anything else in the config.
// Otherwise hook in your own heuristic
EGLConfig chosen_config = nullptr;
for (int i = 0; i < numConfigs; ++i) {
aout << "trying config number " << i << std::endl;
EGLConfig config = supportedConfigs[i];
EGLint alpha, red, green, blue, depth, stencil;
if (eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red)
&& eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green)
&& eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue)
&& eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha)
&& eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depth)
&& eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencil)
) {
if (red == 8 && green == 8 && blue == 8 && alpha == 8 && depth == 24 && stencil == 8) {
LOG_INFO("found config that satisfies [ red == 8 && green == 8 && blue == 8 && alpha == 8 && depth == 24 && stencil == 8 ]");
chosen_config = config;
break;
}
}
}
if (chosen_config == nullptr) {
LOG_ALWAYS_FATAL("could not find config that satisfies [ red == 8 && green == 8 && blue == 8 && alpha == 8 && depth == 24 && stencil == 8 ]");
}
// create the proper window surface
EGLint format;
eglGetConfigAttrib(display, chosen_config, EGL_NATIVE_VISUAL_ID, &format);
EGLSurface surface = eglCreateWindowSurface(display, chosen_config, app_->window, nullptr);
// Create a GLES 3 context
EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
EGLContext context = eglCreateContext(display, chosen_config, nullptr, contextAttribs);
delete[] supportedConfigs;
// get some window metrics
auto madeCurrent = eglMakeCurrent(display, surface, surface, context);
assert(madeCurrent);
display_ = display;
surface_ = surface;
context_ = context;
PRINT_GL_STRING(GL_VENDOR);
PRINT_GL_STRING(GL_RENDERER);
PRINT_GL_STRING(GL_VERSION);
PRINT_GL_STRING_AS_LIST(GL_EXTENSIONS);
// enable alpha globally for now, you probably don't want to do this in a game
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
Renderer::~Renderer() {
if (display_ != EGL_NO_DISPLAY) {
eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (context_ != EGL_NO_CONTEXT) {
eglDestroyContext(display_, context_);
context_ = EGL_NO_CONTEXT;
}
if (surface_ != EGL_NO_SURFACE) {
eglDestroySurface(display_, surface_);
surface_ = EGL_NO_SURFACE;
}
eglTerminate(display_);
display_ = EGL_NO_DISPLAY;
}
}
void Renderer::render() {
// Check to see if the surface has changed size. This is _necessary_ to do every frame when
// using immersive mode as you'll get no other notification that your renderable area has
// changed.
EGLint width;
EGLint height;
eglQuerySurface(display_, surface_, EGL_WIDTH, &width);
eglQuerySurface(display_, surface_, EGL_HEIGHT, &height);
nanogv.switchRenderer(true);
nanogv.resize(width, height);
nanogv.draw();
// Present the rendered image. This is an implicit glFlush.
auto swapResult = eglSwapBuffers(display_, surface_);
assert(swapResult == EGL_TRUE);
}
///**
// * @brief Create any demo models we want for this demo.
// */
//void Renderer::createModels() {
// /*
// * This is a square:
// * 0 --- 1
// * | \ |
// * | \ |
// * | \ |
// * 3 --- 2
// */
// std::vector<Vertex> vertices = {
// Vertex(Vector3{1, 1, 0}, Vector2{0, 0}), // 0
// Vertex(Vector3{-1, 1, 0}, Vector2{1, 0}), // 1
// Vertex(Vector3{-1, -1, 0}, Vector2{1, 1}), // 2
// Vertex(Vector3{1, -1, 0}, Vector2{0, 1}) // 3
// };
// std::vector<Index> indices = {
// 0, 1, 2, 0, 2, 3
// };
//
// // loads an image and assigns it to the square.
// //
// // Note: there is no texture management in this sample, so if you reuse an image be careful not
// // to load it repeatedly. Since you get a shared_ptr you can safely reuse it in many models.
// auto assetManager = app_->activity->assetManager;
// auto spAndroidRobotTexture = TextureAsset::loadAsset(assetManager, "android_robot.png");
//
// // Create a model and put it in the back of the render list.
// models_.emplace_back(vertices, indices, spAndroidRobotTexture);
//}
void Renderer::handleInput() {
// handle all queued inputs
auto *inputBuffer = android_app_swap_input_buffers(app_);
if (!inputBuffer) {
// no inputs yet.
return;
}
// handle motion events (motionEventsCounts can be 0).
for (auto i = 0; i < inputBuffer->motionEventsCount; i++) {
auto &motionEvent = inputBuffer->motionEvents[i];
auto action = motionEvent.action;
// Find the pointer index, mask and bitshift to turn it into a readable value.
auto pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
>> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
aout << "Pointer(s): ";
// get the x and y position of this event if it is not ACTION_MOVE.
auto &pointer = motionEvent.pointers[pointerIndex];
auto x = GameActivityPointerAxes_getX(&pointer);
auto y = GameActivityPointerAxes_getY(&pointer);
// determine the action type and process the event accordingly.
switch (action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_POINTER_DOWN:
aout << "(" << pointer.id << ", " << x << ", " << y << ") "
<< "Pointer Down";
break;
case AMOTION_EVENT_ACTION_CANCEL:
// treat the CANCEL as an UP event: doing nothing in the app, except
// removing the pointer from the cache if pointers are locally saved.
// code pass through on purpose.
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_POINTER_UP:
aout << "(" << pointer.id << ", " << x << ", " << y << ") "
<< "Pointer Up";
break;
case AMOTION_EVENT_ACTION_MOVE:
// There is no pointer index for ACTION_MOVE, only a snapshot of
// all active pointers; app needs to cache previous active pointers
// to figure out which ones are actually moved.
for (auto index = 0; index < motionEvent.pointerCount; index++) {
pointer = motionEvent.pointers[index];
x = GameActivityPointerAxes_getX(&pointer);
y = GameActivityPointerAxes_getY(&pointer);
aout << "(" << pointer.id << ", " << x << ", " << y << ")";
if (index != (motionEvent.pointerCount - 1)) aout << ",";
aout << " ";
}
aout << "Pointer Move";
break;
default:
aout << "Unknown MotionEvent Action: " << action;
}
aout << std::endl;
}
// clear the motion input count in this buffer for main thread to re-use.
android_app_clear_motion_events(inputBuffer);
// handle input key events.
for (auto i = 0; i < inputBuffer->keyEventsCount; i++) {
auto &keyEvent = inputBuffer->keyEvents[i];
aout << "Key: " << keyEvent.keyCode <<" ";
switch (keyEvent.action) {
case AKEY_EVENT_ACTION_DOWN:
aout << "Key Down";
break;
case AKEY_EVENT_ACTION_UP:
aout << "Key Up";
break;
case AKEY_EVENT_ACTION_MULTIPLE:
// Deprecated since Android API level 29.
aout << "Multiple Key Actions";
break;
default:
aout << "Unknown KeyEvent Action: " << keyEvent.action;
}
aout << std::endl;
}
// clear the key input count too.
android_app_clear_key_events(inputBuffer);
}
The license says tbd, is there an update on that?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.