Skip to content

A port of NanoVG to the gxm graphics API for the PSVita (vitasdk)

License

Notifications You must be signed in to change notification settings

xfangfang/nanovg-gxm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NanoVG-GXM

Port of NanoVG to Sony's GXM API.

Compared to running through OpenGL ES2, significant performance improvement has been achieved by using GXM API.

Build

cmake -B build -DENABLE_EXAMPLE=ON
cmake --build build

New Features

1. Compressed texture support

When creating an RGBA texture, you can specify the following image flag and pass in the compressed texture.
This can significantly reduce the memory footprint when the texture dimensions are large.

  • NVG_IMAGE_DXT1
  • NVG_IMAGE_DXT5
// Create a DXT1 texture from a compressed data
uint8_t* dxt1_data = ...;
int image1 = nvgCreateImageRGBA(vg, w, h, NVG_IMAGE_DXT1, dxt1_data);

// Create an empty DXT1 texture, then update the texture with compressed data
int image2 = nvgCreateImageRGBA(vg, w, h, NVG_IMAGE_DXT1, NULL);
nvgUpdateImage(vg, image2, dxt1_data);

// Create an empty DXT1 texture, then directly update the texture data
void dxt1_compress(uint8_t* dst, uint8_t* src, int w, int h);
uint8_t* rgba_data = ...;
int image3 = nvgCreateImageRGBA(vg, w, h, NVG_IMAGE_DXT1, NULL);
NVGXMtexture *tex = nvgxmImageHandle(vg, image3);
dxt1_compress(tex->data, rgba_data, w, h);

2. Texture memory location support

You can manually specify that textures should be stored in system memory or video memory.

  • NVG_IMAGE_LPDDR
  • NVG_IMAGE_CDRAM
// Create a texture in video memory
int image1 = nvgCreateImageRGBA(vg, w, h, NVG_IMAGE_CDRAM, NULL);

// Create a texture in system memory
int image2 = nvgCreateImageRGBA(vg, w, h, NVG_IMAGE_LPDDR, NULL);

by default, textures are stored in system memory, you can specify the default location by defining a global variable: nanovg_gxm_default_mem_type

#include <nanovg.h>

#define NANOVG_GXM_IMPLEMENTATION
#define NANOVG_GXM_UTILS_IMPLEMENTATION
#include <nanovg_gxm.h>

int nanovg_gxm_default_mem_type = NVG_IMAGE_CDRAM;

int main(...) {
    ...
    
    struct NVGcontext* vg = nvgCreateGXM(gxm_context, shader_patcher, NVG_STENCIL_STROKES)
            
    ...
    
    // Create textures in video memory
    int image1 = nvgCreateImageRGBA(vg, w, h, 0, NULL);
    int image2 = nvgCreateImageRGBA(vg, w, h, 0, NULL);
    
    // Create a texture in system memory
    int image3 = nvgCreateImageRGBA(vg, w, h, NVG_IMAGE_LPDDR, NULL);
    
    ...
}

3. Change the size of the vertex buffer

There is a built-in vertex buffer in nanovg, which is used to store the vertex data of the drawn graphics. The default size is 1024 * 1024 bytes. You can define a global variable to modify this default value: nvg_gxm_vertex_buffer_size.

When too many graphics are drawn in a frame, it may exceed the size of this buffer, causing the drawing to fail. In this case, you can increase the size of this buffer.

#include <nanovg.h>

#define NANOVG_GXM_IMPLEMENTATION
#define NANOVG_GXM_UTILS_IMPLEMENTATION
#include <nanovg_gxm.h>

int nvg_gxm_vertex_buffer_size = 2 * 1024 * 1024;

int main(...) {
    ...
}

4. GXM related helper functions

In order to facilitate the initialization of an application, some GXM-related helper functions are provided in src/nanovg_gxm_utils.h.

You can see how these functions are used in example/example_gxm.c and example/example_gxm_fbo.c.

TODO

1. blend function

Currently, these functions in nanovg.h are not supported:

nvgGlobalCompositeOperation, nvgGlobalCompositeBlendFunc, nvgGlobalCompositeBlendFuncSeparate

The default blend behavior is equivalent to: nvgGlobalCompositeOperation(NVG_SOURCE_OVER)

2. Image flag

The NVG_IMAGE_GENERATE_MIPMAPS flag is not supported yet.


This project is not actively maintained.

NanoVG

NanoVG is small antialiased vector graphics rendering library for OpenGL. It has lean API modeled after HTML5 canvas API. It is aimed to be a practical and fun toolset for building scalable user interfaces and visualizations.

Screenshot

screenshot of some text rendered witht the sample program

Usage

The NanoVG API is modeled loosely on HTML5 canvas API. If you know canvas, you're up to speed with NanoVG in no time.

Creating drawing context

The drawing context is created using platform specific constructor function. If you're using the OpenGL 2.0 back-end the context is created as follows:

#define NANOVG_GL2_IMPLEMENTATION	// Use GL2 implementation.
#include "nanovg_gl.h"
...
struct NVGcontext* vg = nvgCreateGL2(NVG_ANTIALIAS | NVG_STENCIL_STROKES);

The first parameter defines flags for creating the renderer.

  • NVG_ANTIALIAS means that the renderer adjusts the geometry to include anti-aliasing. If you're using MSAA, you can omit this flags.
  • NVG_STENCIL_STROKES means that the render uses better quality rendering for (overlapping) strokes. The quality is mostly visible on wider strokes. If you want speed, you can omit this flag.

Currently there is an OpenGL back-end for NanoVG: nanovg_gl.h for OpenGL 2.0, OpenGL ES 2.0, OpenGL 3.2 core profile and OpenGL ES 3. The implementation can be chosen using a define as in above example. See the header file and examples for further info.

NOTE: The render target you're rendering to must have stencil buffer.

Drawing shapes with NanoVG

Drawing a simple shape using NanoVG consists of four steps: 1) begin a new shape, 2) define the path to draw, 3) set fill or stroke, 4) and finally fill or stroke the path.

nvgBeginPath(vg);
nvgRect(vg, 100,100, 120,30);
nvgFillColor(vg, nvgRGBA(255,192,0,255));
nvgFill(vg);

Calling nvgBeginPath() will clear any existing paths and start drawing from blank slate. There are number of number of functions to define the path to draw, such as rectangle, rounded rectangle and ellipse, or you can use the common moveTo, lineTo, bezierTo and arcTo API to compose the paths step by step.

Understanding Composite Paths

Because of the way the rendering backend is build in NanoVG, drawing a composite path, that is path consisting from multiple paths defining holes and fills, is a bit more involved. NanoVG uses even-odd filling rule and by default the paths are wound in counter clockwise order. Keep that in mind when drawing using the low level draw API. In order to wind one of the predefined shapes as a hole, you should call nvgPathWinding(vg, NVG_HOLE), or nvgPathWinding(vg, NVG_CW) after defining the path.

nvgBeginPath(vg);
nvgRect(vg, 100,100, 120,30);
nvgCircle(vg, 120,120, 5);
nvgPathWinding(vg, NVG_HOLE);	// Mark circle as a hole.
nvgFillColor(vg, nvgRGBA(255,192,0,255));
nvgFill(vg);

Rendering is wrong, what to do?

  • make sure you have created NanoVG context using one of the nvgCreatexxx() calls
  • make sure you have initialised OpenGL with stencil buffer
  • make sure you have cleared stencil buffer
  • make sure all rendering calls happen between nvgBeginFrame() and nvgEndFrame()
  • to enable more checks for OpenGL errors, add NVG_DEBUG flag to nvgCreatexxx()
  • if the problem still persists, please report an issue!

OpenGL state touched by the backend

The OpenGL back-end touches following states:

When textures are uploaded or updated, the following pixel store is set to defaults: GL_UNPACK_ALIGNMENT, GL_UNPACK_ROW_LENGTH, GL_UNPACK_SKIP_PIXELS, GL_UNPACK_SKIP_ROWS. Texture binding is also affected. Texture updates can happen when the user loads images, or when new font glyphs are added. Glyphs are added as needed between calls to nvgBeginFrame() and nvgEndFrame().

The data for the whole frame is buffered and flushed in nvgEndFrame(). The following code illustrates the OpenGL state touched by the rendering code:

	glUseProgram(prog);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
	glFrontFace(GL_CCW);
	glEnable(GL_BLEND);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_SCISSOR_TEST);
	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	glStencilMask(0xffffffff);
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
	glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
	glActiveTexture(GL_TEXTURE0);
	glBindBuffer(GL_UNIFORM_BUFFER, buf);
	glBindVertexArray(arr);
	glBindBuffer(GL_ARRAY_BUFFER, buf);
	glBindTexture(GL_TEXTURE_2D, tex);
	glUniformBlockBinding(... , GLNVG_FRAG_BINDING);

API Reference

See the header file nanovg.h for API reference.

Ports

Projects using NanoVG

License

The library is licensed under zlib license Fonts used in examples:

Discussions

NanoVG mailing list

Links

Uses stb_truetype (or, optionally, freetype) for font rendering. Uses stb_image for image loading.

About

A port of NanoVG to the gxm graphics API for the PSVita (vitasdk)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages