First commit

master
Mikko Mononen 2013-11-12 08:34:27 +01:00
commit b89907ba6b
34 changed files with 11951 additions and 0 deletions

28
.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
## Compiled source #
*.com
*.class
*.dll
*.exe
*.o
*.so
test
## Logs and databases #
*.log
*.sql
*.sqlite
## OS generated files #
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
## Build dir
build/*
## xcode specific
*xcuserdata*

138
README.md Normal file
View File

@ -0,0 +1,138 @@
Font Stash
==========
Font stash is light-weight online font texture atlas builder written in C. It uses [stb_truetype](http://nothings.org) to render fonts on demand to a texture atlas.
The code is split in two parts, the font atlas and glyph quad generator [fontstash.h](/src/fontstash.h), and an example OpenGL backend ([glstash.h](/glstash.h).
## Screenshot
![screenshot of some text rendered witht the sample program](/screenshots/screen-01.png?raw=true)
## Example
``` C
// Create stash for 512x512 texture, our coordinate system has zero at top-left.
struct FONSparams params;
memset(&params, 0, sizeof(params));
params.width = 512;
params.height = 512;
params.flags = FONS_ZERO_TOPLEFT;
glstInit(&params);
struct FONScontext* fs = fonsCreate(&params);
// Add font to stash.
int fontNormal = fonsAddFont(fs, "DroidSerif-Regular.ttf");
// Render some text
float dx = 10, dy = 10;
unsigned int white = glstRGBA(255,255,255,255);
unsigned int brown = glstRGBA(192,128,0,128);
struct fontstash_style styleBig = { FONT_NORMAL, 124.0f, white };
fonsSetFont(fs, fontNormal);
fonsSetSize(fs, 124.0f);
fonsSetColor(fs, white);
fonsDrawText(fs, dx,dy,"The big ", &dx);
fonsSetSize(fs, 24.0f);
fonsSetColor(fs, brown);
fonsDrawText(fs, dx,dy,"brown fox", &dx);
```
## Using Font Stash in your project
In order to use fontstash in your own project, just copy fontstash.h, stb_truetype.h, and potentially glstash.h to your project.
In one C/C++ define FONTSTASH_IMPLEMENTATION before including the library to expand the font stash implementation in that file.
``` C
#include <stdio.h> // malloc, free, fopen, fclose, ftell, fseek, fread
#include <string.h> // memset
#define FONTSTASH_IMPLEMENTATION // Expands implementation
#include "fontstash.h"
```
``` C
#include <GLFW/glfw3.h> // Or any other GL header of your choice.
#define GLSTASH_IMPLEMENTATION // Expands implementation
#include "glstash.h"
```
## Creating new rendering backend
The default rendering backend uses OpenGL to render the glyphs. If you want to render the text using some other API, or want tighter integration with your code base you can write your own rendering backend. Take a look at the [glstash.h](/src/glstash.h) for reference implementation.
The rendering interface FontStash assumes access to is defined in the FONSparams structure. The call to `glstInit()` fills in variables.
```C
struct FONSparams {
...
void* userPtr;
int (*renderCreate)(void* uptr, int width, int height);
void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data);
void (*renderDraw)(void* uptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts);
void (*renderDelete)(void* uptr);
};
```
- **renderCreate** is called to create renderer for specific API, this is where you should create a texture of given size.
- return 1 of success, or 0 on failure.
- **renderUpdate** is called to update texture data
- _rect_ describes the region of the texture that has changed
- _data_ pointer to full texture data
- **renderDraw** is called when the font triangles should be drawn
- _verts_ pointer to vertex position data, 2 floats per vertex
- _tcoords_ pointer to texture coordinate data, 2 floats per vertex
- _colors_ pointer to color data, 1 uint per vertex (or 4 bytes)
- _nverts_ is the number of vertices to draw
- **renderDelete** is called when the renderer should be deleted
- **userPtr** is passed to all calls as first parameter
FontStash uses this API as follows:
```
fonsDrawText() {
foreach (glyph in input string) {
if (internal buffer full) {
updateTexture()
render()
}
add glyph to interal draw buffer
}
updateTexture()
render()
}
```
The size of the internal buffer is defined using `FONS_VERTEX_COUNT` define. The default value is 1024, you can override it when you include fontstash.h and specify the implementation:
``` C
#define FONS_VERTEX_COUNT 2048
#define FONTSTASH_IMPLEMENTATION // Expands implementation
#include "fontstash.h"
```
## Compiling
In order to compile the demo project, your will need to install [GLFW](http://www.glfw.org/) to compile.
FontStash example project uses [premake4](http://industriousone.com/premake) to build platform specific projects, now is good time to install it if you don't have it already. To build the example, navigate into the root folder in your favorite terminal, then:
- *OS X*: `premake4 xcode4`
- *Windows*: `premake4 vs2010`
- *Linux*: `premake4 gmake`
See premake4 documentation for full list of supported build file types. The projects will be created in `build` folder. An example of building and running the example on OS X:
```bash
$ premake4 gmake
$ cd build/
$ make
$ ./example
```
# License
The library is licensed under [zlib license](LICENSE.txt)
## Links
Uses [stb_truetype](http://nothings.org) for font rendering.

BIN
example/FiraSans-Bold.ttf Executable file

Binary file not shown.

BIN
example/FiraSans-Light.ttf Executable file

Binary file not shown.

BIN
example/FiraSans-Regular.ttf Executable file

Binary file not shown.

BIN
example/Roboto-Bold.ttf Executable file

Binary file not shown.

BIN
example/Roboto-Light.ttf Executable file

Binary file not shown.

BIN
example/Roboto-Regular.ttf Executable file

Binary file not shown.

BIN
example/entypo.ttf Normal file

Binary file not shown.

767
example/example.c Normal file
View File

@ -0,0 +1,767 @@
//
// Copyright (c) 2013 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#include <stdio.h>
#include <string.h>
#include <iconv.h>
#include <math.h>
#include <GLFW/glfw3.h>
#include "nanovg.h"
#define GLNANOVG_IMPLEMENTATION
#include "glnanovg.h"
#define ICON_SEARCH 0x1F50D
#define ICON_CIRCLED_CROSS 0x2716
#define ICON_CHEVRON_RIGHT 0xE75E
#define ICON_CHECK 0x2713
#define ICON_LOGIN 0xE740
#define ICON_TRASH 0xE729
static char* cpToUTF8(int cp, char* str)
{
int n = 0;
if (cp < 0x80) n = 1;
else if (cp < 0x800) n = 2;
else if (cp < 0x10000) n = 3;
else if (cp < 0x200000) n = 4;
else if (cp < 0x4000000) n = 5;
else if (cp <= 0x7fffffff) n = 6;
str[n] = '\0';
switch (n) {
case 6: str[5] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x4000000;
case 5: str[4] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x200000;
case 4: str[3] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x10000;
case 3: str[2] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x800;
case 2: str[1] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0xc0;
case 1: str[0] = cp;
}
return str;
}
void drawWindow(struct NVGcontext* vg, const char* title, float x, float y, float w, float h)
{
float cornerRadius = 3.0f;
struct NVGpaint shadowPaint;
struct NVGpaint headerPaint;
nvgSave(vg);
// nvgClearState(vg);
// Window
nvgBeginPath(vg);
nvgRoundedRect(vg, x,y, w,h, cornerRadius);
nvgFillColor(vg, nvgRGBA(28,30,34,192));
// nvgFillColor(vg, nvgRGBA(0,0,0,128));
nvgFill(vg);
// Drop shadow
shadowPaint = nvgBoxGradient(vg, x,y+2, w,h, cornerRadius*2, 10, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
nvgBeginPath(vg);
nvgRect(vg, x-10,y-10, w+20,h+30);
nvgRoundedRect(vg, x,y, w,h, cornerRadius);
nvgPathWinding(vg, NVG_HOLE);
nvgFillPaint(vg, shadowPaint);
nvgFill(vg);
// Header
headerPaint = nvgLinearGradient(vg, x,y,x,y+15, nvgRGBA(255,255,255,8), nvgRGBA(0,0,0,16));
nvgBeginPath(vg);
nvgRoundedRect(vg, x+1,y+1, w-2,30, cornerRadius-1);
nvgFillPaint(vg, headerPaint);
nvgFill(vg);
nvgBeginPath(vg);
nvgMoveTo(vg, x+0.5f, y+0.5f+30);
nvgLineTo(vg, x+0.5f+w-1, y+0.5f+30);
nvgStrokeColor(vg, nvgRGBA(0,0,0,32));
nvgStroke(vg);
nvgFontSize(vg, 18.0f);
nvgFontFace(vg, "sans-bold");
nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
nvgFontBlur(vg,2);
nvgFillColor(vg, nvgRGBA(0,0,0,128));
nvgText(vg, x+w/2,y+16+1, title);
nvgFontBlur(vg,0);
nvgFillColor(vg, nvgRGBA(220,220,220,160));
nvgText(vg, x+w/2,y+16, title);
nvgRestore(vg);
}
void drawSearchBox(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
{
struct NVGpaint bg;
char icon[8];
float cornerRadius = h/2-1;
// Edit
bg = nvgBoxGradient(vg, x,y+1.5f, w,h, h/2,5, nvgRGBA(0,0,0,16), nvgRGBA(0,0,0,92));
nvgBeginPath(vg);
nvgRoundedRect(vg, x,y, w,h, cornerRadius);
nvgFillPaint(vg, bg);
nvgFill(vg);
/* nvgBeginPath(vg);
nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
nvgStroke(vg);*/
nvgFontSize(vg, h*1.3f);
nvgFontFace(vg, "icons");
nvgFillColor(vg, nvgRGBA(255,255,255,64));
nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
nvgText(vg, x+h*0.55f, y+h*0.55f, cpToUTF8(ICON_SEARCH,icon));
nvgFontSize(vg, 20.0f);
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,32));
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+h*1.05f,y+h*0.5f,text);
nvgFontSize(vg, h*1.3f);
nvgFontFace(vg, "icons");
nvgFillColor(vg, nvgRGBA(255,255,255,32));
nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
nvgText(vg, x+w-h*0.55f, y+h*0.55f, cpToUTF8(ICON_CIRCLED_CROSS,icon));
}
void drawDropDown(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
{
struct NVGpaint bg;
char icon[8];
float cornerRadius = 4.0f;
bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(255,255,255,16), nvgRGBA(0,0,0,16));
nvgBeginPath(vg);
nvgRoundedRect(vg, x+1,y+1, w-2,h-2, cornerRadius-1);
nvgFillPaint(vg, bg);
nvgFill(vg);
nvgBeginPath(vg);
nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
nvgStroke(vg);
nvgFontSize(vg, 20.0f);
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,160));
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+h*0.3f,y+h*0.5f,text);
nvgFontSize(vg, h*1.3f);
nvgFontFace(vg, "icons");
nvgFillColor(vg, nvgRGBA(255,255,255,64));
nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
nvgText(vg, x+w-h*0.5f, y+h*0.5f, cpToUTF8(ICON_CHEVRON_RIGHT,icon));
}
void drawLabel(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
{
nvgFontSize(vg, 18.0f);
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,128));
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x,y+h*0.5f,text);
}
void drawEditBoxBase(struct NVGcontext* vg, float x, float y, float w, float h)
{
struct NVGpaint bg;
// Edit
bg = nvgBoxGradient(vg, x+1,y+1+1.5f, w-2,h-2, 3,4, nvgRGBA(255,255,255,32), nvgRGBA(32,32,32,32));
nvgBeginPath(vg);
nvgRoundedRect(vg, x+1,y+1, w-2,h-2, 4-1);
nvgFillPaint(vg, bg);
nvgFill(vg);
nvgBeginPath(vg);
nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, 4-0.5f);
nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
nvgStroke(vg);
}
void drawEditBox(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
{
drawEditBoxBase(vg, x,y, w,h);
nvgFontSize(vg, 20.0f);
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,64));
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+h*0.3f,y+h*0.5f,text);
}
void drawEditBoxNum(struct NVGcontext* vg,
const char* text, const char* units, float x, float y, float w, float h)
{
float uw;
drawEditBoxBase(vg, x,y, w,h);
nvgTextBounds(vg, units, &uw, NULL);
nvgFontSize(vg, 18.0f);
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,64));
nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+w-h*0.3f,y+h*0.5f,units);
nvgFontSize(vg, 20.0f);
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,128));
nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+w-uw-h*0.5f,y+h*0.5f,text);
}
void drawCheckBox(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
{
struct NVGpaint bg;
char icon[8];
nvgFontSize(vg, 18.0f);
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,160));
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+28,y+h*0.5f,text);
bg = nvgBoxGradient(vg, x+1,y+(int)(h*0.5f)-9+1, 18,18, 3,3, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,92));
nvgBeginPath(vg);
nvgRoundedRect(vg, x+1,y+(int)(h*0.5f)-9, 18,18, 3);
nvgFillPaint(vg, bg);
nvgFill(vg);
nvgFontSize(vg, 40);
nvgFontFace(vg, "icons");
nvgFillColor(vg, nvgRGBA(255,255,255,128));
nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
nvgText(vg, x+9+2, y+h*0.5f, cpToUTF8(ICON_CHECK,icon));
}
void drawButton(struct NVGcontext* vg, int preicon, const char* text, float x, float y, float w, float h, unsigned int col)
{
struct NVGpaint bg;
char icon[8];
float cornerRadius = 4.0f;
float tw = 0, iw = 0;
bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(255,255,255,col==0?16:32), nvgRGBA(0,0,0,col==0?16:32));
nvgBeginPath(vg);
nvgRoundedRect(vg, x+1,y+1, w-2,h-2, cornerRadius-1);
if (col != 0) {
nvgFillColor(vg, col);
nvgFill(vg);
}
nvgFillPaint(vg, bg);
nvgFill(vg);
nvgBeginPath(vg);
nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
nvgStroke(vg);
nvgFontSize(vg, 20.0f);
nvgFontFace(vg, "sans-bold");
nvgTextBounds(vg, text, &tw, NULL);
if (preicon != 0) {
nvgFontSize(vg, h*1.3f);
nvgFontFace(vg, "icons");
nvgTextBounds(vg, cpToUTF8(preicon,icon), &iw, NULL);
iw += h*0.15f;
}
if (preicon != 0) {
nvgFontSize(vg, h*1.3f);
nvgFontFace(vg, "icons");
nvgFillColor(vg, nvgRGBA(255,255,255,96));
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+w*0.5f-tw*0.5f-iw*0.75f, y+h*0.5f, cpToUTF8(preicon,icon));
}
nvgFontSize(vg, 20.0f);
nvgFontFace(vg, "sans-bold");
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgFillColor(vg, nvgRGBA(0,0,0,160));
nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f-1,text);
nvgFillColor(vg, nvgRGBA(255,255,255,160));
nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f,text);
}
void drawSlider(struct NVGcontext* vg, float pos, float x, float y, float w, float h)
{
struct NVGpaint bg, knob;
float cy = y+(int)(h*0.5f);
float kr = (int)(h*0.25f);
nvgSave(vg);
// nvgClearState(vg);
// Slot
bg = nvgBoxGradient(vg, x,cy-2+1, w,4, 2,2, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,128));
nvgBeginPath(vg);
nvgRoundedRect(vg, x,cy-2, w,4, 2);
nvgFillPaint(vg, bg);
nvgFill(vg);
// Knob Shadow
bg = nvgRadialGradient(vg, x+(int)(pos*w),cy+1, kr-3,kr+3, nvgRGBA(0,0,0,64), nvgRGBA(0,0,0,0));
nvgBeginPath(vg);
nvgRect(vg, x+(int)(pos*w)-kr-5,cy-kr-5,kr*2+5+5,kr*2+5+5+3);
nvgCircle(vg, x+(int)(pos*w),cy, kr);
nvgPathWinding(vg, NVG_HOLE);
nvgFillPaint(vg, bg);
nvgFill(vg);
// Knob
knob = nvgLinearGradient(vg, x,cy-kr,x,cy+kr, nvgRGBA(255,255,255,16), nvgRGBA(0,0,0,16));
nvgBeginPath(vg);
nvgCircle(vg, x+(int)(pos*w),cy, kr-1);
nvgFillColor(vg, nvgRGBA(40,43,48,255));
nvgFill(vg);
nvgFillPaint(vg, knob);
nvgFill(vg);
nvgBeginPath(vg);
nvgCircle(vg, x+(int)(pos*w),cy, kr-0.5f);
nvgStrokeColor(vg, nvgRGBA(0,0,0,92));
nvgStroke(vg);
nvgRestore(vg);
}
void drawEyes(struct NVGcontext* vg, float x, float y, float w, float h, float mx, float my, float t)
{
struct NVGpaint gloss, bg;
float ex = w *0.23f;
float ey = h * 0.5f;
float lx = x + ex;
float ly = y + ey;
float rx = x + w - ex;
float ry = y + ey;
float dx,dy,d;
float br = (ex < ey ? ex : ey) * 0.5f;
float blink = 1 - pow(sinf(t*0.5f),200)*0.8f;
bg = nvgLinearGradient(vg, x,y+h*0.5f,x+w*0.1f,y+h, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,16));
nvgBeginPath(vg);
nvgEllipse(vg, lx+3.0f,ly+16.0f, ex,ey);
nvgEllipse(vg, rx+3.0f,ry+16.0f, ex,ey);
nvgFillPaint(vg, bg);
nvgFill(vg);
bg = nvgLinearGradient(vg, x,y+h*0.25f,x+w*0.1f,y+h, nvgRGBA(220,220,220,255), nvgRGBA(128,128,128,255));
nvgBeginPath(vg);
nvgEllipse(vg, lx,ly, ex,ey);
nvgEllipse(vg, rx,ry, ex,ey);
nvgFillPaint(vg, bg);
nvgFill(vg);
dx = (mx - rx) / (ex * 10);
dy = (my - ry) / (ey * 10);
d = sqrtf(dx*dx+dy*dy);
if (d > 1.0f) {
dx /= d; dy /= d;
}
dx *= ex*0.4f;
dy *= ey*0.5f;
nvgBeginPath(vg);
nvgEllipse(vg, lx+dx,ly+dy+ey*0.25f*(1-blink), br,br*blink);
nvgFillColor(vg, nvgRGBA(32,32,32,255));
nvgFill(vg);
dx = (mx - rx) / (ex * 10);
dy = (my - ry) / (ey * 10);
d = sqrtf(dx*dx+dy*dy);
if (d > 1.0f) {
dx /= d; dy /= d;
}
dx *= ex*0.4f;
dy *= ey*0.5f;
nvgBeginPath(vg);
nvgEllipse(vg, rx+dx,ry+dy+ey*0.25f*(1-blink), br,br*blink);
nvgFillColor(vg, nvgRGBA(32,32,32,255));
nvgFill(vg);
gloss = nvgRadialGradient(vg, lx-ex*0.25f,ly-ey*0.5f, ex*0.1f,ex*0.75f, nvgRGBA(255,255,255,128), nvgRGBA(255,255,255,0));
nvgBeginPath(vg);
nvgEllipse(vg, lx,ly, ex,ey);
nvgFillPaint(vg, gloss);
nvgFill(vg);
gloss = nvgRadialGradient(vg, rx-ex*0.25f,ry-ey*0.5f, ex*0.1f,ex*0.75f, nvgRGBA(255,255,255,128), nvgRGBA(255,255,255,0));
nvgBeginPath(vg);
nvgEllipse(vg, rx,ry, ex,ey);
nvgFillPaint(vg, gloss);
nvgFill(vg);
}
void drawGraph(struct NVGcontext* vg, float x, float y, float w, float h, float t)
{
struct NVGpaint bg;
float samples[6];
float sx[6], sy[6];
float dx = w/5.0f;
int i;
samples[0] = (1+sinf(t*1.2345f+cosf(t*0.33457f)*0.44f))*0.5f;
samples[1] = (1+sinf(t*0.68363f+cosf(t*1.3f)*1.55f))*0.5f;
samples[2] = (1+sinf(t*1.1642f+cosf(t*0.33457)*1.24f))*0.5f;
samples[3] = (1+sinf(t*0.56345f+cosf(t*1.63f)*0.14f))*0.5f;
samples[4] = (1+sinf(t*1.6245f+cosf(t*0.254f)*0.3f))*0.5f;
samples[5] = (1+sinf(t*0.345f+cosf(t*0.03f)*0.6f))*0.5f;
for (i = 0; i < 6; i++) {
sx[i] = x+i*dx;
sy[i] = y+h*samples[i]*0.8f;
}
// Graph background
bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(0,160,192,0), nvgRGBA(0,160,192,64));
nvgBeginPath(vg);
nvgMoveTo(vg, sx[0], sy[0]);
for (i = 1; i < 6; i++)
nvgBezierTo(vg, sx[i-1]+dx*0.5f,sy[i-1], sx[i]-dx*0.5f,sy[i], sx[i],sy[i]);
nvgLineTo(vg, x+w, y+h);
nvgLineTo(vg, x, y+h);
nvgFillPaint(vg, bg);
nvgFill(vg);
// Graph line
nvgBeginPath(vg);
nvgMoveTo(vg, sx[0], sy[0]+2);
for (i = 1; i < 6; i++)
nvgBezierTo(vg, sx[i-1]+dx*0.5f,sy[i-1]+2, sx[i]-dx*0.5f,sy[i]+2, sx[i],sy[i]+2);
nvgStrokeColor(vg, nvgRGBA(0,0,0,32));
nvgStrokeWidth(vg, 3.0f);
nvgStroke(vg);
nvgBeginPath(vg);
nvgMoveTo(vg, sx[0], sy[0]);
for (i = 1; i < 6; i++)
nvgBezierTo(vg, sx[i-1]+dx*0.5f,sy[i-1], sx[i]-dx*0.5f,sy[i], sx[i],sy[i]);
nvgStrokeColor(vg, nvgRGBA(0,160,192,255));
nvgStrokeWidth(vg, 3.0f);
nvgStroke(vg);
// Graph sample pos
for (i = 0; i < 6; i++) {
bg = nvgRadialGradient(vg, sx[i],sy[i]+2, 3.0f,8.0f, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,0));
nvgBeginPath(vg);
nvgRect(vg, sx[i]-10, sy[i]-10+2, 20,20);
nvgFillPaint(vg, bg);
nvgFill(vg);
}
nvgBeginPath(vg);
for (i = 0; i < 6; i++)
nvgCircle(vg, sx[i], sy[i], 4.0f);
nvgFillColor(vg, nvgRGBA(0,160,192,255));
nvgFill(vg);
nvgBeginPath(vg);
for (i = 0; i < 6; i++)
nvgCircle(vg, sx[i], sy[i], 2.0f);
nvgFillColor(vg, nvgRGBA(220,220,220,255));
nvgFill(vg);
nvgStrokeWidth(vg, 1.0f);
}
void drawThumbnails(struct NVGcontext* vg, float x, float y, float w, float h, const int* images, int nimages, float t)
{
float cornerRadius = 3.0f;
struct NVGpaint shadowPaint, imgPaint, fadePaint;
float ix,iy,iw,ih;
float thumb = 60.0f;
float arry = 30.5f;
int imgw, imgh;
float stackh = (nimages/2) * (thumb+10) + 10;
int i;
float u = (1+cosf(t*0.5f))*0.5f;
nvgSave(vg);
// nvgClearState(vg);
// Drop shadow
shadowPaint = nvgBoxGradient(vg, x,y+4, w,h, cornerRadius*2, 20, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
nvgBeginPath(vg);
nvgRect(vg, x-10,y-10, w+20,h+30);
nvgRoundedRect(vg, x,y, w,h, cornerRadius);
nvgPathWinding(vg, NVG_HOLE);
nvgFillPaint(vg, shadowPaint);
nvgFill(vg);
// Window
nvgBeginPath(vg);
nvgRoundedRect(vg, x,y, w,h, cornerRadius);
nvgMoveTo(vg, x-10,y+arry);
nvgLineTo(vg, x+1,y+arry-11);
nvgLineTo(vg, x+1,y+arry+11);
nvgFillColor(vg, nvgRGBA(200,200,200,255));
nvgFill(vg);
nvgSave(vg);
nvgScissor(vg, x,y,w,h);
nvgTranslate(vg, 0, -(stackh - h)*u);
for (i = 0; i < nimages; i++) {
float tx, ty;
tx = x+10;
ty = y+10;
tx += (i%2) * (thumb+10);
ty += (i/2) * (thumb+10);
nvgImageSize(vg, images[i], &imgw, &imgh);
if (imgw < imgh) {
iw = thumb;
ih = iw * (float)imgh/(float)imgw;
ix = 0;
iy = -(ih-thumb)*0.5f;
} else {
ih = thumb;
iw = ih * (float)imgw/(float)imgh;
ix = -(iw-thumb)*0.5f;
iy = 0;
}
imgPaint = nvgImagePattern(vg, tx+ix, ty+iy, iw,ih, 0.0f/180.0f*NVG_PI, images[i], 0);
nvgBeginPath(vg);
nvgRoundedRect(vg, tx,ty, thumb,thumb, 5);
nvgFillPaint(vg, imgPaint);
nvgFill(vg);
shadowPaint = nvgBoxGradient(vg, tx-1,ty, thumb+2,thumb+2, 5, 3, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
nvgBeginPath(vg);
nvgRect(vg, tx-5,ty-5, thumb+10,thumb+10);
nvgRoundedRect(vg, tx,ty, thumb,thumb, 6);
nvgPathWinding(vg, NVG_HOLE);
nvgFillPaint(vg, shadowPaint);
nvgFill(vg);
nvgBeginPath(vg);
nvgRoundedRect(vg, tx+0.5f,ty+0.5f, thumb-1,thumb-1, 4-0.5f);
nvgStrokeWidth(vg,1.0f);
nvgStrokeColor(vg, nvgRGBA(255,255,255,192));
nvgStroke(vg);
}
nvgRestore(vg);
// Hide fades
fadePaint = nvgLinearGradient(vg, x,y,x,y+6, nvgRGBA(200,200,200,255), nvgRGBA(200,200,200,0));
nvgBeginPath(vg);
nvgRect(vg, x+4,y,w-8,6);
nvgFillPaint(vg, fadePaint);
nvgFill(vg);
fadePaint = nvgLinearGradient(vg, x,y+h,x,y+h-6, nvgRGBA(200,200,200,255), nvgRGBA(200,200,200,0));
nvgBeginPath(vg);
nvgRect(vg, x+4,y+h-6,w-8,6);
nvgFillPaint(vg, fadePaint);
nvgFill(vg);
// Scroll bar
shadowPaint = nvgBoxGradient(vg, x+w-12+1,y+4+1, 8,h-8, 3,4, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,92));
nvgBeginPath(vg);
nvgRoundedRect(vg, x+w-12,y+4, 8,h-8, 3);
nvgFillPaint(vg, shadowPaint);
// nvgFillColor(vg, nvgRGBA(255,0,0,128));
nvgFill(vg);
float scrollh = (h/stackh) * (h-8);
shadowPaint = nvgBoxGradient(vg, x+w-12-1,y+4+(h-8-scrollh)*u-1, 8,scrollh, 3,4, nvgRGBA(220,220,220,255), nvgRGBA(128,128,128,255));
nvgBeginPath(vg);
nvgRoundedRect(vg, x+w-12+1,y+4+1 + (h-8-scrollh)*u, 8-2,scrollh-2, 2);
nvgFillPaint(vg, shadowPaint);
// nvgFillColor(vg, nvgRGBA(0,0,0,128));
nvgFill(vg);
nvgRestore(vg);
}
void errorcb(int error, const char* desc)
{
printf("GLFW error: %s\n", desc);
}
int blowup = 0;
static void key(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
if (key == GLFW_KEY_SPACE && action == GLFW_PRESS)
blowup = !blowup;
}
int main()
{
GLFWwindow* window;
int fontNormal = -1, fontBold = -1, fontIcons = -1;
struct NVGcontext* vg = NULL;
int images[12];
int i;
if (!glfwInit()) {
printf("Failed to init GLFW.");
return -1;
}
glfwSetErrorCallback(errorcb);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
window = glfwCreateWindow(1000, 600, "NanoVG", NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
glfwSetKeyCallback(window, key);
glfwMakeContextCurrent(window);
vg = glnvgCreate();
if (vg == NULL) {
printf("Could not init nanovg.\n");
return -1;
}
for (i = 0; i < 12; i++) {
char file[128];
snprintf(file, 128, "../example/images/image%d.jpg", i+1);
images[i] = nvgCreateImage(vg, file);
if (images[i] == 0) {
printf("Could not load %s.\n", file);
return -1;
}
}
fontIcons = nvgCreateFont(vg, "icons", "../example/entypo.ttf");
if (fontIcons == -1) {
printf("Could not add font icons.\n");
return -1;
}
fontNormal = nvgCreateFont(vg, "sans", "../example/Roboto-Regular.ttf");
// fontNormal = nvgAddFont(vg, "sans", "../example/FiraSans-Regular.ttf");
if (fontNormal == -1) {
printf("Could not add font italic.\n");
return -1;
}
fontBold = nvgCreateFont(vg, "sans-bold", "../example/Roboto-Bold.ttf");
// fontBold = nvgAddFont(vg, "sans-bold", "../example/FiraSans-Bold.ttf");
if (fontBold == -1) {
printf("Could not add font bold.\n");
return -1;
}
glfwSetTime(0);
while (!glfwWindowShouldClose(window))
{
// float sx, sy, dx, dy, lh = 0;
double mx, my;
int width, height;
glfwGetCursorPos(window, &mx, &my);
glfwGetFramebufferSize(window, &width, &height);
// Update and render
glViewport(0, 0, width, height);
glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_CULL_FACE);
glDisable(GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,width,height,0,-1,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glColor4ub(255,255,255,255);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
float t = glfwGetTime();
float x,y,popy;
nvgBeginFrame(vg);
drawEyes(vg, width - 250, 50, 200, 120, mx, my, t);
drawGraph(vg, 0, height/2, width, height/2, t);
nvgSave(vg);
if (blowup) {
// nvgRotate(vg, 3.0f/180.0f*NVG_PI);
nvgScale(vg, 2.0f, 2.0f);
}
// Widgets
drawWindow(vg, "Widgets `n Stuff", 20, 20, 300, 400);
x = 30; y = 65;
drawSearchBox(vg, "Search", x,y,280,25);
y += 40;
drawDropDown(vg, "Effects", x,y,280,28);
popy = y + 14;
y += 45;
// Form
drawLabel(vg, "Login", x,y, 280,20);
y += 25;
drawEditBox(vg, "Email", x,y, 280,28);
y += 35;
drawEditBox(vg, "Password", x,y, 280,28);
y += 38;
drawCheckBox(vg, "Remember me", x,y, 140,28);
drawButton(vg, ICON_LOGIN, "Sign in", x+138, y, 140, 28, nvgRGBA(0,96,128,255));
y += 45;
// Slider
drawLabel(vg, "Diameter", x,y, 280,20);
y += 25;
drawEditBoxNum(vg, "123.00", "px", x+180,y, 100,28);
drawSlider(vg, 0.4f, x,y, 170,28);
y += 55;
drawButton(vg, ICON_TRASH, "Delete", x, y, 160, 28, nvgRGBA(128,16,8,255));
drawButton(vg, 0, "Cancel", x+170, y, 110, 28, nvgRGBA(0,0,0,0));
// Thumbnails box
drawThumbnails(vg, 325, popy-30, 160, 300, images, 12, t);
nvgRestore(vg);
glEnable(GL_DEPTH_TEST);
glfwSwapBuffers(window);
glfwPollEvents();
}
for (i = 0; i < 12; i++)
nvgDeleteImage(vg, images[i]);
glnvgDelete(vg);
glfwTerminate();
return 0;
}

116
example/glstash.h Normal file
View File

@ -0,0 +1,116 @@
//
// Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef GLSTASH_H
#define GLSTASH_H
int glstInit(struct FONSparams* params);
unsigned int glstRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
#endif
#ifdef GLSTASH_IMPLEMENTATION
struct GLSTcontext {
GLuint tex;
int width, height;
};
static int glst__renderCreate(void* userPtr, int width, int height)
{
struct GLSTcontext* gl = (struct GLSTcontext*)userPtr;
glGenTextures(1, &gl->tex);
if (!gl->tex) return 0;
gl->width = width;
gl->height = width;
glBindTexture(GL_TEXTURE_2D, gl->tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gl->width, gl->height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
return 1;
}
static void glst__renderUpdate(void* userPtr, int* rect, const unsigned char* data)
{
struct GLSTcontext* gl = (struct GLSTcontext*)userPtr;
if (gl->tex == 0) return;
int w = rect[2] - rect[0];
int h = rect[3] - rect[1];
glBindTexture(GL_TEXTURE_2D, gl->tex);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, gl->width);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, rect[0]);
glPixelStorei(GL_UNPACK_SKIP_ROWS, rect[1]);
glTexSubImage2D(GL_TEXTURE_2D, 0, rect[0], rect[1], w, h, GL_ALPHA,GL_UNSIGNED_BYTE, data);
}
static void glst__renderDraw(void* userPtr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts)
{
struct GLSTcontext* gl = (struct GLSTcontext*)userPtr;
if (gl->tex == 0) return;
glBindTexture(GL_TEXTURE_2D, gl->tex);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(float)*2, verts);
glTexCoordPointer(2, GL_FLOAT, sizeof(float)*2, tcoords);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(unsigned int), colors);
glDrawArrays(GL_TRIANGLES, 0, nverts);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
static void glst__renderDelete(void* userPtr)
{
struct GLSTcontext* gl = (struct GLSTcontext*)userPtr;
if (gl->tex)
glDeleteTextures(1, &gl->tex);
gl->tex = 0;
free(gl);
}
int glstInit(struct FONSparams* params)
{
struct GLSTcontext* gl = (struct GLSTcontext*)malloc(sizeof(struct GLSTcontext));
if (gl == NULL) goto error;
memset(gl, 0, sizeof(struct GLSTcontext));
params->renderCreate = glst__renderCreate;
params->renderUpdate = glst__renderUpdate;
params->renderDraw = glst__renderDraw;
params->renderDelete = glst__renderDelete;
params->userPtr = gl;
return 1;
error:
if (gl != NULL) free(gl);
return 0;
}
unsigned int glstRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
return (r) | (g << 8) | (b << 16) | (a << 24);
}
#endif

431
example/icons.txt Normal file
View File

@ -0,0 +1,431 @@
struct Icon {
const char* name;
int codepoint;
};
const char* getIcon(const char* name)
{
static struct Icon icons[] = {
{ "phone", 0x1F4DE },
{ "mobile", 0x1F4F1 },
{ "mouse", 0xE789 },
{ "address", 0xE723 },
{ "mail", 0x2709 },
{ "paper-plane", 0x1F53F },
{ "pencil", 0x270E },
{ "feather", 0x2712 },
{ "attach", 0x1F4CE },
{ "inbox", 0xE777 },
{ "reply", 0xE712 },
{ "reply-all", 0xE713 },
{ "forward", 0x27A6 },
{ "user", 0x1F464 },
{ "users", 0x1F465 },
{ "add-user", 0xE700 },
{ "vcard", 0xE722 },
{ "export", 0xE715 },
{ "location", 0xE724 },
{ "map", 0xE727 },
{ "compass", 0xE728 },
{ "direction", 0x27A2 },
{ "hair-cross", 0x1F3AF },
{ "share", 0xE73C },
{ "shareable", 0xE73E },
{ "heart", 0x2665 },
{ "heart-empty", 0x2661 },
{ "star", 0x2605 },
{ "star-empty", 0x2606 },
{ "thumbs-up", 0x1F44D },
{ "thumbs-down", 0x1F44E },
{ "chat", 0xE720 },
{ "comment", 0xE718 },
{ "quote", 0x275E },
{ "home", 0x2302 },
{ "popup", 0xE74C },
{ "search", 0x1F50D },
{ "flashlight", 0x1F526 },
{ "print", 0xE716 },
{ "bell", 0x1F514 },
{ "link", 0x1F517 },
{ "flag", 0x2691 },
{ "cog", 0x2699 },
{ "tools", 0x2692 },
{ "trophy", 0x1F3C6 },
{ "tag", 0xE70C },
{ "camera", 0x1F4F7 },
{ "megaphone", 0x1F4E3 },
{ "moon", 0x263D },
{ "palette", 0x1F3A8 },
{ "leaf", 0x1F342 },
{ "note", 0x266A },
{ "beamed-note", 0x266B },
{ "new", 0x1F4A5 },
{ "graduation-cap", 0x1F393 },
{ "book", 0x1F4D5 },
{ "newspaper", 0x1F4F0 },
{ "bag", 0x1F45C },
{ "airplane", 0x2708 },
{ "lifebuoy", 0xE788 },
{ "eye", 0xE70A },
{ "clock", 0x1F554 },
{ "mic", 0x1F3A4 },
{ "calendar", 0x1F4C5 },
{ "flash", 0x26A1 },
{ "thunder-cloud", 0x26C8 },
{ "droplet", 0x1F4A7 },
{ "cd", 0x1F4BF },
{ "briefcase", 0x1F4BC },
{ "air", 0x1F4A8 },
{ "hourglass", 0x23F3 },
{ "gauge", 0x1F6C7 },
{ "language", 0x1F394 },
{ "network", 0xE776 },
{ "key", 0x1F511 },
{ "battery", 0x1F50B },
{ "bucket", 0x1F4FE },
{ "magnet", 0xE7A1 },
{ "drive", 0x1F4FD },
{ "cup", 0x2615 },
{ "rocket", 0x1F680 },
{ "brush", 0xE79A },
{ "suitcase", 0x1F6C6 },
{ "traffic-cone", 0x1F6C8 },
{ "globe", 0x1F30E },
{ "keyboard", 0x2328 },
{ "browser", 0xE74E },
{ "publish", 0xE74D },
{ "progress-3", 0xE76B },
{ "progress-2", 0xE76A },
{ "progress-1", 0xE769 },
{ "progress-0", 0xE768 },
{ "light-down", 0x1F505 },
{ "light-up", 0x1F506 },
{ "adjust", 0x25D1 },
{ "code", 0xE714 },
{ "monitor", 0x1F4BB },
{ "infinity", 0x221E },
{ "light-bulb", 0x1F4A1 },
{ "credit-card", 0x1F4B3 },
{ "database", 0x1F4F8 },
{ "voicemail", 0x2707 },
{ "clipboard", 0x1F4CB },
{ "cart", 0xE73D },
{ "box", 0x1F4E6 },
{ "ticket", 0x1F3AB },
{ "rss", 0xE73A },
{ "signal", 0x1F4F6 },
{ "thermometer", 0x1F4FF },
{ "water", 0x1F4A6 },
{ "sweden", 0xF601 },
{ "line-graph", 0x1F4C8 },
{ "pie-chart", 0x25F4 },
{ "bar-graph", 0x1F4CA },
{ "area-graph", 0x1F53E },
{ "lock", 0x1F512 },
{ "lock-open", 0x1F513 },
{ "logout", 0xE741 },
{ "login", 0xE740 },
{ "check", 0x2713 },
{ "cross", 0x274C },
{ "squared-minus", 0x229F },
{ "squared-plus", 0x229E },
{ "squared-cross", 0x274E },
{ "circled-minus", 0x2296 },
{ "circled-plus", 0x2295 },
{ "circled-cross", 0x2716 },
{ "minus", 0x2796 },
{ "plus", 0x2795 },
{ "erase", 0x232B },
{ "block", 0x1F6AB },
{ "info", 0x2139 },
{ "circled-info", 0xE705 },
{ "help", 0x2753 },
{ "circled-help", 0xE704 },
{ "warning", 0x26A0 },
{ "cycle", 0x1F504 },
{ "cw", 0x27F3 },
{ "ccw", 0x27F2 },
{ "shuffle", 0x1F500 },
{ "back", 0x1F519 },
{ "level-down", 0x21B3 },
{ "retweet", 0xE717 },
{ "loop", 0x1F501 },
{ "back-in-time", 0xE771 },
{ "level-up", 0x21B0 },
{ "switch", 0x21C6 },
{ "numbered-list", 0xE005 },
{ "add-to-list", 0xE003 },
{ "layout", 0x268F },
{ "list", 0x2630 },
{ "text-doc", 0x1F4C4 },
{ "text-doc-inverted", 0xE731},
{ "doc", 0xE730 },
{ "docs", 0xE736 },
{ "landscape-doc", 0xE737 },
{ "picture", 0x1F304 },
{ "video", 0x1F3AC },
{ "music", 0x1F3B5 },
{ "folder", 0x1F4C1 },
{ "archive", 0xE800 },
{ "trash", 0xE729 },
{ "upload", 0x1F4E4 },
{ "download", 0x1F4E5 },
{ "save", 0x1F4BE },
{ "install", 0xE778 },
{ "cloud", 0x2601 },
{ "upload-cloud", 0xE711 },
{ "bookmark", 0x1F516 },
{ "bookmarks", 0x1F4D1 },
{ "open-book", 0x1F4D6 },
{ "play", 0x25B6 },
{ "paus", 0x2016 },
{ "record", 0x25CF },
{ "stop", 0x25A0 },
{ "ff", 0x23E9 },
{ "fb", 0x23EA },
{ "to-start", 0x23EE },
{ "to-end", 0x23ED },
{ "resize-full", 0xE744 },
{ "resize-small", 0xE746 },
{ "volume", 0x23F7 },
{ "sound", 0x1F50A },
{ "mute", 0x1F507 },
{ "flow-cascade", 0x1F568 },
{ "flow-branch", 0x1F569 },
{ "flow-tree", 0x1F56A },
{ "flow-line", 0x1F56B },
{ "flow-parallel", 0x1F56C },
{ "left-bold", 0xE4AD },
{ "down-bold", 0xE4B0 },
{ "up-bold", 0xE4AF },
{ "right-bold", 0xE4AE },
{ "left", 0x2B05 },
{ "down", 0x2B07 },
{ "up", 0x2B06 },
{ "right", 0x27A1 },
{ "circled-left", 0xE759 },
{ "circled-down", 0xE758 },
{ "circled-up", 0xE75B },
{ "circled-right", 0xE75A },
{ "triangle-left", 0x25C2 },
{ "triangle-down", 0x25BE },
{ "triangle-up", 0x25B4 },
{ "triangle-right", 0x25B8 },
{ "chevron-left", 0xE75D },
{ "chevron-down", 0xE75C },
{ "chevron-up", 0xE75F },
{ "chevron-right", 0xE75E },
{ "chevron-small-left", 0xE761 },
{ "chevron-small-down", 0xE760 },
{ "chevron-small-up", 0xE763 },
{ "chevron-small-right",0xE762 },
{ "chevron-thin-left", 0xE765 },
{ "chevron-thin-down", 0xE764 },
{ "chevron-thin-up", 0xE767 },
{ "chevron-thin-right", 0xE766 },
{ "left-thin", 0x2190 },
{ "down-thin", 0x2193 },
{ "up-thin", 0x2191 },
{ "right-thin", 0x2192 },
{ "arrow-combo", 0xE74F },
{ "three-dots", 0x23F6 },
{ "two-dots", 0x23F5 },
{ "dot", 0x23F4 },
{ "cc", 0x1F545 },
{ "cc-by", 0x1F546 },
{ "cc-nc", 0x1F547 },
{ "cc-nc-eu", 0x1F548 },
{ "cc-nc-jp", 0x1F549 },
{ "cc-sa", 0x1F54A },
{ "cc-nd", 0x1F54B },
{ "cc-pd", 0x1F54C },
{ "cc-zero", 0x1F54D },
{ "cc-share", 0x1F54E },
{ "cc-remix", 0x1F54F },
{ "db-logo", 0x1F5F9 },
{ "db-shape", 0x1F5FA },
/* { "icon-cloud", 0x2601 },
{ "icon-at", 0x0040 },
{ "icon-plus", 0x002B },
{ "icon-arrow_up", 0x2191 },
{ "icon-arrow_down", 0x2193 },
{ "icon-arrow_right", 0x2192 },
{ "icon-arrow_left", 0x2190 },
{ "icon-chevron_down", 0xf004 },
{ "icon-chevron_up", 0xf005 },
{ "icon-chevron_right", 0xf006 },
{ "icon-chevron_left", 0xf007 },
{ "icon-reorder", 0xf008 },
{ "icon-list", 0xf009 },
{ "icon-reorder_square", 0xf00a },
{ "icon-reorder_square_line", 0xf00b },
{ "icon-coverflow", 0xf00c },
{ "icon-coverflow_line", 0xf00d },
{ "icon-pause", 0xf00e },
{ "icon-play", 0xf00f },
{ "icon-step_forward", 0xf010 },
{ "icon-step_backward", 0xf011 },
{ "icon-fast_forward", 0xf012 },
{ "icon-fast_backward", 0xf013 },
{ "icon-cloud_upload", 0xf014 },
{ "icon-cloud_download", 0xf015 },
{ "icon-data_science", 0xf016 },
{ "icon-data_science_black", 0xf017 },
{ "icon-globe", 0xf018 },
{ "icon-globe_black", 0xf019 },
{ "icon-math_ico", 0xf01a },
{ "icon-math", 0xf01b },
{ "icon-math_black", 0xf01c },
{ "icon-paperplane_ico", 0xf01d },
{ "icon-paperplane", 0xf01e },
{ "icon-paperplane_black", 0xf01f },
{ "icon-color_balance", 0xf020 },
{ "icon-star", 0x2605 },
{ "icon-star_half", 0xf022 },
{ "icon-star_empty", 0x2606 },
{ "icon-star_half_empty", 0xf024 },
{ "icon-reload", 0xf025 },
{ "icon-heart", 0x2665 },
{ "icon-heart_broken", 0xf028 },
{ "icon-hashtag", 0xf029 },
{ "icon-reply", 0xf02a },
{ "icon-retweet", 0xf02b },
{ "icon-signin", 0xf02c },
{ "icon-signout", 0xf02d },
{ "icon-download", 0xf02e },
{ "icon-upload", 0xf02f },
{ "icon-placepin", 0xf031 },
{ "icon-display_screen", 0xf032 },
{ "icon-tablet", 0xf033 },
{ "icon-smartphone", 0xf034 },
{ "icon-connected_object", 0xf035 },
{ "icon-lock", 0xF512 },
{ "icon-unlock", 0xF513 },
{ "icon-camera", 0xF4F7 },
{ "icon-isight", 0xf039 },
{ "icon-video_camera", 0xf03a },
{ "icon-random", 0xf03b },
{ "icon-message", 0xF4AC },
{ "icon-discussion", 0xf03d },
{ "icon-calendar", 0xF4C5 },
{ "icon-ringbell", 0xf03f },
{ "icon-movie", 0xf040 },
{ "icon-mail", 0x2709 },
{ "icon-pen", 0x270F },
{ "icon-settings", 0x9881 },
{ "icon-measure", 0xf044 },
{ "icon-vector", 0xf045 },
{ "icon-vector_pen", 0x2712 },
{ "icon-mute_on", 0xf047 },
{ "icon-mute_off", 0xf048 },
{ "icon-home", 0x2302 },
{ "icon-sheet", 0xf04a },
{ "icon-arrow_big_right", 0x21C9 },
{ "icon-arrow_big_left", 0x21C7 },
{ "icon-arrow_big_down", 0x21CA },
{ "icon-arrow_big_up", 0x21C8 },
{ "icon-dribbble_circle", 0xf04f },
{ "icon-dribbble", 0xf050 },
{ "icon-facebook_circle", 0xf051 },
{ "icon-facebook", 0xf052 },
{ "icon-git_circle_alt", 0xf053 },
{ "icon-git_circle", 0xf054 },
{ "icon-git", 0xf055 },
{ "icon-octopus", 0xf056 },
{ "icon-twitter_circle", 0xf057 },
{ "icon-twitter", 0xf058 },
{ "icon-google_plus_circle", 0xf059 },
{ "icon-google_plus", 0xf05a },
{ "icon-linked_in_circle", 0xf05b },
{ "icon-linked_in", 0xf05c },
{ "icon-instagram", 0xf05d },
{ "icon-instagram_circle", 0xf05e },
{ "icon-mfg_icon", 0xf05f },
{ "icon-mfg_icon_circle", 0xf060 },
{ "icon-user", 0xf061 },
{ "icon-user_male", 0xf062 },
{ "icon-user_female", 0xf063 },
{ "icon-users", 0xf064 },
{ "icon-file_open", 0xF4C2 },
{ "icon-file_close", 0xf067 },
{ "icon-file_alt", 0xf068 },
{ "icon-file_close_alt", 0xf069 },
{ "icon-attachment", 0xf06a },
{ "icon-check", 0x2713 },
{ "icon-cross_mark", 0x274C },
{ "icon-cancel_circle", 0xF06E },
{ "icon-check_circle", 0xf06d },
{ "icon-magnifying", 0xF50D },
{ "icon-inbox", 0xf070 },
{ "icon-clock", 0x23F2 },
{ "icon-stopwatch", 0x23F1 },
{ "icon-hourglass", 0x231B },
{ "icon-trophy", 0xf074 },
{ "icon-unlock_alt", 0xF075 },
{ "icon-lock_alt", 0xF510 },
{ "icon-arrow_doubled_right", 0x21D2 },
{ "icon-arrow_doubled_left", 0x21D0 },
{ "icon-arrow_doubled_down", 0x21D3 },
{ "icon-arrow_doubled_up", 0x21D1 },
{ "icon-link", 0xf07B },
{ "icon-warning", 0x2757 },
{ "icon-warning_alt", 0x2755 },
{ "icon-magnifying_plus", 0xf07E },
{ "icon-magnifying_minus", 0xf07F },
{ "icon-white_question", 0x2754 },
{ "icon-black_question", 0x2753 },
{ "icon-stop", 0xf080 },
{ "icon-share", 0xf081 },
{ "icon-eye", 0xf082 },
{ "icon-trash_can", 0xf083 },
{ "icon-hard_drive", 0xf084 },
{ "icon-information_black", 0xf085 },
{ "icon-information_white", 0xf086 },
{ "icon-printer", 0xf087 },
{ "icon-letter", 0xf088 },
{ "icon-soundcloud", 0xf089 },
{ "icon-soundcloud_circle", 0xf08A },
{ "icon-anchor", 0x2693 },
{ "icon-female_sign", 0x2640 },
{ "icon-male_sign", 0x2642 },
{ "icon-joystick", 0xF514 },
{ "icon-high_voltage", 0x26A1 },
{ "icon-fire", 0xF525 },
{ "icon-newspaper", 0xF4F0 },
{ "icon-chart", 0xF526 },
{ "icon-spread", 0xF527 },
{ "icon-spinner_1", 0xF528 },
{ "icon-spinner_2", 0xF529 },
{ "icon-chart_alt", 0xF530 },
{ "icon-label", 0xF531 },*/
};
static const int nicons = sizeof(icons) / sizeof(struct Icon);
int i;
static char str[8];
for (i = 0; i < nicons; i++) {
if (strcmp(icons[i].name, name) == 0) {
cpToUTF8(icons[i].codepoint, str);
return str;
}
}
return "";
}

13
example/images.txt Normal file
View File

@ -0,0 +1,13 @@
Image credits
http://cuteoverload.com/2013/11/05/mom-taxi-xvi-birthday-party/
http://cuteoverload.com/2013/11/05/benson-hedges-private-eye-in-the-case-of-the-crafty-craftsman/
http://cuteoverload.com/2013/11/05/no-underwater-ballets/
http://cuteoverload.com/2013/11/05/every-nose-has-a-story/
http://cuteoverload.com/2013/11/04/nosevember-nozzle-nose/
http://cuteoverload.com/2013/11/04/this-just-in-super-strength-cute/
http://cuteoverload.com/2013/11/03/have-a-bunderful-sunday/
http://cuteoverload.com/2013/11/02/caturday-sense-a-common-theme-here/
http://cuteoverload.com/2013/11/01/nosevember-1st-24-hours-of-noses-1148pm-pt/
http://cuteoverload.com/2013/04/02/there-might-be-something-cuter-than-this/
http://cuteoverload.com/2013/07/17/snorting-micro-peeg-gets-belleh-rubs-interwebs-explode/
http://cuteoverload.com/2013/08/07/bark-in-the-park-v3-0/

BIN
example/images/image1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
example/images/image10.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
example/images/image11.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
example/images/image12.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
example/images/image2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
example/images/image3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
example/images/image4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
example/images/image5.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
example/images/image6.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
example/images/image7.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
example/images/image8.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
example/images/image9.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

84
example/templates.xml Normal file
View File

@ -0,0 +1,84 @@
<style>
$color = rgba(255,255,255,255);
@font-face {
font-family: "Roboto";
font-weight: bold;
src: "../examples/Roboto-light.ttf";
}
@font-face {
font-family: "Entypo";
src: "../examples/entypo.ttf";
}
.icon-search {
font-family: "Entypo";
font-size: 28px;
content: 0x1F50D;
}
.icon-circled-cross {
font-family: "Entypo";
font-size: 28px;
content: 0x2716;
}
.icon-plus {
font-family: "Entypo";
font-size: 28px;
content: "\2796";
}
.search-box {
padding: 5px;
}
.footer-buttons {
padding: 5px;
}
/* default style */
header {
height: 30px;
/*font-size: 26px;*/
}
input {
height: ;
font-size: 26px;
}
</style>
<template id="material-window">
<win width="300px" height="500px" align="justify">
<col align="justify">
<header>Materials</header>
<row height="auto" style="search-box">
<input id="search" grow="1">
<icon style="icon-search" />
<field grow="1" />
<icon style="icon-circled-cross" />
</input>
</row>
<col id="materials" grow="1" height="10px" align="justify" />
<row height="auto" style="footer-buttons">
<spacer grow="1" />
<button id="add-item"><icon style="icon-plus"/>Add</button>
<button id="remove">Remove</button>
</row>
</col>
</win>
</template>
<template id="material-item">
<item padding="4px" align="center">
<img id="thumbnail" width="25px" height="25px" />
<label id="name" grow="1" />
</item>
</template>
<template id="material-noitems">
<col padding="4px" pack="center" align="center">
<icon src="sad-face" />
<label>Sorry, no items found.</label>
</col>
</template>

32
premake4.lua Normal file
View File

@ -0,0 +1,32 @@
local action = _ACTION or ""
solution "nanovg"
location ( "build" )
configurations { "Debug", "Release" }
platforms {"native", "x64", "x32"}
project "example"
kind "ConsoleApp"
language "C"
files { "example/*.c", "src/*.h", "src/*.c" }
includedirs { "src" }
targetdir("build")
configuration { "linux" }
links { "X11","Xrandr", "rt", "GL", "GLU", "pthread" }
configuration { "windows" }
links { "glu32","opengl32", "gdi32", "winmm", "user32" }
configuration { "macosx" }
links { "glfw3" }
linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit" }
configuration "Debug"
defines { "DEBUG" }
flags { "Symbols", "ExtraWarnings"}
configuration "Release"
defines { "NDEBUG" }
flags { "Optimize", "ExtraWarnings"}

1134
src/fontstash.h Normal file

File diff suppressed because it is too large Load Diff

690
src/glnanovg.h Normal file
View File

@ -0,0 +1,690 @@
//
// Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef GLNANOVG_H
#define GLNANOVG_H
struct NVGcontext* glnvgCreate();
void glnvgDelete(struct NVGcontext* ctx);
#endif
#ifdef GLNANOVG_IMPLEMENTATION
#include <stdlib.h>
#include "nanovg.h"
enum GLNVGuniformLoc {
GLNVG_LOC_SCISSORMAT,
GLNVG_LOC_SCISSOREXT,
GLNVG_LOC_PAINTMAT,
GLNVG_LOC_EXTENT,
GLNVG_LOC_RADIUS,
GLNVG_LOC_FEATHER,
GLNVG_LOC_INNERCOL,
GLNVG_LOC_OUTERCOL,
GLNVG_LOC_STROKEMULT,
GLNVG_LOC_TEX,
GLNVG_MAX_LOCS
};
struct GLNVGshader {
GLuint prog;
GLuint frag;
GLuint vert;
GLint loc[GLNVG_MAX_LOCS];
};
struct GLNVGtexture {
int id;
GLuint tex;
int width, height;
int type;
};
struct GLNVGcontext {
struct GLNVGshader gradShader;
struct GLNVGshader imgShader;
struct GLNVGtexture* textures;
int ntextures;
int ctextures;
int textureId;
};
static struct GLNVGtexture* glnvg__allocTexture(struct GLNVGcontext* gl)
{
struct GLNVGtexture* tex = NULL;
int i;
for (i = 0; i < gl->ntextures; i++) {
if (gl->textures[i].id == 0) {
tex = &gl->textures[i];
break;
}
}
if (tex == NULL) {
if (gl->ntextures+1 > gl->ctextures) {
gl->ctextures = (gl->ctextures == 0) ? 2 : gl->ctextures*2;
gl->textures = (struct GLNVGtexture*)realloc(gl->textures, sizeof(struct GLNVGtexture)*gl->ctextures);
if (gl->textures == NULL) return NULL;
}
tex = &gl->textures[gl->ntextures++];
}
memset(tex, 0, sizeof(*tex));
tex->id = ++gl->textureId;
return tex;
}
static struct GLNVGtexture* glnvg__findTexture(struct GLNVGcontext* gl, int id)
{
int i;
for (i = 0; i < gl->ntextures; i++)
if (gl->textures[i].id == id)
return &gl->textures[i];
return NULL;
}
static int glnvg__deleteTexture(struct GLNVGcontext* gl, int id)
{
int i;
for (i = 0; i < gl->ntextures; i++) {
if (gl->textures[i].id == id) {
if (gl->textures[i].tex != 0)
glDeleteTextures(1, &gl->textures[i].tex);
memset(&gl->textures[i], 0, sizeof(gl->textures[i]));
return 1;
}
}
return 0;
}
static void glnvg__dumpShaderError(GLuint shader, const char* name, const char* type)
{
char str[512+1];
int len = 0;
glGetShaderInfoLog(shader, 512, &len, str);
if (len > 512) len = 512;
str[len] = '\0';
printf("Shader %s/%s error:\n%s\n", name, type, str);
}
static void glnvg__dumpProgramError(GLuint prog, const char* name)
{
char str[512+1];
int len = 0;
glGetProgramInfoLog(prog, 512, &len, str);
if (len > 512) len = 512;
str[len] = '\0';
printf("Program %s error:\n%s\n", name, str);
}
static void glnvg__checkError(const char* str)
{
GLenum err = glGetError();
if (err != GL_NO_ERROR) {
printf("Error %08x after %s\n", err, str);
}
}
static int glnvg__createShader(struct GLNVGshader* shader, const char* name, const char* vshader, const char* fshader)
{
GLint status;
GLuint prog, vert, frag;
memset(shader, 0, sizeof(*shader));
prog = glCreateProgram();
vert = glCreateShader(GL_VERTEX_SHADER);
frag = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vert, 1, &vshader, 0);
glShaderSource(frag, 1, &fshader, 0);
glCompileShader(vert);
glGetShaderiv(vert, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
glnvg__dumpShaderError(vert, name, "vert");
return 0;
}
glCompileShader(frag);
glGetShaderiv(frag, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
glnvg__dumpShaderError(frag, name, "frag");
return 0;
}
glAttachShader(prog, vert);
glAttachShader(prog, frag);
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if (status != GL_TRUE) {
glnvg__dumpProgramError(prog, name);
return 0;
}
shader->prog = prog;
shader->vert = vert;
shader->frag = frag;
return 1;
}
static void glnvg__deleteShader(struct GLNVGshader* shader)
{
if (shader->prog != 0)
glDeleteProgram(shader->prog);
if (shader->vert != 0)
glDeleteShader(shader->vert);
if (shader->frag != 0)
glDeleteShader(shader->frag);
}
static int glnvg__renderCreate(void* uptr)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
static const char* fillVertShader =
"#version 120\n"
"varying vec2 pos;\n"
"varying vec2 alpha;\n"
"void main(void) {\n"
" alpha = gl_MultiTexCoord0.st;"
" pos = gl_Vertex.xy;\n"
" gl_Position = ftransform();\n"
"}\n";
static const char* fillFragGradShader =
"#version 120\n"
"uniform mat3 scissorMat;\n"
"uniform vec2 scissorExt;\n"
"uniform mat3 paintMat;\n"
"uniform vec2 extent;\n"
"uniform float radius;\n"
"uniform float feather;\n"
"uniform vec4 innerCol;\n"
"uniform vec4 outerCol;\n"
"uniform float strokeMult;\n"
"varying vec2 pos;\n"
"varying vec2 alpha;\n"
"float sdroundrect(vec2 pt, vec2 ext, float rad) {\n"
" vec2 ext2 = ext - vec2(rad,rad);\n"
" vec2 d = abs(pt) - ext2;\n"
" return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad;\n"
"}\n"
"void main(void) {\n"
" // Scissoring\n"
" vec2 sc = vec2(0.5,0.5) - (abs((scissorMat * vec3(pos,1.0)).xy) - scissorExt);\n"
" float scissor = clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);\n"
// " if (scissor < 0.001) discard;\n"
" // Stroke - from [0..1] to clipped pyramid, where the slope is 1px.\n"
" float strokeAlpha = min(1.0, (1.0-abs(alpha.x*2.0-1.0))*strokeMult) * alpha.y;\n"
" // Calculate gradient color using box gradient\n"
" vec2 pt = (paintMat * vec3(pos,1.0)).xy;\n"
" float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);\n"
" vec4 color = mix(innerCol,outerCol,d);\n"
" // Combine alpha\n"
" color.w *= strokeAlpha * scissor;\n"
" gl_FragColor = color;\n"
"}\n";
static const char* fillFragImgShader =
"#version 120\n"
"uniform mat3 scissorMat;\n"
"uniform vec2 scissorExt;\n"
"uniform mat3 paintMat;\n"
"uniform vec2 extent;\n"
"uniform float strokeMult;\n"
"uniform sampler2D tex;\n"
"varying vec2 pos;\n"
"varying vec2 alpha;\n"
"void main(void) {\n"
" // Scissoring\n"
" vec2 sc = vec2(0.5,0.5) - (abs((scissorMat * vec3(pos,1.0)).xy) - scissorExt);\n"
" float scissor = clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);\n"
// " if (scissor < 0.001) discard;\n"
" // Stroke - from [0..1] to clipped pyramid, where the slope is 1px.\n"
" float strokeAlpha = min(1.0, (1.0-abs(alpha.x*2.0-1.0))*strokeMult) * alpha.y;\n"
" // Calculate color fron texture\n"
" vec2 pt = (paintMat * vec3(pos,1.0)).xy;\n"
" pt /= extent;\n"
" vec4 color = texture2D(tex, pt);\n"
" // Combine alpha\n"
" color.w *= strokeAlpha * scissor;\n"
" gl_FragColor = color;\n"
"}\n";
glnvg__checkError("init");
if (glnvg__createShader(&gl->gradShader, "grad", fillVertShader, fillFragGradShader) == 0)
return 0;
glnvg__checkError("grad");
gl->gradShader.loc[GLNVG_LOC_SCISSORMAT] = glGetUniformLocation(gl->gradShader.prog, "scissorMat");
gl->gradShader.loc[GLNVG_LOC_SCISSOREXT] = glGetUniformLocation(gl->gradShader.prog, "scissorExt");
gl->gradShader.loc[GLNVG_LOC_PAINTMAT] = glGetUniformLocation(gl->gradShader.prog, "paintMat");
gl->gradShader.loc[GLNVG_LOC_EXTENT] = glGetUniformLocation(gl->gradShader.prog, "extent");
gl->gradShader.loc[GLNVG_LOC_RADIUS] = glGetUniformLocation(gl->gradShader.prog, "radius");
gl->gradShader.loc[GLNVG_LOC_FEATHER] = glGetUniformLocation(gl->gradShader.prog, "feather");
gl->gradShader.loc[GLNVG_LOC_INNERCOL] = glGetUniformLocation(gl->gradShader.prog, "innerCol");
gl->gradShader.loc[GLNVG_LOC_OUTERCOL] = glGetUniformLocation(gl->gradShader.prog, "outerCol");
gl->gradShader.loc[GLNVG_LOC_STROKEMULT] = glGetUniformLocation(gl->gradShader.prog, "strokeMult");
glnvg__checkError("grad loc");
if (glnvg__createShader(&gl->imgShader, "image", fillVertShader, fillFragImgShader) == 0)
return 0;
glnvg__checkError("image");
gl->imgShader.loc[GLNVG_LOC_SCISSORMAT] = glGetUniformLocation(gl->imgShader.prog, "scissorMat");
gl->imgShader.loc[GLNVG_LOC_SCISSOREXT] = glGetUniformLocation(gl->imgShader.prog, "scissorExt");
gl->imgShader.loc[GLNVG_LOC_PAINTMAT] = glGetUniformLocation(gl->imgShader.prog, "paintMat");
gl->imgShader.loc[GLNVG_LOC_EXTENT] = glGetUniformLocation(gl->imgShader.prog, "extent");
// gl->gradShader.loc[GLNVG_LOC_RADIUS] = glGetUniformLocation(gl->gradShader.prog, "radius");
// gl->gradShader.loc[GLNVG_LOC_FEATHER] = glGetUniformLocation(gl->gradShader.prog, "feather");
// gl->gradShader.loc[GLNVG_LOC_INNERCOL] = glGetUniformLocation(gl->gradShader.prog, "innerCol");
// gl->gradShader.loc[GLNVG_LOC_OUTERCOL] = glGetUniformLocation(gl->gradShader.prog, "outerCol");
gl->imgShader.loc[GLNVG_LOC_STROKEMULT] = glGetUniformLocation(gl->imgShader.prog, "strokeMult");
gl->imgShader.loc[GLNVG_LOC_TEX] = glGetUniformLocation(gl->imgShader.prog, "tex");
glnvg__checkError("image loc");
return 1;
}
static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, const unsigned char* data)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
struct GLNVGtexture* tex = glnvg__allocTexture(gl);
if (tex == NULL) return 0;
glGenTextures(1, &tex->tex);
tex->width = w;
tex->height = h;
tex->type = type;
glBindTexture(GL_TEXTURE_2D, tex->tex);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->width);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
if (type == NVG_TEXTURE_RGBA)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glnvg__checkError("create tex");
return tex->id;
}
static int glnvg__renderDeleteTexture(void* uptr, int image)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
return glnvg__deleteTexture(gl, image);
}
static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
struct GLNVGtexture* tex = glnvg__findTexture(gl, image);
if (tex == NULL) return 0;
glBindTexture(GL_TEXTURE_2D, tex->tex);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->width);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
if (tex->type == NVG_TEXTURE_RGBA)
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data);
else
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_ALPHA, GL_UNSIGNED_BYTE, data);
return 1;
}
static int glnvg__renderGetTextureSize(void* uptr, int image, int* w, int* h)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
struct GLNVGtexture* tex = glnvg__findTexture(gl, image);
if (tex == NULL) return 0;
*w = tex->width;
*h = tex->height;
return 1;
}
static void glnvg__toFloatColor(float* fc, unsigned int c)
{
fc[0] = ((c) & 0xff) / 255.0f;
fc[1] = ((c>>8) & 0xff) / 255.0f;
fc[2] = ((c>>16) & 0xff) / 255.0f;
fc[3] = ((c>>24) & 0xff) / 255.0f;
}
static void glnvg__xformIdentity(float* t)
{
t[0] = 1.0f; t[1] = 0.0f;
t[2] = 0.0f; t[3] = 1.0f;
t[4] = 0.0f; t[5] = 0.0f;
}
static void glnvg__xformInverse(float* inv, float* t)
{
double det = (double)t[0] * t[3] - (double)t[2] * t[1];
if (det > -1e-6 && det < -1e-6) {
glnvg__xformIdentity(t);
return;
}
double invdet = 1.0 / det;
inv[0] = (float)(t[3] * invdet);
inv[2] = (float)(-t[2] * invdet);
inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet);
inv[1] = (float)(-t[1] * invdet);
inv[3] = (float)(t[0] * invdet);
inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet);
}
static void glnvg__xformToMat3x3(float* m3, float* t)
{
m3[0] = t[0];
m3[1] = t[1];
m3[2] = 0.0f;
m3[3] = t[2];
m3[4] = t[3];
m3[5] = 0.0f;
m3[6] = t[4];
m3[7] = t[5];
m3[8] = 1.0f;
}
static int glnvg__setupPaint(struct GLNVGcontext* gl, struct NVGpaint* paint, struct NVGscissor* scissor,
float width, float aasize)
{
float innerCol[4];
float outerCol[4];
glnvg__toFloatColor(innerCol, paint->innerColor);
glnvg__toFloatColor(outerCol, paint->outerColor);
struct GLNVGtexture* tex = NULL;
float invxform[6], paintMat[9], scissorMat[9];
float scissorx = 0, scissory = 0;
glnvg__xformInverse(invxform, paint->xform);
glnvg__xformToMat3x3(paintMat, invxform);
if (scissor->extent[0] < 0.5f || scissor->extent[1] < 0.5f) {
memset(scissorMat, 0, sizeof(scissorMat));
scissorx = 1.0f;
scissory = 1.0f;
} else {
glnvg__xformInverse(invxform, scissor->xform);
glnvg__xformToMat3x3(scissorMat, invxform);
scissorx = scissor->extent[0];
scissory = scissor->extent[1];
}
if (paint->image != 0) {
tex = glnvg__findTexture(gl, paint->image);
if (tex == NULL) return 0;
glUseProgram(gl->imgShader.prog);
glUniformMatrix3fv(gl->imgShader.loc[GLNVG_LOC_SCISSORMAT], 1, GL_FALSE, scissorMat);
glUniform2f(gl->imgShader.loc[GLNVG_LOC_SCISSOREXT], scissorx, scissory);
glUniformMatrix3fv(gl->imgShader.loc[GLNVG_LOC_PAINTMAT], 1, GL_FALSE, paintMat);
glUniform2f(gl->imgShader.loc[GLNVG_LOC_EXTENT], paint->extent[0], paint->extent[1]);
glUniform1f(gl->imgShader.loc[GLNVG_LOC_STROKEMULT], width*0.5f + aasize*0.5f);
glUniform1i(gl->imgShader.loc[GLNVG_LOC_TEX], 0);
glnvg__checkError("tex paint loc");
glBindTexture(GL_TEXTURE_2D, tex->tex);
glEnable(GL_TEXTURE_2D);
glnvg__checkError("tex paint tex");
} else {
glUseProgram(gl->gradShader.prog);
glUniformMatrix3fv(gl->gradShader.loc[GLNVG_LOC_SCISSORMAT], 1, GL_FALSE, scissorMat);
glUniform2f(gl->gradShader.loc[GLNVG_LOC_SCISSOREXT], scissorx, scissory);
glUniformMatrix3fv(gl->gradShader.loc[GLNVG_LOC_PAINTMAT], 1, GL_FALSE, paintMat);
glUniform2f(gl->gradShader.loc[GLNVG_LOC_EXTENT], paint->extent[0], paint->extent[1]);
glUniform1f(gl->gradShader.loc[GLNVG_LOC_RADIUS], paint->radius);
glUniform1f(gl->gradShader.loc[GLNVG_LOC_FEATHER], paint->feather);
glUniform4fv(gl->gradShader.loc[GLNVG_LOC_INNERCOL], 1, innerCol);
glUniform4fv(gl->gradShader.loc[GLNVG_LOC_OUTERCOL], 1, outerCol);
glUniform1f(gl->gradShader.loc[GLNVG_LOC_STROKEMULT], width*0.5f + aasize*0.5f);
glnvg__checkError("grad paint loc");
}
return 1;
}
static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float aasize,
const float* bounds, const struct NVGpath* paths, int npaths)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
const struct NVGpath* path;
int i;
if (gl->gradShader.prog == 0)
return;
glEnable(GL_CULL_FACE);
glEnableClientState(GL_VERTEX_ARRAY);
// Draw shapes
glDisable(GL_BLEND);
glEnable(GL_STENCIL_TEST);
glStencilMask(0xff);
glStencilFunc(GL_ALWAYS, 0, ~0);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
glDisable(GL_CULL_FACE);
for (i = 0; i < npaths; i++) {
path = &paths[i];
glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->fill[0].x);
glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill);
}
/* glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP);
glCullFace(GL_BACK);
for (i = 0; i < npaths; i++) {
path = &paths[i];
glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->fill[0].x);
glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill);
}
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP);
glCullFace(GL_FRONT);
for (i = 0; i < npaths; i++) {
path = &paths[i];
glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->fill[0].x);
glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill);
}
glCullFace(GL_BACK);*/
glEnable(GL_CULL_FACE);
// Draw aliased off-pixels
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_BLEND);
glStencilFunc(GL_EQUAL, 0x00, 0xff);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glnvg__setupPaint(gl, paint, scissor, 1.0001f, aasize);
// Draw fringes
for (i = 0; i < npaths; i++) {
path = &paths[i];
glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->stroke[0].x);
glTexCoordPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->stroke[0].u);
glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// Draw fill
glStencilFunc(GL_NOTEQUAL, 0x0, 0xff);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
// glUseProgram(0);
// glColor4ub(255,0,0,128);
glBegin(GL_QUADS);
glTexCoord2f(0.5f,1.0f);
glVertex2f(bounds[0], bounds[3]);
glVertex2f(bounds[2], bounds[3]);
glVertex2f(bounds[2], bounds[1]);
glVertex2f(bounds[0], bounds[1]);
glEnd();
glUseProgram(0);
glDisable(GL_TEXTURE_2D);
glDisable(GL_STENCIL_TEST);
}
static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float aasize,
float width, const struct NVGpath* paths, int npaths)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
const struct NVGpath* path;
int i;
if (gl->gradShader.prog == 0)
return;
glnvg__setupPaint(gl, paint, scissor, width, aasize);
glEnable(GL_CULL_FACE);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Draw Strokes
for (i = 0; i < npaths; i++) {
path = &paths[i];
glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->stroke[0].x);
glTexCoordPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->stroke[0].u);
glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glUseProgram(0);
glDisable(GL_TEXTURE_2D);
}
static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, int image,
const struct NVGvertex* verts, int nverts)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
struct GLNVGtexture* tex = glnvg__findTexture(gl, image);
float color[4];
if (tex != NULL) {
glBindTexture(GL_TEXTURE_2D, tex->tex);
glEnable(GL_TEXTURE_2D);
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glnvg__toFloatColor(color, paint->innerColor);
glColor4fv(color);
glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &verts[0].x);
glTexCoordPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &verts[0].u);
glDrawArrays(GL_TRIANGLES, 0, nverts);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
}
static void glnvg__renderDelete(void* uptr)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
int i;
if (gl == NULL) return;
glnvg__deleteShader(&gl->gradShader);
glnvg__deleteShader(&gl->imgShader);
for (i = 0; i < gl->ntextures; i++) {
if (gl->textures[i].tex != 0)
glDeleteTextures(1, &gl->textures[i].tex);
}
free(gl->textures);
free(gl);
}
struct NVGcontext* glnvgCreate()
{
struct NVGparams params;
struct NVGcontext* ctx = NULL;
struct GLNVGcontext* gl = (struct GLNVGcontext*)malloc(sizeof(struct GLNVGcontext));
if (gl == NULL) goto error;
memset(gl, 0, sizeof(struct GLNVGcontext));
memset(&params, 0, sizeof(params));
params.renderCreate = glnvg__renderCreate;
params.renderCreateTexture = glnvg__renderCreateTexture;
params.renderDeleteTexture = glnvg__renderDeleteTexture;
params.renderUpdateTexture = glnvg__renderUpdateTexture;
params.renderGetTextureSize = glnvg__renderGetTextureSize;
params.renderFill = glnvg__renderFill;
params.renderStroke = glnvg__renderStroke;
params.renderTriangles = glnvg__renderTriangles;
params.renderDelete = glnvg__renderDelete;
params.userPtr = gl;
ctx = nvgCreateInternal(&params);
if (ctx == NULL) goto error;
return ctx;
error:
if (gl != NULL) free(gl);
if (ctx != NULL) nvgDeleteInternal(ctx);
return NULL;
}
void glnvgDelete(struct NVGcontext* ctx)
{
nvgDeleteInternal(ctx);
}
#endif

1586
src/nanovg.c Normal file

File diff suppressed because it is too large Load Diff

194
src/nanovg.h Normal file
View File

@ -0,0 +1,194 @@
//
// Copyright (c) 2013 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef NANOVG_H
#define NANOVG_H
#define NVG_PI 3.14159265358979323846264338327f
enum NVGdir {
NVG_CCW = 1,
NVG_CW = 2,
};
enum NVGdir2 {
NVG_SOLID = 1, // ccw
NVG_HOLE = 2, // cw
};
enum NVGpatternRepeat {
NVG_REPEATX = 0x01,
NVG_REPEATY = 0x02,
};
enum NVGaling {
// Horizontal align
NVG_ALIGN_LEFT = 1<<0, // Default
NVG_ALIGN_CENTER = 1<<1,
NVG_ALIGN_RIGHT = 1<<2,
// Vertical align
NVG_ALIGN_TOP = 1<<3,
NVG_ALIGN_MIDDLE = 1<<4,
NVG_ALIGN_BOTTOM = 1<<5,
NVG_ALIGN_BASELINE = 1<<6, // Default
};
// Used by the rendering API
enum NVGtexture {
NVG_TEXTURE_ALPHA = 0x01,
NVG_TEXTURE_RGBA = 0x02,
};
struct NVGpaint
{
float xform[6];
float extent[2];
float radius;
float feather;
unsigned int innerColor;
unsigned int outerColor;
int image;
int repeat;
};
struct NVGscissor
{
float xform[6];
float extent[2];
};
struct NVGvertex {
float x,y,u,v;
};
struct NVGpath {
int first;
int count;
unsigned char closed;
int nbevel;
struct NVGvertex* fill;
int nfill;
struct NVGvertex* stroke;
int nstroke;
int winding;
};
struct NVGparams {
void* userPtr;
int (*renderCreate)(void* uptr);
int (*renderCreateTexture)(void* uptr, int type, int w, int h, const unsigned char* data);
int (*renderDeleteTexture)(void* uptr, int image);
int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data);
int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h);
void (*renderFill)(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float aasize, const float* bounds, const struct NVGpath* paths, int npaths);
void (*renderStroke)(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float aasize, float strokeWidth, const struct NVGpath* paths, int npaths);
void (*renderTriangles)(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, int image, const struct NVGvertex* verts, int nverts);
void (*renderDelete)(void* uptr);
};
// Contructor and destructor.
struct NVGcontext* nvgCreateInternal(struct NVGparams* params);
void nvgDeleteInternal(struct NVGcontext* ctx);
// Color utils
unsigned int nvgRGB(unsigned char r, unsigned char g, unsigned char b);
unsigned int nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
unsigned int nvgLerpRGBA(unsigned int c0, unsigned int c1, float u);
// State handling
void nvgSave(struct NVGcontext* ctx);
void nvgRestore(struct NVGcontext* ctx);
void nvgReset(struct NVGcontext* ctx);
// State setting
void nvgStrokeColor(struct NVGcontext* ctx, unsigned int color);
void nvgStrokePaint(struct NVGcontext* ctx, struct NVGpaint paint);
void nvgFillColor(struct NVGcontext* ctx, unsigned int color);
void nvgFillPaint(struct NVGcontext* ctx, struct NVGpaint paint);
void nvgMiterLimit(struct NVGcontext* ctx, float limit);
void nvgStrokeWidth(struct NVGcontext* ctx, float size);
void nvgResetTransform(struct NVGcontext* ctx);
void nvgTransform(struct NVGcontext* ctx, float a, float b, float c, float d, float e, float f);
void nvgTranslate(struct NVGcontext* ctx, float x, float y);
void nvgRotate(struct NVGcontext* ctx, float angle);
void nvgScale(struct NVGcontext* ctx, float x, float y);
// Images
int nvgCreateImage(struct NVGcontext* ctx, const char* filename);
int nvgCreateImageMem(struct NVGcontext* ctx, unsigned char* data, int ndata, int freeData);
int nvgCreateImageRGBA(struct NVGcontext* ctx, int w, int h, const unsigned char* data);
void nvgUpdateImage(struct NVGcontext* ctx, int image, const unsigned char* data);
void nvgImageSize(struct NVGcontext* ctx, int image, int* w, int* h);
void nvgDeleteImage(struct NVGcontext* ctx, int image);
// Paints
struct NVGpaint nvgLinearGradient(struct NVGcontext* ctx, float sx, float sy, float ex, float ey, unsigned int icol, unsigned int ocol);
struct NVGpaint nvgBoxGradient(struct NVGcontext* ctx, float x, float y, float w, float h, float r, float f, unsigned int icol, unsigned int ocol);
struct NVGpaint nvgRadialGradient(struct NVGcontext* ctx, float cx, float cy, float inr, float outr, unsigned int icol, unsigned int ocol);
struct NVGpaint nvgImagePattern(struct NVGcontext* ctx, float ox, float oy, float ex, float ey, float angle, int image, int repeat);
// Scissoring
void nvgScissor(struct NVGcontext* ctx, float x, float y, float w, float h);
void nvgResetScissor(struct NVGcontext* ctx);
// Draw
void nvgBeginFrame(struct NVGcontext* ctx);
void nvgBeginPath(struct NVGcontext* ctx);
void nvgMoveTo(struct NVGcontext* ctx, float x, float y);
void nvgLineTo(struct NVGcontext* ctx, float x, float y);
void nvgBezierTo(struct NVGcontext* ctx, float c1x, float c1y, float c2x, float c2y, float x, float y);
void nvgArcTo(struct NVGcontext* ctx, float x1, float y1, float x2, float y2, float radius);
void nvgClosePath(struct NVGcontext* ctx);
void nvgPathWinding(struct NVGcontext* ctx, int dir);
void nvgArc(struct NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir);
void nvgRect(struct NVGcontext* ctx, float x, float y, float w, float h);
void nvgRoundedRect(struct NVGcontext* ctx, float x, float y, float w, float h, float r);
void nvgEllipse(struct NVGcontext* ctx, float cx, float cy, float rx, float ry);
void nvgCircle(struct NVGcontext* ctx, float cx, float cy, float r);
void nvgFill(struct NVGcontext* ctx);
void nvgStroke(struct NVGcontext* ctx);
// Text
// Add fonts
int nvgCreateFont(struct NVGcontext* ctx, const char* name, const char* path);
int nvgCreateFontMem(struct NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData);
// State setting
void nvgFontSize(struct NVGcontext* ctx, float size);
void nvgLetterSpacing(struct NVGcontext* ctx, float spacing);
void nvgFontBlur(struct NVGcontext* ctx, float blur);
void nvgTextAlign(struct NVGcontext* ctx, int align);
void nvgFontFaceId(struct NVGcontext* ctx, int font);
void nvgFontFace(struct NVGcontext* ctx, const char* font);
// Draw text
void nvgText(struct NVGcontext* ctx, float x, float y, const char* string);
// Measure text
void nvgTextBounds(struct NVGcontext* ctx, const char* string, float* width, float* bounds);
void nvgVertMetrics(struct NVGcontext* ctx, float* ascender, float* descender, float* lineh);
#endif // NANOVG_H

4673
src/stb_image.c Normal file

File diff suppressed because it is too large Load Diff

2065
src/stb_truetype.h Normal file

File diff suppressed because it is too large Load Diff