GithubHelp home page GithubHelp logo

styluslabs / nanovgxc Goto Github PK

View Code? Open in Web Editor NEW
119.0 119.0 5.0 1.54 MB

Lightweight vector graphics library implementing exact-coverage antialiasing in OpenGL

License: Other

Makefile 0.46% C 97.52% C++ 2.02%

nanovgxc's People

Contributors

pbsurf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

nanovgxc's Issues

Failed to compile skia-test on my mingw64

I was trying to compile skia-test on my mingw, but get linking errors like:
webp error
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

how to draw?

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);
}

License

The license says tbd, is there an update on that?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.