diff --git a/.gitmodules b/.gitmodules index 274bedd..a93cf8f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "deps/glew"] path = deps/glew - url = https://github.com/native-toolkit/glew + url = https://github.com/native-toolkit/glew \ No newline at end of file diff --git a/README.md b/README.md index 2abe583..01438ce 100755 --- a/README.md +++ b/README.md @@ -17,6 +17,9 @@ haxelib dev hx-nanovg hx-nanovg #### Included Demo: ![hx-nanovg](http://developium.net/pics/nanovg2.png) +#### Include Example from the ported original NanoVG (not perfect): +![hx-nanovg example](https://dl.dropboxusercontent.com/u/79150615/nanovg_example_in_haxe.png) + #### Notes: * Demo uses Lime (stencil buffer enabled!) * uses https://github.com/native-toolkit/glew as submodule diff --git a/demo/demo.lime.xml b/demo/demo.lime.xml index ead2897..0f3d395 100755 --- a/demo/demo.lime.xml +++ b/demo/demo.lime.xml @@ -1,8 +1,8 @@ - - + + diff --git a/demo/src/Demo.hx b/demo/src/Demo.hx deleted file mode 100755 index 4f6a4bd..0000000 --- a/demo/src/Demo.hx +++ /dev/null @@ -1,53 +0,0 @@ -package; - -import lime.gl.GL; -import hxnanovg.Nvg; -import lime.Lime; - -using cpp.NativeString; - -@:buildXml("&") -class Demo { - - private var lime:Lime; - - var vg:cpp.Pointer; - var font:Int; - var linearGradient:NvgPaint; - - public function new () {} - - public function ready (lime:Lime):Void { - this.lime = lime; - - vg = Nvg.createGL(NvgMode.ANTIALIAS); - font = Nvg.createFont(vg, "arial".c_str(), "assets/arial.ttf".c_str()); - linearGradient = Nvg.linearGradient(vg, 0, 0, 500, 500, Nvg.rgba(255,192,0,255), Nvg.rgba(0,0,0,255)); - } - private function render ():Void { - - GL.viewport (0, 0, lime.config.width, lime.config.height); - GL.clearColor (0.3, 0.3, 0.3, 1.0); - GL.clear (GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT | GL.STENCIL_BUFFER_BIT); - - Nvg.beginFrame(vg, 800, 600, 1.0); - - Nvg.rect(vg, 100,100, 500,300); - Nvg.circle(vg, 120,120, 250); - Nvg.pathWinding(vg, NvgSolidity.HOLE); // Mark circle as a hole. - Nvg.fillPaint(vg, linearGradient); - Nvg.fill(vg); - - Nvg.fontFaceId(vg, font); - Nvg.fillColor(vg, Nvg.rgba(255,0,0,255)); - Nvg.text(vg, 50, 50, "This is some text".c_str(), untyped __cpp__("NULL")); - - Nvg.fontSize(vg, 100.0); - Nvg.fontFaceId(vg, font); - Nvg.fillColor(vg, Nvg.rgba(255,255,255,64)); - Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT|NvgAlign.ALIGN_MIDDLE); - Nvg.text(vg, 100, 100, "Some other text!".c_str(), untyped __cpp__("NULL")); - - Nvg.endFrame(vg); - } -} diff --git a/demo/src/Main.hx b/demo/src/Main.hx new file mode 100644 index 0000000..81fa619 --- /dev/null +++ b/demo/src/Main.hx @@ -0,0 +1,83 @@ +package; + +import hxnanovg.Nvg; +import lime.app.Application; +import lime.graphics.opengl.GL; +import lime.graphics.RenderContext; +import lime.graphics.GLRenderContext; + +using cpp.NativeString; + +@:buildXml("&") +class Main extends Application +{ + private var ctx:GLRenderContext; + + var vg:cpp.Pointer; + var linearGradient:NvgPaint; + var font:Int; + + public function new() + { + super(); + } + + public override function init(context:RenderContext):Void + { + updateSavedContext(context); + + vg = Nvg.createGL(NvgMode.ANTIALIAS); + font = Nvg.createFont(vg, "arial".c_str(), "assets/times.ttf".c_str()); + linearGradient = Nvg.linearGradient(vg, 0, 0, 500, 500, Nvg.rgba(255, 192, 0, 255), Nvg.rgba(0, 0, 0, 255)); + } + + public override function render(context:RenderContext):Void + { + updateSavedContext(context); + + GL.viewport(0, 0, config.width, config.height); + GL.clearColor(0.3, 0.3, 0.3, 1.0); + GL.clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT | GL.STENCIL_BUFFER_BIT); + + Nvg.beginFrame(vg, 800, 600, 1.0); + + Nvg.rect(vg, 100, 100, 500, 300); + Nvg.circle(vg, 120, 120, 250); + Nvg.pathWinding(vg, NvgSolidity.HOLE); // Mark circle as a hole. + Nvg.fillPaint(vg, linearGradient); + Nvg.fill(vg); + +//* + Nvg.fontSize(vg, 30.0); + Nvg.fontFaceId(vg, font); + Nvg.fillColor(vg, Nvg.rgba(255, 0, 0, 255)); + Nvg.text(vg, 50, 50, "This is some text: اقتصادية".c_str(), untyped __cpp__("NULL")); + + Nvg.fontSize(vg, 100.0); + Nvg.fontFaceId(vg, font); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 64)); + Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, 100, 100, "Some other text!".c_str(), untyped __cpp__("NULL")); +//*/ + Nvg.closePath(vg); + + Nvg.beginPath(vg); + Nvg.moveTo(vg, 0, 400); + Nvg.bezierTo(vg, 50, 100, 300, 600, 400, 50); + Nvg.strokeWidth(vg, 2); + Nvg.strokeColor(vg, Nvg.rgba(0, 255, 255, 255)); + Nvg.stroke(vg); + + Nvg.endFrame(vg); + } + + + function updateSavedContext(context:RenderContext):Void + { + switch(context) + { + case RenderContext.OPENGL(gl): ctx = gl; + default: null; + } + } +} \ No newline at end of file diff --git a/example/NanovgDemo.hxproj b/example/NanovgDemo.hxproj new file mode 100644 index 0000000..02f300c --- /dev/null +++ b/example/NanovgDemo.hxproj @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "$(CompilerPath)/haxelib" run lime build "$(OutputFile)" $(TargetBuild) -$(BuildConfig) -Dfdb + + + + + + + + \ No newline at end of file diff --git a/example/assets/Roboto-Bold.ttf b/example/assets/Roboto-Bold.ttf new file mode 100644 index 0000000..aaf374d Binary files /dev/null and b/example/assets/Roboto-Bold.ttf differ diff --git a/example/assets/Roboto-Light.ttf b/example/assets/Roboto-Light.ttf new file mode 100644 index 0000000..664e1b2 Binary files /dev/null and b/example/assets/Roboto-Light.ttf differ diff --git a/example/assets/Roboto-Regular.ttf b/example/assets/Roboto-Regular.ttf new file mode 100644 index 0000000..3e6e2e7 Binary files /dev/null and b/example/assets/Roboto-Regular.ttf differ diff --git a/example/assets/entypo.ttf b/example/assets/entypo.ttf new file mode 100644 index 0000000..fc305d2 Binary files /dev/null and b/example/assets/entypo.ttf differ diff --git a/example/assets/images/image1.jpg b/example/assets/images/image1.jpg new file mode 100644 index 0000000..c2ce39b Binary files /dev/null and b/example/assets/images/image1.jpg differ diff --git a/example/assets/images/image10.jpg b/example/assets/images/image10.jpg new file mode 100644 index 0000000..d443fb0 Binary files /dev/null and b/example/assets/images/image10.jpg differ diff --git a/example/assets/images/image11.jpg b/example/assets/images/image11.jpg new file mode 100644 index 0000000..7429fe5 Binary files /dev/null and b/example/assets/images/image11.jpg differ diff --git a/example/assets/images/image12.jpg b/example/assets/images/image12.jpg new file mode 100644 index 0000000..eb0369d Binary files /dev/null and b/example/assets/images/image12.jpg differ diff --git a/example/assets/images/image2.jpg b/example/assets/images/image2.jpg new file mode 100644 index 0000000..1db15ab Binary files /dev/null and b/example/assets/images/image2.jpg differ diff --git a/example/assets/images/image3.jpg b/example/assets/images/image3.jpg new file mode 100644 index 0000000..884f9f2 Binary files /dev/null and b/example/assets/images/image3.jpg differ diff --git a/example/assets/images/image4.jpg b/example/assets/images/image4.jpg new file mode 100644 index 0000000..f6e1039 Binary files /dev/null and b/example/assets/images/image4.jpg differ diff --git a/example/assets/images/image5.jpg b/example/assets/images/image5.jpg new file mode 100644 index 0000000..d952d16 Binary files /dev/null and b/example/assets/images/image5.jpg differ diff --git a/example/assets/images/image6.jpg b/example/assets/images/image6.jpg new file mode 100644 index 0000000..f098087 Binary files /dev/null and b/example/assets/images/image6.jpg differ diff --git a/example/assets/images/image7.jpg b/example/assets/images/image7.jpg new file mode 100644 index 0000000..623b4cb Binary files /dev/null and b/example/assets/images/image7.jpg differ diff --git a/example/assets/images/image8.jpg b/example/assets/images/image8.jpg new file mode 100644 index 0000000..123b6da Binary files /dev/null and b/example/assets/images/image8.jpg differ diff --git a/example/assets/images/image9.jpg b/example/assets/images/image9.jpg new file mode 100644 index 0000000..045fadb Binary files /dev/null and b/example/assets/images/image9.jpg differ diff --git a/example/assets/lime.svg b/example/assets/lime.svg new file mode 100644 index 0000000..98fa176 --- /dev/null +++ b/example/assets/lime.svg @@ -0,0 +1,54 @@ + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/project.xml b/example/project.xml new file mode 100644 index 0000000..65c5d99 --- /dev/null +++ b/example/project.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/example/screenshot.png b/example/screenshot.png new file mode 100644 index 0000000..94724d2 Binary files /dev/null and b/example/screenshot.png differ diff --git a/example/src/DbgTrace.hx b/example/src/DbgTrace.hx new file mode 100644 index 0000000..4c69f49 --- /dev/null +++ b/example/src/DbgTrace.hx @@ -0,0 +1,42 @@ +package; +import cpp.Pointer; +import cpp.Char; +import cpp.ConstPointer; +import cpp.Pointer; +import hxnanovg.Nvg; + +using cpp.NativeString; + +/** + * ... + * @author Hortobágyi Tamás + */ +class DbgTrace +{ + var text:String = ""; + + var fontID:Int; + + public function new(fontID:Int) + { + this.fontID = fontID; + } + + public function log(s:String) + { + text += (text.length > 0 ? "\n" : "") + s; + } + + public function render(vg:Pointer) + { + if (text.length > 0) + { + Nvg.fontSize(vg, 14.0); + Nvg.fontFaceId(vg, fontID); + Nvg.fillColor(vg, Nvg.rgb(255, 0, 0)); + + Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT | NvgAlign.ALIGN_TOP); + Nvg.textBox(vg, 10, 100, 400, text.c_str(), untyped __cpp__("NULL")); + } + } +} \ No newline at end of file diff --git a/example/src/Demo.hx b/example/src/Demo.hx new file mode 100644 index 0000000..7a3c04f --- /dev/null +++ b/example/src/Demo.hx @@ -0,0 +1,1125 @@ +package; + +import cpp.NativeArray; +import cpp.Pointer; +import cpp.Char; +import cpp.ConstPointer; +import cpp.Pointer; +import hxnanovg.Nvg; +import haxe.Utf8; +import cpp.Lib; + +using cpp.NativeString; +//using cpp.NativeArray; + +/** + * ... + * @author Thomas Hortobágyi + */ +class Demo +{ + public static inline var ICON_SEARCH:Int = 0x1F50D; + public static inline var ICON_CIRCLED_CROSS:Int = 0x2716; + public static inline var ICON_CHEVRON_RIGHT:Int = 0xE75E; + public static inline var ICON_CHECK:Int = 0x2713; + public static inline var ICON_LOGIN:Int = 0xE740; + public static inline var ICON_TRASH:Int = 0xE729; + + public static inline function maxf(a:Float, b:Float):Float { return (a < b ? a : b); } + + public static inline function clampf(a:Float, mn:Float, mx:Float):Float { return (a < mn ? mn : (a > mx ? mx : a)); } + + public static inline function isBlack(col:Pointer):Bool + { + return (col.ref.r == 0.0 && col.ref.g == 0.0 && col.ref.b == 0.0/* && col.ref.a == 0.0*/); + } + + public static function cpToUTF8(cp:Int):String + { + var s:Utf8 = new Utf8(); + s.addChar(cp); + + return s.toString(); + } + + public var fontIconsID:Int; + public var fontSansID:Int; + public var fontSansBoldID:Int; + + private var _t:Float = 0.0; + + private var images:Array = []; + + public function new(_vg:Pointer) + { + loadDemoData(_vg); + } + + public function render(_vg:Pointer, mx:Float, my:Float, width:Float, height:Float, blowup:Int) + { + drawEyes(_vg, width - 250, 50, 150, 100, mx, my, _t); + drawParagraph(_vg, width - 450, 50, 150, 100, mx, my); + drawGraph(_vg, 0, height / 2, width, height / 2, _t); + drawColorwheel(_vg, width - 300, height - 300, 250.0, 250.0, _t); + + // Line joints + drawLines(_vg, 120, height - 50, 600, 50, _t); + + // Line caps + drawWidths(_vg, 10, 50, 30); + + // Line caps + drawCaps(_vg, 10, 300, 30); + + //drawScissor(_vg, 50, height - 80, _t); + + Nvg.save(_vg); + if (blowup != 0) + { + Nvg.rotate(_vg, Math.sin(_t * 0.3) * 5.0 / 180.0 * Math.PI); + Nvg.scale(_vg, 2.0, 2.0); + } + + // Widgets + drawWindow(_vg, "Widgets `n Stuff", 50, 50, 300, 400); + var x:Float = 60, y:Float = 95; + drawSearchBox(_vg, "Search", x, y, 280, 25); + y += 40; + drawDropDown(_vg, "Effects", x, y, 280, 28); + var popy:Float = 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, [0, 96, 128, 255]); + y += 45; + + // Slider + drawLabel(_vg, "Diameter", x, y, 280, 20); + y += 25; + var percent:Float = clampf(Math.cos(_t) * 1.5, 0, 1); + var value:Float = Math.round(30000 * percent) / 100; + var value_str:String = value == 0 ? "0.00" : Std.string(value); + if (value_str.lastIndexOf(".") == -1) value_str += ".00"; + else if (value_str.lastIndexOf(".") == value_str.length - 2) value_str += "0"; + + drawEditBoxNum(_vg, value_str, "px", x + 180, y, 100, 28); + drawSlider(_vg, percent, x, y, 170, 28); + y += 55; + + drawButton(_vg, ICON_TRASH, "Delete", x, y, 160, 28, [128, 16, 8, 255]); + drawButton(_vg, 0, "Cancel", x + 170, y, 110, 28, [0, 0, 0, 0]); + + // Thumbnails box + drawThumbnails(_vg, 365, popy - 30, 160, 300, _t); + + Nvg.restore(_vg); + + // increase the time + _t += 0.01; + } + + function drawWindow(vg:Pointer, title:String, x:Float, y:Float, w:Float, h:Float):Void + { + var cornerRadius:Float = 3.0; + // drop shadow + var shadowPaint:NvgPaint = Nvg.boxGradient(vg, x, y + 2, w, h, cornerRadius * 2, 10, Nvg.rgba(0, 0, 0, 128), Nvg.rgba(0, 0, 0, 0)); + // header + var headerPaint:NvgPaint = Nvg.linearGradient(vg, x, y, x, y + 15, Nvg.rgba(255, 255, 255, 8), Nvg.rgba(0, 0, 0, 16)); + + Nvg.save(vg); + + // window + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x, y, w, h, cornerRadius); + Nvg.fillColor(vg, Nvg.rgba(28, 30, 34, 192)); + Nvg.fill(vg); + + // drop shadow + Nvg.beginPath(vg); + Nvg.rect(vg, x - 10, y - 10, w + 20, h + 30); + Nvg.roundedRect(vg, x, y, w, h, cornerRadius); + Nvg.pathWinding(vg, NvgSolidity.HOLE); + Nvg.fillPaint(vg, shadowPaint); + Nvg.fill(vg); + + // header + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x + 1, y + 1, w - 2, 30, cornerRadius - 1); + Nvg.fillPaint(vg, headerPaint); + Nvg.fill(vg); + Nvg.beginPath(vg); + Nvg.moveTo(vg, x + 0.5, y + 0.5 + 30); + Nvg.lineTo(vg, x + 0.5 + w - 1, y + 0.5 + 30); + Nvg.strokeColor(vg, Nvg.rgba(0, 0, 0, 32)); + Nvg.stroke(vg); + + Nvg.fontSize(vg, 18.0); + Nvg.fontFaceId(vg, fontSansID); + Nvg.textAlign(vg, NvgAlign.ALIGN_CENTER | NvgAlign.ALIGN_MIDDLE); + + Nvg.fontBlur(vg, 2); + Nvg.fillColor(vg, Nvg.rgba(0, 0, 0, 128)); + Nvg.text(vg, x + w / 2, y + 16 + 1, title.c_str(), untyped __cpp__("NULL")); + + Nvg.fontBlur(vg, 0); + Nvg.fillColor(vg, Nvg.rgba(220, 220, 220, 160)); + Nvg.text(vg, x + w / 2, y + 16, title.c_str(), untyped __cpp__("NULL")); + + Nvg.restore(vg); + } + + function drawSearchBox(vg:Pointer, text:String, x:Float, y:Float, w:Float, h:Float):Void + { + var bg:NvgPaint = Nvg.boxGradient(vg, x, y + 1.5, w, h, h / 2, 5, Nvg.rgba(0, 0, 0, 16), Nvg.rgba(0, 0, 0, 92)); + //var icon:String = ""; + var cornerRadius:Float = h / 2.0 - 1; + + // Edit + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x, y, w, h, cornerRadius); + Nvg.fillPaint(vg, bg); + Nvg.fill(vg); + + Nvg.fontSize(vg, h * 1.3); + Nvg.fontFaceId(vg, fontIconsID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 64)); + Nvg.textAlign(vg, NvgAlign.ALIGN_CENTER | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x + h * 0.55, y + h * 0.55, cpToUTF8(ICON_SEARCH).c_str(), untyped __cpp__("NULL")); + + Nvg.fontSize(vg, 20.0); + Nvg.fontFaceId(vg, fontSansID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 32)); + + Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x + h * 1.05, y + h * 0.5, text.c_str(), untyped __cpp__("NULL")); + + Nvg.fontSize(vg, h * 1.3); + Nvg.fontFaceId(vg, fontIconsID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 32)); + Nvg.textAlign(vg, NvgAlign.ALIGN_CENTER | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x + w - h * 0.55, y + h * 0.55, cpToUTF8(ICON_CIRCLED_CROSS).c_str(), untyped __cpp__("NULL")); + } + + function drawDropDown(vg:Pointer, text:String, x:Float, y:Float, w:Float, h:Float):Void + { + var bg:NvgPaint = Nvg.linearGradient(vg, x, y, x, y + h, Nvg.rgba(255, 255, 255, 16), Nvg.rgba(0, 0, 0, 16)); + //var icon:String = ""; + var cornerRadius:Float = 4.0; + + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x + 1, y + 1, w - 2, h - 2, cornerRadius - 1); + Nvg.fillPaint(vg, bg); + Nvg.fill(vg); + + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x + 0.5, y + 0.5, w - 1, h - 1, cornerRadius - 0.5); + Nvg.strokeColor(vg, Nvg.rgba(0, 0, 0, 48)); + Nvg.stroke(vg); + + Nvg.fontSize(vg, 20.0); + Nvg.fontFaceId(vg, fontSansID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 160)); + Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x + h * 0.3, y + h * 0.5, text.c_str(), untyped __cpp__("NULL")); + + Nvg.fontSize(vg, h * 1.3); + Nvg.fontFaceId(vg, fontIconsID); + Nvg.fillColor(vg, Nvg.rgba(255,255,255,64)); + Nvg.textAlign(vg, NvgAlign.ALIGN_CENTER | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x + w - h * 0.5, y + h * 0.5, cpToUTF8(ICON_CHEVRON_RIGHT).c_str(), untyped __cpp__("NULL")); + } + + function drawLabel(vg:Pointer, text:String, x:Float, y:Float, w:Float, h:Float):Void + { + Nvg.fontSize(vg, 18.0); + Nvg.fontFaceId(vg, fontSansID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 128)); + + Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x, y + h * 0.5, text.c_str(), untyped __cpp__("NULL")); + } + + function drawEditBoxBase(vg:Pointer, x:Float, y:Float, w:Float, h:Float):Void + { + var bg:NvgPaint = Nvg.boxGradient(vg, x + 1, y + 1 + 1.5, w - 2, h - 2, 3, 4, Nvg.rgba(255, 255, 255, 32), Nvg.rgba(32, 32, 32, 32)); + // Edit + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x + 1, y + 1, w - 2, h - 2, 4 - 1); + Nvg.fillPaint(vg, bg); + Nvg.fill(vg); + + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x + 0.5, y + 0.5, w - 1, h - 1, 4 - 0.5); + Nvg.strokeColor(vg, Nvg.rgba(0,0,0,48)); + Nvg.stroke(vg); + } + + function drawEditBox(vg:Pointer, text:String, x:Float, y:Float, w:Float, h:Float):Void + { + drawEditBoxBase(vg, x, y, w, h); + + Nvg.fontSize(vg, 20.0); + Nvg.fontFaceId(vg, fontSansID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 64)); + Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x + h * 0.3, y + h * 0.5, text.c_str(), untyped __cpp__("NULL")); + } + + function drawEditBoxNum(vg:Pointer, text:String, units:String, x:Float, y:Float, w:Float, h:Float):Void + { + drawEditBoxBase(vg, x, y, w, h); + + var uw:Float = Nvg.textBounds(vg, 0, 0, units.c_str(), untyped __cpp__("NULL"), untyped __cpp__("NULL")); + + Nvg.fontSize(vg, 18.0); + Nvg.fontFaceId(vg, fontSansID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 64)); + Nvg.textAlign(vg, NvgAlign.ALIGN_RIGHT | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x + w - h * 0.3, y + h * 0.5, units.c_str(), untyped __cpp__("NULL")); + + Nvg.fontSize(vg, 20.0); + Nvg.fontFaceId(vg, fontSansID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 128)); + Nvg.textAlign(vg, NvgAlign.ALIGN_RIGHT | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x + w - uw - h * 0.5, y + h * 0.5, text.c_str(), untyped __cpp__("NULL")); + } + + function drawCheckBox(vg:Pointer, text:String, x:Float, y:Float, w:Float, h:Float):Void + { + var bg:NvgPaint = Nvg.boxGradient(vg, x + 1, y + Std.int(h * 0.5) - 9 + 1, 18, 18, 3, 3, Nvg.rgba(0, 0, 0, 32), Nvg.rgba(0, 0, 0, 92)); + + Nvg.fontSize(vg, 18.0); + Nvg.fontFaceId(vg, fontSansID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 160)); + + Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x + 28, y + h * 0.5, text.c_str(), untyped __cpp__("NULL")); + + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x + 1, y + Std.int(h * 0.5) - 9, 18, 18, 3); + Nvg.fillPaint(vg, bg); + Nvg.fill(vg); + + Nvg.fontSize(vg, 40); + Nvg.fontFaceId(vg, fontIconsID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 128)); + Nvg.textAlign(vg, NvgAlign.ALIGN_CENTER | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x + 9 + 2, y + h * 0.5, cpToUTF8(ICON_CHECK).c_str(), untyped __cpp__("NULL")); + } + + function drawButton(vg:Pointer, preicon:Int, text:String, x:Float, y:Float, w:Float, h:Float, rgba:Array):Void + { + var col:NvgColor = Nvg.rgba(rgba[0], rgba[1], rgba[2], rgba[3]); + + var black:Bool = col.r == 0 && col.g == 0 && col.b == 0; + + var bg:NvgPaint = Nvg.linearGradient(vg, x, y, x, y + h, Nvg.rgba(255, 255, 255, black ? 16 : 32), Nvg.rgba(0, 0, 0, black ? 16 : 32)); + var cornerRadius:Float = 4.0; + var tw:Float = 0, iw:Float = 0; + + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x + 1, y + 1, w - 2, h - 2, cornerRadius - 1); + if (!black) + { + Nvg.fillColor(vg, col); + Nvg.fill(vg); + } + Nvg.fillPaint(vg, bg); + Nvg.fill(vg); + + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x + 0.5, y + 0.5, w - 1, h - 1, cornerRadius - 0.5); + Nvg.strokeColor(vg, Nvg.rgba(0, 0, 0, 48)); + Nvg.stroke(vg); + + Nvg.fontSize(vg, 20.0); + Nvg.fontFaceId(vg, fontSansBoldID); + tw = Nvg.textBounds(vg, 0, 0, text.c_str(), untyped __cpp__("NULL"), untyped __cpp__("NULL")); + + if (preicon != 0) + { + Nvg.fontSize(vg, h * 1.3); + Nvg.fontFaceId(vg, fontIconsID); + iw = Nvg.textBounds(vg, 0,0, cpToUTF8(preicon).c_str(), untyped __cpp__("NULL"), untyped __cpp__("NULL")); + iw += h * 0.15; + } + + if (preicon != 0) + { + Nvg.fontSize(vg, h * 1.3); + Nvg.fontFaceId(vg, fontIconsID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 96)); + Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT | NvgAlign.ALIGN_MIDDLE); + Nvg.text(vg, x + w * 0.5 - tw * 0.5 - iw * 0.75, y + h * 0.5, cpToUTF8(preicon).c_str(), untyped __cpp__("NULL")); + } + + Nvg.fontSize(vg, 20.0); + Nvg.fontFaceId(vg, fontSansBoldID); + Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT | NvgAlign.ALIGN_MIDDLE); + Nvg.fillColor(vg, Nvg.rgba(0, 0, 0, 160)); + Nvg.text(vg, x + w * 0.5 - tw * 0.5 + iw * 0.25, y + h * 0.5 - 1, text.c_str(), untyped __cpp__("NULL")); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 160)); + Nvg.text(vg, x + w * 0.5 - tw * 0.5 + iw * 0.25, y + h * 0.5, text.c_str(), untyped __cpp__("NULL")); + } + + function drawSlider(vg:Pointer, pos:Float, x:Float, y:Float, w:Float, h:Float):Void + { + var cy:Float = y + Std.int(h * 0.5); + var kr:Float = Std.int(h * 0.25); + + Nvg.save(vg); + + // Slot + var bg:NvgPaint = Nvg.boxGradient(vg, x, cy - 2 + 1, w, 4, 2, 2, Nvg.rgba(0, 0, 0, 32), Nvg.rgba(0, 0, 0, 128)); + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x, cy - 2, w, 4, 2); + Nvg.fillPaint(vg, bg); + Nvg.fill(vg); + + // Knob Shadow + bg = Nvg.radialGradient(vg, x + Std.int(pos * w), cy + 1, kr - 3, kr + 3, Nvg.rgba(0, 0, 0, 64), Nvg.rgba(0, 0, 0, 0)); + Nvg.beginPath(vg); + Nvg.rect(vg, x + Std.int(pos * w) - kr - 5, cy - kr - 5, kr * 2 + 5 + 5, kr * 2 + 5 + 5 + 3); + Nvg.circle(vg, x + Std.int(pos * w), cy, kr); + Nvg.pathWinding(vg, NvgSolidity.HOLE); + Nvg.fillPaint(vg, bg); + Nvg.fill(vg); + + // Knob + var knob:NvgPaint = Nvg.linearGradient(vg, x, cy - kr, x, cy + kr, Nvg.rgba(255, 255, 255, 16), Nvg.rgba(0, 0, 0, 16)); + Nvg.beginPath(vg); + Nvg.circle(vg, x + Std.int(pos * w), cy, kr - 1); + Nvg.fillColor(vg, Nvg.rgba(40, 43, 48, 255)); + Nvg.fill(vg); + Nvg.fillPaint(vg, knob); + Nvg.fill(vg); + + Nvg.beginPath(vg); + Nvg.circle(vg, x + Std.int(pos * w), cy, kr - 0.5); + Nvg.strokeColor(vg, Nvg.rgba(0, 0, 0, 92)); + Nvg.stroke(vg); + + Nvg.restore(vg); + } + + function drawEyes(vg:Pointer, x:Float, y:Float, w:Float, h:Float, mx:Float, my:Float, t:Float):Void + { + var gloss:NvgPaint, bg:NvgPaint; + + var ex:Float = w * 0.23; + var ey:Float = h * 0.5; + var lx:Float = x + ex; + var ly:Float = y + ey; + var rx:Float = x + w - ex; + var ry:Float = y + ey; + var dx:Float,dy:Float,d:Float; + var br:Float = (ex < ey ? ex : ey) * 0.5; + var blink:Float = 1 - Math.pow(Math.sin(t * 0.5), 200) * 0.8; + + bg = Nvg.linearGradient(vg, x, y + h * 0.5, x + w * 0.1, y + h, Nvg.rgba(0, 0, 0, 32), Nvg.rgba(0, 0, 0, 16)); + Nvg.beginPath(vg); + Nvg.ellipse(vg, lx + 3.0, ly + 16.0, ex, ey); + Nvg.ellipse(vg, rx + 3.0, ry + 16.0, ex, ey); + Nvg.fillPaint(vg, bg); + Nvg.fill(vg); + + bg = Nvg.linearGradient(vg, x, y + h * 0.25, x + w * 0.1, y + h, Nvg.rgba(220, 220, 220, 255), Nvg.rgba(128, 128, 128, 255)); + Nvg.beginPath(vg); + Nvg.ellipse(vg, lx, ly, ex, ey); + Nvg.ellipse(vg, rx, ry, ex, ey); + Nvg.fillPaint(vg, bg); + Nvg.fill(vg); + + dx = (mx - rx) / (ex * 10); + dy = (my - ry) / (ey * 10); + d = Math.sqrt(dx * dx + dy * dy); + if (d > 1.0) + { + dx /= d; + dy /= d; + } + + dx *= ex * 0.4; + dy *= ey * 0.5; + Nvg.beginPath(vg); + Nvg.ellipse(vg, lx + dx, ly + dy + ey * 0.25 * (1 - blink), br, br * blink); + Nvg.fillColor(vg, Nvg.rgba(32,32,32,255)); + Nvg.fill(vg); + + dx = (mx - rx) / (ex * 10); + dy = (my - ry) / (ey * 10); + d = Math.sqrt(dx * dx + dy * dy); + if (d > 1.0) + { + dx /= d; + dy /= d; + } + dx *= ex * 0.4; + dy *= ey * 0.5; + Nvg.beginPath(vg); + Nvg.ellipse(vg, rx + dx, ry + dy + ey * 0.25 * (1 - blink), br, br * blink); + Nvg.fillColor(vg, Nvg.rgba(32, 32, 32, 255)); + Nvg.fill(vg); + + gloss = Nvg.radialGradient(vg, lx - ex * 0.25, ly - ey * 0.5, ex * 0.1, ex * 0.75, Nvg.rgba(255, 255, 255, 128), Nvg.rgba(255, 255, 255, 0)); + Nvg.beginPath(vg); + Nvg.ellipse(vg, lx, ly, ex, ey); + Nvg.fillPaint(vg, gloss); + Nvg.fill(vg); + + gloss = Nvg.radialGradient(vg, rx - ex * 0.25, ry - ey * 0.5, ex * 0.1, ex * 0.75, Nvg.rgba(255, 255, 255, 128), Nvg.rgba(255, 255, 255, 0)); + Nvg.beginPath(vg); + Nvg.ellipse(vg, rx, ry, ex, ey); + Nvg.fillPaint(vg, gloss); + Nvg.fill(vg); + } + + function drawGraph(vg:Pointer, x:Float, y:Float, w:Float, h:Float, t:Float):Void + { + var bg:NvgPaint; + var samples:Array = []; + var sx:Array = [], sy:Array = []; + var dx:Float = w / 5.0; + + samples[0] = (1 + Math.sin(t * 1.2345 + Math.cos(t * 0.33457) * 0.44)) * 0.5; + samples[1] = (1 + Math.sin(t * 0.68363 + Math.cos(t * 1.3) * 1.55)) * 0.5; + samples[2] = (1 + Math.sin(t * 1.1642 + Math.cos(t * 0.33457) * 1.24)) * 0.5; + samples[3] = (1 + Math.sin(t * 0.56345 + Math.cos(t * 1.63) * 0.14)) * 0.5; + samples[4] = (1 + Math.sin(t * 1.6245 + Math.cos(t * 0.254) * 0.3)) * 0.5; + samples[5] = (1 + Math.sin(t * 0.345 + Math.cos(t * 0.03) * 0.6)) * 0.5; + + for (i in 0 ... 6) + { + sx[i] = x + i * dx; + sy[i] = y + h * samples[i] * 0.8; + } + + // Graph background + bg = Nvg.linearGradient(vg, x, y, x, y + h, Nvg.rgba(0, 160, 192, 0), Nvg.rgba(0, 160, 192, 64)); + Nvg.beginPath(vg); + Nvg.moveTo(vg, sx[0], sy[0]); + for (i in 1 ... 6) Nvg.bezierTo(vg, sx[i - 1] + dx * 0.5, sy[i - 1], sx[i] - dx * 0.5, sy[i], sx[i], sy[i]); + Nvg.lineTo(vg, x + w, y + h); + Nvg.lineTo(vg, x, y + h); + Nvg.fillPaint(vg, bg); + Nvg.fill(vg); + + // Graph line + Nvg.beginPath(vg); + Nvg.moveTo(vg, sx[0], sy[0] + 2); + for (i in 1 ... 6) Nvg.bezierTo(vg, sx[i - 1] + dx * 0.5, sy[i - 1] + 2, sx[i] - dx * 0.5, sy[i] + 2, sx[i], sy[i] + 2); + Nvg.strokeColor(vg, Nvg.rgba(0, 0, 0, 32)); + Nvg.strokeWidth(vg, 3.0); + Nvg.stroke(vg); + + Nvg.beginPath(vg); + Nvg.moveTo(vg, sx[0], sy[0]); + for (i in 1 ... 6) Nvg.bezierTo(vg, sx[i - 1] + dx * 0.5, sy[i - 1], sx[i] - dx * 0.5, sy[i], sx[i], sy[i]); + Nvg.strokeColor(vg, Nvg.rgba(0, 160, 192, 255)); + Nvg.strokeWidth(vg, 3.0); + Nvg.stroke(vg); + + // Graph sample pos + for (i in 0 ... 6) + { + bg = Nvg.radialGradient(vg, sx[i], sy[i] + 2, 3.0, 8.0, Nvg.rgba(0, 0, 0, 32), Nvg.rgba(0, 0, 0, 0)); + Nvg.beginPath(vg); + Nvg.rect(vg, sx[i] - 10, sy[i] - 10 + 2, 20, 20); + Nvg.fillPaint(vg, bg); + Nvg.fill(vg); + } + + Nvg.beginPath(vg); + for (i in 0 ... 6) Nvg.circle(vg, sx[i], sy[i], 4.0); + Nvg.fillColor(vg, Nvg.rgba(0,160,192,255)); + Nvg.fill(vg); + Nvg.beginPath(vg); + for (i in 0 ... 6) Nvg.circle(vg, sx[i], sy[i], 2.0); + Nvg.fillColor(vg, Nvg.rgba(220,220,220,255)); + Nvg.fill(vg); + + Nvg.strokeWidth(vg, 1.0); + } + + function drawSpinner(vg:Pointer, cx:Float, cy:Float, r:Float, t:Float):Void + { + var a0:Float = 0.0 + t * 6; + var a1:Float = Math.PI + t * 6; + var r0:Float = r; + var r1:Float = r * 0.75; + var ax:Float, ay:Float, bx:Float, by:Float; + var paint:NvgPaint; + + Nvg.save(vg); + + Nvg.beginPath(vg); + Nvg.arc(vg, cx, cy, r0, a0, a1, NvgWinding.CW); + Nvg.arc(vg, cx, cy, r1, a1, a0, NvgWinding.CCW); + Nvg.closePath(vg); + ax = cx + Math.cos(a0) * (r0 + r1) * 0.5; + ay = cy + Math.sin(a0) * (r0 + r1) * 0.5; + bx = cx + Math.cos(a1) * (r0 + r1) * 0.5; + by = cy + Math.sin(a1) * (r0 + r1) * 0.5; + paint = Nvg.linearGradient(vg, ax, ay, bx, by, Nvg.rgba(0, 0, 0, 0), Nvg.rgba(0, 0, 0, 128)); + Nvg.fillPaint(vg, paint); + Nvg.fill(vg); + + Nvg.restore(vg); + } + + function drawThumbnails(vg:Pointer, x:Float, y:Float, w:Float, h:Float, /*images:ConstPointer, nimages:Int,*/ t:Float):Void + { + var cornerRadius:Float = 3.0; + var shadowPaint:NvgPaint, imgPaint:NvgPaint, fadePaint:NvgPaint; + var ix:Float, iy:Float, iw:Float, ih:Float; + var thumb:Float = 60.0; + var arry:Float = 30.5; + var imgw:Int = 10, imgh:Int = 5; + var stackh:Float = (images.length / 2) * (thumb + 10) + 10; + + var u:Float = (1 + Math.cos(t * 0.5)) * 0.5; + var u2:Float = (1 - Math.cos(t * 0.2)) * 0.5; + var scrollh:Float, dv:Float; + + Nvg.save(vg); + + // Drop shadow + shadowPaint = Nvg.boxGradient(vg, x, y + 4, w, h, cornerRadius * 2, 20, Nvg.rgba(0, 0, 0, 128), Nvg.rgba(0, 0, 0, 0)); + Nvg.beginPath(vg); + Nvg.rect(vg, x - 10, y - 10, w + 20, h + 30); + Nvg.roundedRect(vg, x, y, w, h, cornerRadius); + Nvg.pathWinding(vg, NvgSolidity.HOLE); + Nvg.fillPaint(vg, shadowPaint); + Nvg.fill(vg); + + // Window + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x, y, w, h, cornerRadius); + Nvg.moveTo(vg, x - 10, y + arry); + Nvg.lineTo(vg, x + 1, y + arry - 11); + Nvg.lineTo(vg, x + 1, y + arry + 11); + Nvg.fillColor(vg, Nvg.rgba(200, 200, 200, 255)); + Nvg.fill(vg); + + Nvg.save(vg); + Nvg.scissor(vg, x, y, w, h); + Nvg.translate(vg, 0, -(stackh - h) * u); + + dv = 1.0 / cast(images.length - 1.0, Float); + + var tx:Float, ty:Float, v:Float, a:Float; + for (i in 0 ... images.length) + { + tx = x + 10; + ty = y + 10; + tx += (i % 2) * (thumb + 10); + ty += (i / 2) * (thumb + 10); + Nvg.imageSize(vg, images[i], Pointer.addressOf(imgw), Pointer.addressOf(imgh)); + if (imgw < imgh) + { + iw = thumb; + ih = iw * cast(imgh, Float) / cast(imgw, Float); + ix = 0; + iy = -(ih - thumb) * 0.5; + } + else + { + ih = thumb; + iw = ih * cast(imgw, Float) / cast(imgh, Float); + ix = -(iw - thumb) * 0.5; + iy = 0; + } + + v = i * dv; + a = clampf((u2 - v) / dv, 0, 1); + + if (a < 1.0) drawSpinner(vg, tx + thumb / 2, ty + thumb / 2, thumb * 0.25, t); + + imgPaint = Nvg.imagePattern(vg, tx + ix, ty + iy, iw, ih, 0.0 / 180.0 * Math.PI, images[i], a); + Nvg.beginPath(vg); + Nvg.roundedRect(vg, tx,ty, thumb,thumb, 5); + Nvg.fillPaint(vg, imgPaint); + Nvg.fill(vg); + + shadowPaint = Nvg.boxGradient(vg, tx - 1, ty, thumb + 2, thumb + 2, 5, 3, Nvg.rgba(0, 0, 0, 128), Nvg.rgba(0, 0, 0, 0)); + Nvg.beginPath(vg); + Nvg.rect(vg, tx - 5, ty - 5, thumb + 10, thumb + 10); + Nvg.roundedRect(vg, tx, ty, thumb, thumb, 6); + Nvg.pathWinding(vg, NvgSolidity.HOLE); + Nvg.fillPaint(vg, shadowPaint); + Nvg.fill(vg); + + Nvg.beginPath(vg); + Nvg.roundedRect(vg, tx + 0.5, ty + 0.5, thumb - 1, thumb - 1, 4 - 0.5); + Nvg.strokeWidth(vg, 1.0); + Nvg.strokeColor(vg, Nvg.rgba(255,255,255,192)); + Nvg.stroke(vg); + } + Nvg.restore(vg); + + // Hide fades + fadePaint = Nvg.linearGradient(vg, x, y, x, y + 6, Nvg.rgba(200, 200, 200, 255), Nvg.rgba(200, 200, 200, 0)); + Nvg.beginPath(vg); + Nvg.rect(vg, x + 4, y, w - 8, 6); + Nvg.fillPaint(vg, fadePaint); + Nvg.fill(vg); + + fadePaint = Nvg.linearGradient(vg, x, y + h, x, y + h - 6, Nvg.rgba(200, 200, 200, 255), Nvg.rgba(200, 200, 200, 0)); + Nvg.beginPath(vg); + Nvg.rect(vg, x + 4, y + h - 6, w - 8, 6); + Nvg.fillPaint(vg, fadePaint); + Nvg.fill(vg); + + // Scroll bar + shadowPaint = Nvg.boxGradient(vg, x + w - 12 + 1, y + 4 + 1, 8, h - 8, 3, 4, Nvg.rgba(0, 0, 0, 32), Nvg.rgba(0, 0, 0, 92)); + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x + w - 12, y + 4, 8, h - 8, 3); + Nvg.fillPaint(vg, shadowPaint); + Nvg.fill(vg); + + scrollh = (h / stackh) * (h - 8); + shadowPaint = Nvg.boxGradient(vg, x + w - 12 - 1, y + 4 + (h - 8 - scrollh) * u - 1, 8, scrollh, 3, 4, Nvg.rgba(220, 220, 220, 255), Nvg.rgba(128, 128, 128, 255)); + Nvg.beginPath(vg); + Nvg.roundedRect(vg, x + w - 12 + 1, y + 4 + 1 + (h - 8 - scrollh) * u, 8 - 2, scrollh - 2, 2); + Nvg.fillPaint(vg, shadowPaint); + Nvg.fill(vg); + + Nvg.restore(vg); + } + + function drawColorwheel(vg:Pointer, x:Float, y:Float, w:Float, h:Float, t:Float):Void + { + var r0:Float, r1:Float, ax:Float, ay:Float, bx:Float, by:Float, cx:Float, cy:Float, aeps:Float, r:Float; + var hue:Float = Math.sin(t * 0.12); + var paint:NvgPaint; + + Nvg.save(vg); + + /* + Nvg.beginPath(vg); + Nvg.rect(vg, x,y,w,h); + Nvg.fillColor(vg, Nvg.rgba(255,0,0,128)); + Nvg.fill(vg); + //*/ + + cx = x + w * 0.5; + cy = y + h * 0.5; + r1 = (w < h ? w : h) * 0.5 - 5.0; + r0 = r1 - 20.0; + aeps = 0.5 / r1; // half a pixel arc length in radians (2pi cancels out). + + for (i in 0 ... 6) + { + var a0:Float = i * Math.PI * 2.0 / 6.0 - aeps; + var a1:Float = (i + 1.0) * Math.PI * 2.0 / 6.0 + aeps; + + Nvg.beginPath(vg); + Nvg.arc(vg, cx,cy, r0, a0, a1, NvgWinding.CW); + Nvg.arc(vg, cx,cy, r1, a1, a0, NvgWinding.CCW); + Nvg.closePath(vg); + + ax = cx + Math.cos(a0) * (r0 + r1) * 0.5; + ay = cy + Math.sin(a0) * (r0 + r1) * 0.5; + bx = cx + Math.cos(a1) * (r0 + r1) * 0.5; + by = cy + Math.sin(a1) * (r0 + r1) * 0.5; + paint = Nvg.linearGradient(vg, ax, ay, bx, by, Nvg.hsla(a0 / (Math.PI * 2), 1.0, 0.55, 255), Nvg.hsla(a1 / (Math.PI * 2), 1.0, 0.55, 255)); + Nvg.fillPaint(vg, paint); + Nvg.fill(vg); + } + + Nvg.beginPath(vg); + Nvg.circle(vg, cx, cy, r0 - 0.5); + Nvg.circle(vg, cx, cy, r1 + 0.5); + Nvg.strokeColor(vg, Nvg.rgba(0, 0, 0, 64)); + Nvg.strokeWidth(vg, 1.0); + Nvg.stroke(vg); + + // Selector + Nvg.save(vg); + Nvg.translate(vg, cx, cy); + Nvg.rotate(vg, hue * Math.PI * 2); + + // Marker on + Nvg.strokeWidth(vg, 2.0); + Nvg.beginPath(vg); + Nvg.rect(vg, r0 - 1, -3, r1 - r0 + 2, 6); + Nvg.strokeColor(vg, Nvg.rgba(255, 255, 255, 192)); + Nvg.stroke(vg); + + paint = Nvg.boxGradient(vg, r0 - 3, -5, r1 - r0 + 6, 10, 2, 4, Nvg.rgba(0, 0, 0, 128), Nvg.rgba(0, 0, 0, 0)); + Nvg.beginPath(vg); + Nvg.rect(vg, r0 - 2 - 10, -4 - 10, r1 - r0 + 4 + 20, 8 + 20); + Nvg.rect(vg, r0 - 2, -4, r1 - r0 + 4, 8); + Nvg.pathWinding(vg, NvgSolidity.HOLE); + Nvg.fillPaint(vg, paint); + Nvg.fill(vg); + + // Center triangle + r = r0 - 6; + ax = Math.cos(120.0 / 180.0 * Math.PI) * r; + ay = Math.sin(120.0 / 180.0 * Math.PI) * r; + bx = Math.cos( -120.0 / 180.0 * Math.PI) * r; + by = Math.sin( -120.0 / 180.0 * Math.PI) * r; + Nvg.beginPath(vg); + Nvg.moveTo(vg, r, 0); + Nvg.lineTo(vg, ax, ay); + Nvg.lineTo(vg, bx, by); + Nvg.closePath(vg); + paint = Nvg.linearGradient(vg, r, 0, ax, ay, Nvg.hsla(hue, 1.0, 0.5, 255), Nvg.rgba(255, 255, 255, 255)); + Nvg.fillPaint(vg, paint); + Nvg.fill(vg); + paint = Nvg.linearGradient(vg, (r + ax) * 0.5, (0 + ay) * 0.5, bx, by, Nvg.rgba(0, 0, 0, 0), Nvg.rgba(0, 0, 0, 255)); + Nvg.fillPaint(vg, paint); + Nvg.fill(vg); + Nvg.strokeColor(vg, Nvg.rgba(0, 0, 0, 64)); + Nvg.stroke(vg); + + // Select circle on triangle + ax = Math.cos(120.0 / 180.0 * Math.PI) * r * 0.3; + ay = Math.sin(120.0 / 180.0 * Math.PI) * r * 0.4; + Nvg.strokeWidth(vg, 2.0); + Nvg.beginPath(vg); + Nvg.circle(vg, ax, ay, 5); + Nvg.strokeColor(vg, Nvg.rgba(255, 255, 255, 192)); + Nvg.stroke(vg); + + paint = Nvg.radialGradient(vg, ax, ay, 7, 9, Nvg.rgba(0, 0, 0, 64), Nvg.rgba(0, 0, 0, 0)); + Nvg.beginPath(vg); + Nvg.rect(vg, ax - 20, ay - 20, 40, 40); + Nvg.circle(vg, ax, ay, 7); + Nvg.pathWinding(vg, NvgSolidity.HOLE); + Nvg.fillPaint(vg, paint); + Nvg.fill(vg); + + Nvg.restore(vg); + + Nvg.restore(vg); + } + + function drawLines(vg:Pointer, x:Float, y:Float, w:Float, h:Float, t:Float):Void + { + var pad:Float = 5.0, s:Float = w / 9.0 - pad * 2; + var pts:Array = [], fx:Float, fy:Float; + var joins:Array = [NvgLineCap.MITER, NvgLineCap.ROUND, NvgLineCap.BEVEL]; + var caps:Array = [NvgLineCap.BUTT, NvgLineCap.ROUND, NvgLineCap.SQUARE]; + + Nvg.save(vg); + pts[0] = -s * 0.25 + Math.cos(t * 0.3) * s * 0.5; + pts[1] = Math.sin(t * 0.3) * s * 0.5; + pts[2] = -s * 0.25; + pts[3] = 0; + pts[4] = s * 0.25; + pts[5] = 0; + pts[6] = s * 0.25 + Math.cos( -t * 0.3) * s * 0.5; + pts[7] = Math.sin( -t * 0.3) * s * 0.5; + + for (i in 0 ... 3) + { + for (j in 0 ... 3) + { + fx = x + s * 0.5 + (i * 3 + j) / 9.0 * w + pad; + fy = y - s * 0.5 + pad; + + Nvg.lineCap(vg, caps[i]); + Nvg.lineJoin(vg, joins[j]); + + Nvg.strokeWidth(vg, s * 0.3); + Nvg.strokeColor(vg, Nvg.rgba(0, 0, 0, 160)); + Nvg.beginPath(vg); + Nvg.moveTo(vg, fx + pts[0], fy + pts[1]); + Nvg.lineTo(vg, fx + pts[2], fy + pts[3]); + Nvg.lineTo(vg, fx + pts[4], fy + pts[5]); + Nvg.lineTo(vg, fx + pts[6], fy + pts[7]); + Nvg.stroke(vg); + + Nvg.lineCap(vg, NvgLineCap.BUTT); + Nvg.lineJoin(vg, NvgLineCap.BEVEL); + + Nvg.strokeWidth(vg, 1.0); + Nvg.strokeColor(vg, Nvg.rgba(0, 192, 255, 255)); + Nvg.beginPath(vg); + Nvg.moveTo(vg, fx + pts[0], fy + pts[1]); + Nvg.lineTo(vg, fx + pts[2], fy + pts[3]); + Nvg.lineTo(vg, fx + pts[4], fy + pts[5]); + Nvg.lineTo(vg, fx + pts[6], fy + pts[7]); + Nvg.stroke(vg); + } + } + + Nvg.restore(vg); + } + + function loadDemoData(vg:Pointer):Int + { + if (vg == untyped __cpp__("NULL")) return -1; + // fonts - if any fontID == -1, then error occured + fontIconsID = Nvg.createFont(vg, "icon".c_str(), "assets/entypo.ttf".c_str()); + fontSansID = Nvg.createFont(vg, "sans".c_str(), "assets/Roboto-Regular.ttf".c_str()); + fontSansBoldID = Nvg.createFont(vg, "sans-bold".c_str(), "assets/Roboto-Bold.ttf".c_str()); + + for (i in 0 ... 12) + { + images[i] = Nvg.createImage(vg, ("assets/images/image" + (i + 1) + ".jpg").c_str(), 0); + if (images[i] == 0) + { + Lib.print("Could not load: image" + (i + 1)); + return -1; + } + } + + return 0; + } + + public function freeDemoData(vg:Pointer):Void + { + if (vg == untyped __cpp__("NULL")) return; + + for (i in 0 ... images.length) Nvg.deleteImage(vg, images[i]); + } + + function drawParagraph(vg:Pointer, x:Float, y:Float, width:Float, height:Float, mx:Float, my:Float):Void + { + // need to use the cpp syntax + untyped __cpp__("NVGtextRow rows[3];"); + untyped __cpp__("NVGglyphPosition glyphs[100];"); + + untyped __cpp__('const char* text = "This is longer chunk of text.\\n \\n Would have used lorem ipsum but she was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party.";'); + + untyped __cpp__("const char* start;"); + untyped __cpp__("const char* end;"); + + var nrows:Int, nglyphs:Int, lnum:Int = 0; + var lineh:Float = 1.0; + untyped __cpp__("float lineheight;"); + var caretx:Float, px:Float; + untyped __cpp__ ("float bounds[4];"); + + var a:Float; + var gx:Float = 0, gy:Float = 0; + var gutter:Int = 0; + + var index:Int = 0; + + Nvg.save(vg); + + Nvg.fontSize(vg, 18.0); + Nvg.fontFaceId(vg, fontSansID); + Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT | NvgAlign.ALIGN_TOP); + Nvg.textMetrics(vg, untyped __cpp__("NULL"), untyped __cpp__("NULL"), untyped __cpp__("&lineheight")); + + // The text break API can be used to fill a large buffer of rows, + // or to iterate over the text just few lines (or just one) at a time. + // The "next" variable of the last returned item tells where to continue. + untyped __cpp__("start = text; end = text + strlen(text);"); + + lineh = untyped __cpp__("lineheight"); + + while ((nrows = Nvg.textBreakLines(vg, untyped __cpp__("start"), untyped __cpp__("end"), width, untyped __cpp__("rows"), 3)) > 0) + { + for (i in 0 ... nrows) + { + var row:NvgTextRow = untyped __cpp__("rows[i]");//rows[i]; + + var hit:Bool = mx > x && mx < (x + width) && my >= y && my < (y + lineh); + + Nvg.beginPath(vg); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, hit ? 64 : 16)); + Nvg.rect(vg, x, y, row.width, lineh); + Nvg.fill(vg); + + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 255)); + Nvg.text(vg, x, y, row.start, row.end); + + if (hit) + { + caretx = (mx < x + row.width / 2) ? x : x + row.width; + px = x; + nglyphs = Nvg.textGlyphPositions(vg, x, y, row.start, row.end, untyped __cpp__("glyphs"), 100); + for (j in 0 ... nglyphs) + { + var glp:NvgGlyphPosition = untyped __cpp__("glyphs[j]"); + var x0:Float = glp.x; + + var x1:Float = x + row.width; + if (j + 1 < nglyphs) + { + glp = untyped __cpp__("glyphs[j+1]"); + x1 = glp.x; + } + + var gx:Float = x0 * 0.3 + x1 * 0.7; + if (mx >= px && mx < gx) + { + glp = untyped __cpp__("glyphs[j]"); + caretx = glp.x; + } + px = gx; + } + + Nvg.beginPath(vg); + Nvg.fillColor(vg, Nvg.rgba(255, 192, 0, 255)); + Nvg.rect(vg, caretx, y, 1, lineh); + Nvg.fill(vg); + + gutter = lnum + 1; + gx = x - 10; + gy = y + lineh / 2; + } + + lnum++; + y += lineh; + } + + // Keep going... + untyped __cpp__("start = rows[nrows-1].next"); + } + + if (gutter != 0) + { + var txt:String = Std.string(gutter); + + Nvg.fontSize(vg, 13.0); + Nvg.textAlign(vg, NvgAlign.ALIGN_RIGHT | NvgAlign.ALIGN_MIDDLE); + + Nvg.textBounds(vg, gx, gy, txt.c_str(), untyped __cpp__("NULL"), untyped __cpp__ ("bounds")); + + Nvg.beginPath(vg); + Nvg.fillColor(vg, Nvg.rgba(255, 192, 0, 255)); + Nvg.roundedRect(vg, Std.int(untyped __cpp__ ("bounds[0]") - 4), Std.int(untyped __cpp__ ("bounds[1]") - 2), + Std.int(untyped __cpp__ ("bounds[2]") - untyped __cpp__ ("bounds[0]")) + 8, + Std.int(untyped __cpp__ ("bounds[3]") - untyped __cpp__ ("bounds[1]")) + 4, + (Std.int(untyped __cpp__ ("bounds[3]") - untyped __cpp__ ("bounds[1]")) + 4) / 2 - 1); + Nvg.fill(vg); + + Nvg.fillColor(vg, Nvg.rgba(32, 32, 32, 255)); + Nvg.text(vg, gx, gy, txt.c_str(), untyped __cpp__("NULL")); + } + + y += 20.0; + + Nvg.fontSize(vg, 13.0); + Nvg.textAlign(vg, NvgAlign.ALIGN_LEFT | NvgAlign.ALIGN_TOP); + Nvg.textLineHeight(vg, 1.2); + + Nvg.textBoxBounds(vg, x, y, 150, "Hover your mouse over the text to see calculated caret position.".c_str(), untyped __cpp__("NULL"), untyped __cpp__ ("bounds")); + + // Fade the tooltip out when close to it. + gx = Math.abs((mx - (untyped __cpp__ ("bounds[0]") + untyped __cpp__ ("bounds[2]")) * 0.5) / (untyped __cpp__ ("bounds[0]") - untyped __cpp__ ("bounds[2]"))); + gy = Math.abs((my - (untyped __cpp__ ("bounds[1]") + untyped __cpp__ ("bounds[3]")) * 0.5) / (untyped __cpp__ ("bounds[1]") - untyped __cpp__ ("bounds[3]"))); + a = maxf(gx, gy) - 0.5; + a = clampf(a, 0, 1); + Nvg.globalAlpha(vg, a); + + Nvg.beginPath(vg); + Nvg.fillColor(vg, Nvg.rgba(220, 220, 220, 255)); + Nvg.roundedRect(vg, untyped __cpp__ ("bounds[0]") - 2, untyped __cpp__ ("bounds[1]") - 2, Std.int(untyped __cpp__ ("bounds[2]") - untyped __cpp__ ("bounds[0]")) + 4, Std.int(untyped __cpp__ ("bounds[3]") - untyped __cpp__ ("bounds[1]")) + 4, 3); + px = Std.int((untyped __cpp__ ("bounds[2]") + untyped __cpp__ ("bounds[0]")) / 2); + Nvg.moveTo(vg, px, untyped __cpp__ ("bounds[1]") - 10); + Nvg.lineTo(vg, px + 7, untyped __cpp__ ("bounds[1]") + 1); + Nvg.lineTo(vg, px - 7, untyped __cpp__ ("bounds[1]") + 1); + Nvg.fill(vg); + + Nvg.fillColor(vg, Nvg.rgba(0, 0, 0, 220)); + Nvg.textBox(vg, x,y, 150, "Hover your mouse over the text to see calculated caret position.".c_str(), untyped __cpp__("NULL")); + + Nvg.restore(vg); + } + + function drawWidths(vg:Pointer, x:Float, y:Float, width:Float):Void + { + Nvg.save(vg); + + Nvg.strokeColor(vg, Nvg.rgba(0, 0, 0, 255)); + + var w:Float; + + for (i in 0 ... 20) + { + w = (i + 0.5) * 0.1; + Nvg.strokeWidth(vg, w); + Nvg.beginPath(vg); + Nvg.moveTo(vg, x, y); + Nvg.lineTo(vg, x + width, y + width * 0.3); + Nvg.stroke(vg); + y += 10; + } + + Nvg.restore(vg); + } + + function drawCaps(vg:Pointer, x:Float, y:Float, width:Float):Void + { + var caps:Array = [NvgLineCap.BUTT, NvgLineCap.ROUND, NvgLineCap.SQUARE]; + var lineWidth:Float = 8.0; + + Nvg.save(vg); + + Nvg.beginPath(vg); + Nvg.rect(vg, x - lineWidth / 2, y, width + lineWidth, 40); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 32)); + Nvg.fill(vg); + + Nvg.beginPath(vg); + Nvg.rect(vg, x, y, width, 40); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 32)); + Nvg.fill(vg); + + Nvg.strokeWidth(vg, lineWidth); + + for (i in 0 ... 3) + { + Nvg.lineCap(vg, caps[i]); + Nvg.strokeColor(vg, Nvg.rgba(0, 0, 0, 255)); + Nvg.beginPath(vg); + Nvg.moveTo(vg, x, y + i * 10 + 5); + Nvg.lineTo(vg, x + width, y + i * 10 + 5); + Nvg.stroke(vg); + } + + Nvg.restore(vg); + } + + function drawScissor(vg:Pointer, x:Float, y:Float, t:Float):Void + { + Nvg.save(vg); + + // Draw first rect and set scissor to it's area. + Nvg.translate(vg, x, y); + Nvg.rotate(vg, Nvg.degToRad(5)); + Nvg.beginPath(vg); + Nvg.rect(vg, -20, -20, 60, 40); + Nvg.fillColor(vg, Nvg.rgba(255, 0, 0, 255)); + Nvg.fill(vg); + Nvg.scissor(vg, -20, -20, 60, 40); + + // Draw second rectangle with offset and rotation. + Nvg.translate(vg, 40, 0); + Nvg.rotate(vg, t); + + // Draw the intended second rectangle without any scissoring. + Nvg.save(vg); + Nvg.resetScissor(vg); + Nvg.beginPath(vg); + Nvg.rect(vg, -20, -10, 60, 30); + Nvg.fillColor(vg, Nvg.rgba(255, 128, 0, 64)); + Nvg.fill(vg); + Nvg.restore(vg); + + // Draw second rectangle with combined scissoring. + Nvg.intersectScissor(vg, -20, -10, 60, 30); + Nvg.beginPath(vg); + Nvg.rect(vg, -20, -10, 60, 30); + Nvg.fillColor(vg, Nvg.rgba(255, 128, 0, 255)); + Nvg.fill(vg); + + Nvg.restore(vg); + } + +} \ No newline at end of file diff --git a/example/src/FPSMonitor.hx b/example/src/FPSMonitor.hx new file mode 100644 index 0000000..0744511 --- /dev/null +++ b/example/src/FPSMonitor.hx @@ -0,0 +1,87 @@ +package; + +import cpp.Pointer; +import cpp.Char; +import cpp.ConstPointer; +import cpp.Pointer; +import hxnanovg.Nvg; + +import haxe.Timer; + +using cpp.NativeString; + +/** + * ... + * @author Hortobágyi Tamás + */ +class FPSMonitor +{ + private var vg:Pointer; + + private var fontID:Int = 0; + + private var prevTime:Float; + private var times:Array = []; + /** Calculate the average time **/ + private var maxTimeCount:Int = 100; + + public function new(vg:Pointer, fontID:Int) + { + this.vg = vg; + this.fontID = fontID; + + prevTime = Timer.stamp(); + } + + public function render() + { + times.push(Timer.stamp() - prevTime); + prevTime = Timer.stamp(); + // if we hase enough data, remove the first data + if (times.length > maxTimeCount) times.shift(); + + var time:Float = 0.0; + for (i in 0 ... times.length) time += times[i]; + time /= times.length; + + var fps:Float = Math.fround(100.0 / time) / 100.0; + time = Math.fround(time * 100000) / 100.0; + + var x:Float = 5, y:Float = 5; + var w:Float = 220, h:Float = 35; + + // base + Nvg.beginPath(vg); + Nvg.rect(vg, x, y, w, h); + Nvg.fillColor(vg, Nvg.rgba(0, 0, 0, 128)); + Nvg.fill(vg); + + // graph + Nvg.beginPath(vg); + Nvg.moveTo(vg, x, y + h); + for (i in 0 ... times.length) + { + var v:Float = times[i] * 1000.0; + if (v > 30.0) v = 30.0; + var vx:Float = x + cast(w * i, Float) / cast(maxTimeCount, Float); + var vy:Float = y + h - (v / 30.0) * h; + Nvg.lineTo(vg, vx, vy); + } + Nvg.lineTo(vg, x + w * times.length / maxTimeCount, y + h); + Nvg.fillColor(vg, Nvg.rgba(255, 192, 0, 128)); + Nvg.fill(vg); + + // values + Nvg.fontSize(vg, 18); + Nvg.fontFaceId(vg, fontID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 192)); + Nvg.textAlign(vg, NvgAlign.ALIGN_RIGHT | NvgAlign.ALIGN_TOP); + Nvg.text(vg, x + w - 3, y, (Std.string(fps) + " FPS").c_str(), untyped __cpp__("NULL")); + + Nvg.fontSize(vg, 14); + Nvg.fontFaceId(vg, fontID); + Nvg.fillColor(vg, Nvg.rgba(255, 255, 255, 192)); + Nvg.textAlign(vg, NvgAlign.ALIGN_RIGHT | NvgAlign.ALIGN_BOTTOM); + Nvg.text(vg, x + w - 3, y + h - 3, (Std.string(time) + " ms").c_str(), untyped __cpp__("NULL")); + } +} \ No newline at end of file diff --git a/example/src/Main.hx b/example/src/Main.hx new file mode 100644 index 0000000..0279018 --- /dev/null +++ b/example/src/Main.hx @@ -0,0 +1,119 @@ +package; + +import cpp.Pointer; +import hxnanovg.Nvg; +import lime.app.Application; +import lime.graphics.opengl.GL; +import lime.graphics.RenderContext; +import lime.graphics.GLRenderContext; + +using cpp.NativeString; + + +/** + * ... + * @author Thomas Hortobágyi + */ + +@:buildXml("&") + +class Main extends Application +{ + private var ctx:GLRenderContext; + + private var _vg:Pointer; + /** the original NanoVG example, ported to Haxe **/ + private var demo:Demo; + /** "performance" monitor **/ + private var fpsMonitor:FPSMonitor; + /** trace **/ + private var dbgTrace:DbgTrace; + + public var mouseX:Float = 0; + public var mouseY:Float = 0; + + public var blowup:Int = 0; + + public function new() + { + super(); + } + + public override function init(context:RenderContext):Void + { + updateSavedContext(context); + + _vg = Nvg.createGL(NvgMode.ANTIALIAS); + + demo = new Demo(_vg); + + dbgTrace = new DbgTrace(demo.fontSansID); + fpsMonitor = new FPSMonitor(_vg, demo.fontSansID); + } + + public override function render(context:RenderContext):Void + { + updateSavedContext(context); + + GL.viewport(0, 0, this.window.width, this.window.height); + GL.clearColor(0.3, 0.3, 0.32, 1.0); + GL.clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT | GL.STENCIL_BUFFER_BIT); + + Nvg.beginFrame(_vg, this.window.width, this.window.height, 1.0); + // calculate the minimum scale - with this the "scene" will be in the windows, at maximum size + var globalScale:Float = Math.min(this.window.width / config.width, this.window.height / config.height); + // position to center + var xp:Float = Math.fround((this.window.width - config.width * globalScale) * 0.5); + var yp:Float = Math.fround((this.window.height - config.height * globalScale) * 0.5); + //Nvg.save(_vg); + Nvg.translate(_vg, xp, yp); + Nvg.scale(_vg, globalScale, globalScale); + // transform the mouseX, mouseY coordinates too + demo.render(_vg, (mouseX - xp) / globalScale, (mouseY - yp) / globalScale, config.width, config.height, blowup); + + fpsMonitor.render(); + + dbgTrace.render(_vg); + + //Nvg.restore(_vg); + + Nvg.endFrame(_vg); + } + + override public function onWindowClose():Void + { + super.onWindowClose(); + + demo.freeDemoData(_vg); + } + + override public function onKeyUp(keyCode:Int, modifier:Int):Void + { + super.onKeyUp(keyCode, modifier); + + //dbgTrace.log(Std.string(keyCode)); + + switch (keyCode) + { + // SPACE + case 32: blowup = 1 - blowup; + } + } + + override public function onMouseMove(x:Float, y:Float, button:Int):Void + { + super.onMouseMove(x, y, button); + + mouseX = x; + mouseY = y; + } + + function updateSavedContext(context:RenderContext):Void + { + switch(context) + { + case RenderContext.OPENGL(gl): ctx = gl; + default: null; + } + } +} diff --git a/hxnanovg/Nvg.hx b/hxnanovg/Nvg.hx index 1ea3598..6fc3ebc 100755 --- a/hxnanovg/Nvg.hx +++ b/hxnanovg/Nvg.hx @@ -16,12 +16,16 @@ class NvgMode { } class NvgWinding { + /** Winding for solid shapes **/ inline public static var CCW:Int = 1; + /** Winding for holes **/ inline public static var CW:Int = 2; } class NvgSolidity { + /** CCW **/ inline public static var SOLID:Int = 1; + /** CW **/ inline public static var HOLE:Int = 2; } @@ -40,13 +44,20 @@ class NvgPatternRepeat { } class NvgAlign { - inline public static var ALIGN_LEFT:Int = 1<<0; - inline public static var ALIGN_CENTER:Int = 1<<1; - inline public static var ALIGN_RIGHT:Int = 1<<2; - inline public static var ALIGN_TOP:Int = 1<<3; - inline public static var ALIGN_MIDDLE:Int = 1<<4; - inline public static var ALIGN_BOTTOM:Int = 1<<5; - inline public static var ALIGN_BASELINE:Int = 1<<6; + /** Default, align text horizontally to left. **/ + inline public static var ALIGN_LEFT:Int = 1 << 0; + /** Align text horizontally to center. **/ + inline public static var ALIGN_CENTER:Int = 1 << 1; + /** Align text horizontally to right. **/ + inline public static var ALIGN_RIGHT:Int = 1 << 2; + /** Align text vertically to top. **/ + inline public static var ALIGN_TOP:Int = 1 << 3; + /** Align text vertically to middle. **/ + inline public static var ALIGN_MIDDLE:Int = 1 << 4; + /** Align text vertically to bottom. **/ + inline public static var ALIGN_BOTTOM:Int = 1 << 5; + /** Default, align text vertically to baseline. **/ + inline public static var ALIGN_BASELINE:Int = 1 << 6; } @:include("nanovg.h") @@ -82,9 +93,15 @@ extern class NvgPaint { @:unreflective @:native("NVGglyphPosition") extern class NvgGlyphPosition { + @:native("new NvgGlyphPosition") + static public function create():Pointer; + /** Position of the glyph in the input string. **/ public var str:ConstPointer; + /** The x-coordinate of the logical glyph position. **/ public var x:Float32; + /** The bounds of the glyph shape. **/ public var min:Float32; + /** The bounds of the glyph shape. **/ public var max:Float32; } @@ -93,293 +110,749 @@ extern class NvgGlyphPosition { @:unreflective @:native("NVGtextRow") extern class NvgTextRow { + @:native("new NVGtextRow") + static public function create():Pointer; + /** Pointer to the input text where the row starts. **/ public var start:ConstPointer; + /** Pointer to the input text where the row ends (one past the last character). **/ public var end:ConstPointer; + /** Pointer to the beginning of the next row. **/ public var next:ConstPointer; + /** Logical width of the row. **/ public var width:Float32; + /** Actual bounds of the row. Logical with and bounds can differ because of kerning and some parts over extending. **/ public var minx:Float32; + /** Actual bounds of the row. Logical with and bounds can differ because of kerning and some parts over extending. **/ public var maxx:Float32; } +class NVGimageFlags { + /** Generate mipmaps during creation of the image. **/ + inline public static var IMAGE_GENERATE_MIPMAPS:Int = 1 << 0; + /** Repeat image in X direction. **/ + inline public static var IMAGE_REPEATX:Int = 1 << 1; + /** Repeat image in Y direction. **/ + inline public static var IMAGE_REPEATY:Int = 1 << 2; + /** Flips (inverses) image in Y direction when rendered. **/ + inline public static var IMAGE_FLIPY:Int = 1 << 3; + /** Image data has premultiplied alpha. **/ + inline public static var IMAGE_PREMULTIPLIED:Int = 1 << 4; +} @:include("hx-nanovg.h") @:include("nanovg.h") @:buildXml("&") extern class Nvg { - @:native("nanovg::nvgCreateGL") - public static function createGL(_flags:Int):Pointer; - - @:native("nanovg::nvgDeleteGL") - public static function deleteGL(_ctx:Pointer):Void; - - @:native("::nvgBeginFrame") - public static function beginFrame(_ctx:Pointer, _windowWidth:Int, _windowHeight:Int, _devicePixelRatio:Float32):Void; - - @:native("::nvgEndFrame") - public static function endFrame(_ctx:Pointer):Void; - - - @:native("::nvgRGB") - public static function rgb(_r:UInt8, _g:UInt8, _b:UInt8):NvgColor; - - @:native("::nvgRGBf") - public static function rgbf(_r:Float32, _g:Float32, _b:Float32):NvgColor; - - @:native("::nvgRGBA") - public static function rgba(_r:UInt8, _g:UInt8, _b:UInt8, _a:UInt8):NvgColor; - - @:native("::nvgRGBAf") - public static function rgbaf(_r:Float32, _g:Float32, _b:Float32, _a:Float32):NvgColor; - - @:native("::nvgLerpRGBA") - public static function lerpRgba(_c0:NvgColor, _c1:NvgColor, _u:Float32):NvgColor; - - @:native("::nvgTransRGBA") - public static function transRgba(_c0:NvgColor, _a:UInt8):NvgColor; - - @:native("::nvgTransRGBAf") - public static function transRgbaf(_c0:NvgColor, _a:Float32):NvgColor; - - @:native("::nvgHSL") - public static function hsl(_h:Float32, _s:Float32, _l:Float32):NvgColor; - - @:native("::nvgHSLA") - public static function hsla(_h:Float32, _s:Float32, _l:Float32, _a:UInt8):NvgColor; - - - @:native("::nvgSave") - public static function save(_ctx:Pointer):Void; - - @:native("::nvgRestore") - public static function restore(_ctx:Pointer):Void; - - @:native("::nvgReset") - public static function reset(_ctx:Pointer):Void; - - - @:native("::nvgStrokeColor") - public static function strokeColor(_ctx:Pointer, _color:NvgColor):Void; - - @:native("::nvgStrokePaint") - public static function strokePaint(_ctx:Pointer, _paint:NvgPaint):Void; - - @:native("::nvgFillColor") - public static function fillColor(_ctx:Pointer, _color:NvgColor):Void; - - @:native("::nvgFillPaint") - public static function fillPaint(_ctx:Pointer, _paint:NvgPaint):Void; - - @:native("::nvgMiterLimit") - public static function miterLimit(_ctx:Pointer, _limit:Float32):Void; - - @:native("::nvgStrokeWidth") - public static function strokeWidth(_ctx:Pointer, _size:Float32):Void; - - @:native("::nvgLineCap") - public static function lineCap(_ctx:Pointer, _cap:Int):Void; - - @:native("::nvgLineJoin") - public static function lineJoin(_ctx:Pointer, _join:Int):Void; - - @:native("::nvgGlobalAlpha") - public static function globalAlpha(_ctx:Pointer, _alpha:Float32):Void; - - - @:native("::nvgResetTransform") - public static function resetTransform(_ctx:Pointer):Void; - - - @:native("::nvgTransform") - public static function transform(_ctx:Pointer, _a:Float32, _b:Float32, _c:Float32, _d:Float32, _e:Float32, _f:Float32):Void; - - @:native("::nvgTranslate") - public static function translate(_ctx:Pointer, _x:Float32, _y:Float32):Void; - - @:native("::nvgRotate") - public static function rotate(_ctx:Pointer, _angle:Float32):Void; - - @:native("::nvgSkewX") - public static function skewX(_ctx:Pointer, _angle:Float32):Void; - - @:native("::nvgSkewY") - public static function skewY(_ctx:Pointer, _angle:Float32):Void; - - @:native("::nvgScale") - public static function scale(_ctx:Pointer, _x:Float32, _y:Float32):Void; - - @:native("::nvgCurrentTransform") - public static function currentTransform(_ctx:Pointer, _xForm:Float32):Void; - - @:native("::nvgTransformIdentity") - public static function transformIdentity(_dst:Float32):Void; - - @:native("::nvgTransformTranslate") - public static function transformTranslate(_dst:Pointer, _tx:Float32, _ty:Float32):Void; - - @:native("::nvgTransformScale") - public static function transformScale(_dst:Pointer, _sx:Float32, _sy:Float32):Void; - - @:native("::nvgTransformRotate") - public static function transformRotate(_dst:Pointer, _angle:Float32):Void; - - @:native("::nvgTransformSkewX") - public static function transformSkewX(_dst:Pointer, _angle:Float32):Void; - - @:native("::nvgTransformSkewY") - public static function transformSkewY(_dst:Pointer, _angle:Float32):Void; - - @:native("::nvgTransformMultiply") - public static function transformMultiply(_dst:Pointer, _src:ConstPointer):Void; - - @:native("::nvgTransformPremultiply") - public static function transformPremultiply(_dst:Pointer, _src:ConstPointer):Void; - - @:native("::nvgTransformInverse") - public static function transformInverse(_dst:Pointer, _src:ConstPointer):Void; - - @:native("::nvgTransformPoint") - public static function transformPoint(_dstx:Pointer, _dsty:Pointer, _xform:ConstPointer, _srcx:Float32, _srcy:Float32):Void; - - - @:native("::nvgDegToRad") - public static function degToRad(_deg:Float32):Float32; - - @:native("::nvgRadToDeg") - public static function radToDeg(_rad:Float32):Float32; - - - @:native("::nvgCreateImage") - public static function createImage(_ctx:Pointer, _filename:ConstPointer):Int; - - @:native("::nvgCreateImageMem") - public static function createImageMem(_ctx:Pointer, _data:Pointer, _ndata:Int):Int; - - @:native("::nvgCreateImageRGBA") - public static function createImageRGBA(_ctx:Pointer, _w:Int, _h:Int, _data:Pointer):Int; - - @:native("::nvgUpdateImage") - public static function updateImage(_ctx:Pointer, _image:Int, _data:Pointer):Void; - - @:native("::nvgImageSize") - public static function imageSize(_ctx:Pointer, _image:Int, _w:Pointer, _h:Pointer):Void; - - @:native("::nvgDeleteImage") - public static function deleteImage(_ctx:Pointer, _image:Int):Void; - - - @:native("::nvgLinearGradient") - public static function linearGradient(_ctx:Pointer, _sx:Float32, _sy:Float32, _ex:Float32, _ey:Float32, _icol:NvgColor, _ocol:NvgColor):NvgPaint; - - @:native("::nvgBoxGradient") - public static function boxGradient(_ctx:Pointer, _x:Float32, _y:Float32, _w:Float32, _h:Float32, _r:Float32, _f:Float32, _icol:NvgColor, _ocol:NvgColor):NvgPaint; - - @:native("::nvgRadialGradient") - public static function radialGradient(_ctx:Pointer, _cx:Float32, _cy:Float32, _inr:Float32, _outr:Float32, _icol:NvgColor, _ocol:NvgColor):NvgPaint; - - @:native("::nvgImagePattern") - public static function imagePattern(_ctx:Pointer, _ox:Float32, _oy:Float32, _ex:Float32, _ey:Float32, _angle:Float32, _image:Int, _repeat:Int, _alpha:Float32):NvgPaint; - - - @:native("::nvgScissor") - public static function scissor(_ctx:Pointer, _x:Float32, _y:Float32, _w:Float32, _h:Float32):Void; - - @:native("::nvgResetScissor") - public static function resetScissor(_ctx:Pointer):Void; - - - @:native("::nvgBeginPath") - public static function beginPath(_ctx:Pointer):Void; - - @:native("::nvgMoveTo") - public static function moveTo(_ctx:Pointer, _x:Float32, _y:Float32):Void; - - @:native("::nvgLineTo") - public static function lineTo(_ctx:Pointer, _x:Float32, _y:Float32):Void; - - @:native("::nvgBezierTo") - public static function bezierTo(_ctx:Pointer, _c1x:Float32, _c1y:Float32, _c2x:Float32, _c2y:Float32, _x:Float32, _y:Float32):Void; - - @:native("::nvgArcTo") - public static function arcTo(_ctx:Pointer, _x1:Float32, _y1:Float32, _x2:Float32, _y2:Float32, _radius:Float32):Void; - - @:native("::nvgClosePath") - public static function closePath(_ctx:Pointer):Void; - - @:native("::nvgPathWinding") - public static function pathWinding(_ctx:Pointer, _dir:Int):Void; - - @:native("::nvgArc") - public static function arc(_ctx:Pointer, _cx:Int, _cy:Int, _r:Float32, _a0:Float32, _a1:Float32, _dir:Int):Void; - - @:native("::nvgRect") - public static function rect(_ctx:Pointer, _x:Int, _y:Int, _w:Float32, _h:Float32):Void; - - @:native("::nvgRoundedRect") - public static function roundedRect(_ctx:Pointer, _x:Int, _y:Int, _w:Float32, _h:Float32, _r:Float32):Void; - - @:native("::nvgEllipse") - public static function ellipse(_ctx:Pointer, _cx:Int, _cy:Int, _rx:Float32, _ry:Float32):Void; - - @:native("::nvgCircle") - public static function circle(_ctx:Pointer, _cx:Int, _cy:Int, _r:Float32):Void; - - @:native("::nvgFill") - public static function fill(_ctx:Pointer):Void; - - @:native("::nvgStroke") - public static function stroke(_ctx:Pointer):Void; - - - @:native("::nvgCreateFont") - public static function createFont(_ctx:Pointer, _name:ConstPointer, _filename:ConstPointer):Int; - - @:native("::nvgCreateFontMem") - public static function createFontMem(_ctx:Pointer, _name:ConstPointer, _data:Pointer, _ndata:Int, _freeData:Int):Int; - - @:native("::nvgFindFont") - public static function findFont(_ctx:Pointer, _name:ConstPointer):Int; - - @:native("::nvgFontSize") - public static function fontSize(_ctx:Pointer, _size:Float32):Void; - - @:native("::nvgFontBlur") - public static function fontBlur(_ctx:Pointer, _blur:Float32):Void; - - @:native("::nvgTextLetterSpacing") - public static function textLetterSpacing(_ctx:Pointer, _spacing:Float32):Void; - - @:native("::nvgTextLineHeight") - public static function textLineHeight(_ctx:Pointer, _lineHeight:Float32):Void; - - @:native("::nvgTextAlign") - public static function textAlign(_ctx:Pointer, _align:Int):Void; - - @:native("::nvgFontFaceId") - public static function fontFaceId(_ctx:Pointer, _font:Int):Void; - - @:native("::nvgFontFace") - public static function fontFace(_ctx:Pointer, _font:ConstPointer):Void; - - @:native("::nvgText") - public static function text(_ctx:Pointer, _x:Float32, _y:Float32, _string:ConstPointer, _end:ConstPointer):Float32; - - @:native("::nvgTextBox") - public static function textBox(_ctx:Pointer, _x:Float32, _y:Float32, _breakRowWidth:Float32, _string:ConstPointer, _end:ConstPointer):Void; - - @:native("::nvgTextBounds") - public static function textBounds(_ctx:Pointer, _x:Float32, _y:Float32, _string:ConstPointer, _end:ConstPointer, _bounds:Pointer):Float32; - - @:native("::nvgTextBoxBounds") - public static function textBoxBounds(_ctx:Pointer, _x:Float32, _y:Float32, _breakRowWidth:Float32, _string:ConstPointer, _end:ConstPointer, _bounds:Pointer):Void; - - @:native("::nvgTextGlyphPositions") - public static function textGlyphPositions(_ctx:Pointer, _x:Float32, _y:Float32, _string:ConstPointer, _end:ConstPointer, _positions:Pointer, _maxPositions:Int):Int; - - @:native("::nvgTextMetrics") - public static function textMetrics(_ctx:Pointer, _ascender:Pointer, _descender:Pointer, _lineh:Pointer):Void; - - @:native("::nvgTextBreakLines") - public static function textBreakLines(_ctx:Pointer, _string:ConstPointer, _end:ConstPointer, _breakRowWidth:Float32, _rows:Pointer, _maxRows:Int):Int; + @:native("nanovg::nvgCreateGL") + public static function createGL(_flags:Int):Pointer; + + @:native("nanovg::nvgDeleteGL") + public static function deleteGL(_ctx:Pointer):Void; + + @:native("::nvgBeginFrame") + /** + * Begin drawing a new frame + * Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame() + * nvgBeginFrame() defines the size of the window to render to in relation currently + * set viewport (i.e. glViewport on GL backends). Device pixel ration allows to + * control the rendering on Hi-DPI devices. + * For example, GLFW returns two dimension for an opened window: window size and + * frame buffer size. In that case you would set windowWidth/Height to the window size + * @param _ctx + * @param _windowWidth + * @param _windowHeight + * @param _devicePixelRatio frameBufferWidth / windowWidth + */ + public static function beginFrame(_ctx:Pointer, _windowWidth:Int, _windowHeight:Int, _devicePixelRatio:Float32):Void; + + @:native("::nvgCancelFrame") + /** + * Cancels drawing the current frame. + */ + public static function cancelFrame(_ctx:Pointer):Void; + + @:native("::nvgEndFrame") + /** + * Ends drawing flushing remaining render state. + */ + public static function endFrame(_ctx:Pointer):Void; + + // + // Color utils + // + // Colors in NanoVG are stored as unsigned ints in ABGR format. + + @:native("::nvgRGB") + /** + * Returns a color value from red, green, blue values. Alpha will be set to 255 (1.0). + */ + public static function rgb(_r:UInt8, _g:UInt8, _b:UInt8):NvgColor; + + @:native("::nvgRGBf") + /** + * Returns a color value from red, green, blue values. Alpha will be set to 1.0. + */ + public static function rgbf(_r:Float32, _g:Float32, _b:Float32):NvgColor; + + @:native("::nvgRGBA") + /** + * Returns a color value from red, green, blue and alpha values. [0..255] + */ + public static function rgba(_r:UInt8, _g:UInt8, _b:UInt8, _a:UInt8):NvgColor; + + @:native("::nvgRGBAf") + /** + * Returns a color value from red, green, blue and alpha values. [0..1] + */ + public static function rgbaf(_r:Float32, _g:Float32, _b:Float32, _a:Float32):NvgColor; + + @:native("::nvgLerpRGBA") + /** + * Linearly interpolates from color c0 to c1, and returns resulting color value. + */ + public static function lerpRgba(_c0:NvgColor, _c1:NvgColor, _u:Float32):NvgColor; + + @:native("::nvgTransRGBA") + /** Sets transparency of a color value. **/ + public static function transRgba(_c0:NvgColor, _a:UInt8):NvgColor; + + @:native("::nvgTransRGBAf") + /** Sets transparency of a color value. **/ + public static function transRgbaf(_c0:NvgColor, _a:Float32):NvgColor; + + @:native("::nvgHSL") + /** + * Returns color value specified by hue, saturation and lightness. + * HSL values are all in range [0..1], alpha will be set to 255. + */ + public static function hsl(_h:Float32, _s:Float32, _l:Float32):NvgColor; + + @:native("::nvgHSLA") + /** + * Returns color value specified by hue, saturation and lightness. + * HSL values are all in range [0..1], alpha in range [0..255]. + */ + public static function hsla(_h:Float32, _s:Float32, _l:Float32, _a:UInt8):NvgColor; + + // State Handling + // + // NanoVG contains state which represents how paths will be rendered. + // The state contains transform, fill and stroke styles, text and font styles, and scissor clipping. + + @:native("::nvgSave") + /** + * Pushes and saves the current render state into a state stack. + * A matching nvgRestore() must be used to restore the state. + */ + public static function save(_ctx:Pointer):Void; + + @:native("::nvgRestore") + /** + * Pops and restores current render state. + */ + public static function restore(_ctx:Pointer):Void; + + @:native("::nvgReset") + /** + * Resets current render state to default values. Does not affect the render state stack. + */ + public static function reset(_ctx:Pointer):Void; + + // + // Render styles + // + // Fill and stroke render style can be either a solid color or a paint which is a gradient or a pattern. + // Solid color is simply defined as a color value, different kinds of paints can be created + // using nvgLinearGradient(), nvgBoxGradient(), nvgRadialGradient() and nvgImagePattern(). + // + // Current render style can be saved and restored using nvgSave() and nvgRestore(). + + @:native("::nvgStrokeColor") + /** + * Sets current stroke style to a solid color. + */ + public static function strokeColor(_ctx:Pointer, _color:NvgColor):Void; + + @:native("::nvgStrokePaint") + /** + * Sets current stroke style to a paint, which can be a one of the gradients or a pattern. + */ + public static function strokePaint(_ctx:Pointer, _paint:NvgPaint):Void; + + @:native("::nvgFillColor") + /** + * Sets current fill style to a solid color. + */ + public static function fillColor(_ctx:Pointer, _color:NvgColor):Void; + + @:native("::nvgFillPaint") + /** + * Sets current fill style to a paint, which can be a one of the gradients or a pattern. + */ + public static function fillPaint(_ctx:Pointer, _paint:NvgPaint):Void; + + @:native("::nvgMiterLimit") + /** + * Sets the miter limit of the stroke style. + * Miter limit controls when a sharp corner is beveled. + */ + public static function miterLimit(_ctx:Pointer, _limit:Float32):Void; + + @:native("::nvgStrokeWidth") + /** + * Sets the stroke width of the stroke style. + */ + public static function strokeWidth(_ctx:Pointer, _size:Float32):Void; + + @:native("::nvgLineCap") + /** + * Sets how the end of the line (cap) is drawn, + * Can be one of: NvgLineCap.BUTT (default), NvgLineCap.ROUND, NvgLineCap.SQUARE. + */ + public static function lineCap(_ctx:Pointer, _cap:Int):Void; + + @:native("::nvgLineJoin") + /** + * Sets how sharp path corners are drawn. + * Can be one of NvgLineCap.MITER (default), NvgLineCap.ROUND, NvgLineCap.BEVEL. + */ + public static function lineJoin(_ctx:Pointer, _join:Int):Void; + + @:native("::nvgGlobalAlpha") + /** + * Sets the transparency applied to all rendered shapes. + * Already transparent paths will get proportionally more transparent as well. + */ + public static function globalAlpha(_ctx:Pointer, _alpha:Float32):Void; + + // + // Transforms + // + // The paths, gradients, patterns and scissor region are transformed by an transformation + // matrix at the time when they are passed to the API. + // The current transformation matrix is a affine matrix: + // [sx kx tx] + // [ky sy ty] + // [ 0 0 1] + // Where: sx,sy define scaling, kx,ky skewing, and tx,ty translation. + // The last row is assumed to be 0,0,1 and is not stored. + // + // Apart from nvgResetTransform(), each transformation function first creates + // specific transformation matrix and pre-multiplies the current transformation by it. + // + // Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore(). + + @:native("::nvgResetTransform") + /** + * Resets current transform to a identity matrix. + */ + public static function resetTransform(_ctx:Pointer):Void; + + @:native("::nvgTransform") + /** + * Premultiplies current coordinate system by specified matrix. + * The parameters are interpreted as matrix as follows: + * [a c e] + * [b d f] + * [0 0 1] + */ + public static function transform(_ctx:Pointer, _a:Float32, _b:Float32, _c:Float32, _d:Float32, _e:Float32, _f:Float32):Void; + + @:native("::nvgTranslate") + /** + * Translates current coordinate system. + */ + public static function translate(_ctx:Pointer, _x:Float32, _y:Float32):Void; + + @:native("::nvgRotate") + /** + * Rotates current coordinate system. Angle is specified in radians. + */ + public static function rotate(_ctx:Pointer, _angle:Float32):Void; + + @:native("::nvgSkewX") + /** + * Skews the current coordinate system along X axis. Angle is specified in radians. + */ + public static function skewX(_ctx:Pointer, _angle:Float32):Void; + + @:native("::nvgSkewY") + /** + * Skews the current coordinate system along Y axis. Angle is specified in radians. + */ + public static function skewY(_ctx:Pointer, _angle:Float32):Void; + + @:native("::nvgScale") + /** + * Scales the current coordinate system. + */ + public static function scale(_ctx:Pointer, _x:Float32, _y:Float32):Void; + + @:native("::nvgCurrentTransform") + /** + * Stores the top part (a-f) of the current transformation matrix in to the specified buffer. + * [a c e] + * [b d f] + * [0 0 1] + * There should be space for 6 floats in the return buffer for the values a-f. + */ + public static function currentTransform(_ctx:Pointer, _xForm:Float32):Void; + + // The following functions can be used to make calculations on 2x3 transformation matrices. + // A 2x3 matrix is represented as float[6]. + + @:native("::nvgTransformIdentity") + /** + * Sets the transform to identity matrix. + */ + public static function transformIdentity(_dst:Pointer):Void; + + @:native("::nvgTransformTranslate") + /** + * Sets the transform to translation matrix matrix. + */ + public static function transformTranslate(_dst:Pointer, _tx:Float32, _ty:Float32):Void; + + @:native("::nvgTransformScale") + /** + * Sets the transform to scale matrix. + */ + public static function transformScale(_dst:Pointer, _sx:Float32, _sy:Float32):Void; + + @:native("::nvgTransformRotate") + /** + * Sets the transform to rotate matrix. Angle is specified in radians. + */ + public static function transformRotate(_dst:Pointer, _angle:Float32):Void; + + @:native("::nvgTransformSkewX") + /** + * Sets the transform to skew-x matrix. Angle is specified in radians. + */ + public static function transformSkewX(_dst:Pointer, _angle:Float32):Void; + + @:native("::nvgTransformSkewY") + /** + * Sets the transform to skew-y matrix. Angle is specified in radians. + */ + public static function transformSkewY(_dst:Pointer, _angle:Float32):Void; + + @:native("::nvgTransformMultiply") + /** + * Sets the transform to the result of multiplication of two transforms, of A = A*B. + */ + public static function transformMultiply(_dst:Pointer, _src:ConstPointer):Void; + + @:native("::nvgTransformPremultiply") + /** + * Sets the transform to the result of multiplication of two transforms, of A = B*A. + */ + public static function transformPremultiply(_dst:Pointer, _src:ConstPointer):Void; + + @:native("::nvgTransformInverse") + /** + * Sets the destination to inverse of specified transform. + * Returns 1 if the inverse could be calculated, else 0. + */ + public static function transformInverse(_dst:Pointer, _src:ConstPointer):Void; + + @:native("::nvgTransformPoint") + /** + * Transform a point by given transform. + */ + public static function transformPoint(_dstx:Pointer, _dsty:Pointer, _xform:ConstPointer, _srcx:Float32, _srcy:Float32):Void; + + + @:native("::nvgDegToRad") + /** + * Converts degrees to radians. + */ + public static function degToRad(_deg:Float32):Float32; + + @:native("::nvgRadToDeg") + /** + * Converts radians to degrees. + */ + public static function radToDeg(_rad:Float32):Float32; + + // + // Images + // + // NanoVG allows you to load jpg, png, psd, tga, pic and gif files to be used for rendering. + // In addition you can upload your own image. The image loading is provided by stb_image. + // The parameter imageFlags is combination of flags defined in NVGimageFlags. + + @:native("::nvgCreateImage") + /** + * Creates image by loading it from the disk from specified file name. + * Returns handle to the image. + */ + public static function createImage(_ctx:Pointer, _filename:ConstPointer, _imageFlags:Int):Int; + + @:native("::nvgCreateImageMem") + /** + * Creates image by loading it from the specified chunk of memory. + * Returns handle to the image. + */ + public static function createImageMem(_ctx:Pointer, _data:Pointer, _ndata:Int):Int; + + @:native("::nvgCreateImageRGBA") + /** + * Creates image from specified image data. + * Returns handle to the image. + */ + public static function createImageRGBA(_ctx:Pointer, _w:Int, _h:Int, _data:Pointer):Int; + + @:native("::nvgUpdateImage") + /** + * Updates image data specified by image handle. + */ + public static function updateImage(_ctx:Pointer, _image:Int, _data:Pointer):Void; + + @:native("::nvgImageSize") + /** + * Returns the dimensions of a created image. + */ + public static function imageSize(_ctx:Pointer, _image:Int, _w:Pointer, _h:Pointer):Void; + + @:native("::nvgDeleteImage") + /** + * Deletes created image. + */ + public static function deleteImage(_ctx:Pointer, _image:Int):Void; + + // + // Paints + // + // NanoVG supports four types of paints: linear gradient, box gradient, radial gradient and image pattern. + // These can be used as paints for strokes and fills. + + @:native("::nvgLinearGradient") + /** + * Creates and returns a linear gradient. Parameters (sx,sy)-(ex,ey) specify the start and end coordinates + * of the linear gradient, icol specifies the start color and ocol the end color. + * The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). + */ + public static function linearGradient(_ctx:Pointer, _sx:Float32, _sy:Float32, _ex:Float32, _ey:Float32, _icol:NvgColor, _ocol:NvgColor):NvgPaint; + + @:native("::nvgBoxGradient") + /** + * Creates and returns a box gradient. Box gradient is a feathered rounded rectangle, it is useful for rendering + * drop shadows or highlights for boxes. Parameters (x,y) define the top-left corner of the rectangle, + * (w,h) define the size of the rectangle, r defines the corner radius, and f feather. Feather defines how blurry + * the border of the rectangle is. Parameter icol specifies the inner color and ocol the outer color of the gradient. + * The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). + */ + public static function boxGradient(_ctx:Pointer, _x:Float32, _y:Float32, _w:Float32, _h:Float32, _r:Float32, _f:Float32, _icol:NvgColor, _ocol:NvgColor):NvgPaint; + + @:native("::nvgRadialGradient") + /** + * Creates and returns a radial gradient. Parameters (cx,cy) specify the center, inr and outr specify + * the inner and outer radius of the gradient, icol specifies the start color and ocol the end color. + * The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). + */ + public static function radialGradient(_ctx:Pointer, _cx:Float32, _cy:Float32, _inr:Float32, _outr:Float32, _icol:NvgColor, _ocol:NvgColor):NvgPaint; + + @:native("::nvgImagePattern") + /** + * Creates and returns an image patter. Parameters (ox,oy) specify the left-top location of the image pattern, + * (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render. + * The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). + */ + public static function imagePattern(_ctx:Pointer, _ox:Float32, _oy:Float32, _ex:Float32, _ey:Float32, _angle:Float32, _image:Int, _alpha:Float32):NvgPaint; + + // + // Scissoring + // + // Scissoring allows you to clip the rendering into a rectangle. This is useful for various + // user interface cases like rendering a text edit or a timeline. + + @:native("::nvgScissor") + /** + * Sets the current scissor rectangle. + * The scissor rectangle is transformed by the current transform. + */ + public static function scissor(_ctx:Pointer, _x:Float32, _y:Float32, _w:Float32, _h:Float32):Void; + + @:native("::nvgIntersectScissor") + /** + * Intersects current scissor rectangle with the specified rectangle. + * The scissor rectangle is transformed by the current transform. + * Note: in case the rotation of previous scissor rect differs from + * the current one, the intersection will be done between the specified + * rectangle and the previous scissor rectangle transformed in the current + * transform space. The resulting shape is always rectangle. + */ + public static function intersectScissor(_ctx:Pointer, x:Float, y:Float, w:Float, h:Float):Void; + + @:native("::nvgResetScissor") + /** + * Reset and disables scissoring. + */ + public static function resetScissor(_ctx:Pointer):Void; + + // + // Paths + // + // Drawing a new shape starts with nvgBeginPath(), it clears all the currently defined paths. + // Then you define one or more paths and sub-paths which describe the shape. The are functions + // to draw common shapes like rectangles and circles, and lower level step-by-step functions, + // which allow to define a path curve by curve. + // + // NanoVG uses even-odd fill rule to draw the shapes. Solid shapes should have counter clockwise + // winding and holes should have counter clockwise order. To specify winding of a path you can + // call nvgPathWinding(). This is useful especially for the common shapes, which are drawn CCW. + // + // Finally you can fill the path using current fill style by calling nvgFill(), and stroke it + // with current stroke style by calling nvgStroke(). + // + // The curve segments and sub-paths are transformed by the current transform. + + @:native("::nvgBeginPath") + /** + * Clears the current path and sub-paths. + */ + public static function beginPath(_ctx:Pointer):Void; + + @:native("::nvgMoveTo") + /** + * Starts new sub-path with specified point as first point. + */ + public static function moveTo(_ctx:Pointer, _x:Float32, _y:Float32):Void; + + @:native("::nvgLineTo") + /** + * Adds line segment from the last point in the path to the specified point. + */ + public static function lineTo(_ctx:Pointer, _x:Float32, _y:Float32):Void; + + @:native("::nvgBezierTo") + /** + * Adds cubic bezier segment from last point in the path via two control points to the specified point. + */ + public static function bezierTo(_ctx:Pointer, _c1x:Float32, _c1y:Float32, _c2x:Float32, _c2y:Float32, _x:Float32, _y:Float32):Void; + + @:native("::nvgQuadTo") + /** + * Adds an arc segment at the corner defined by the last path point, and two specified points. + */ + public static function quadTo(_ctx:Pointer, _cx:Float32, _cy:Float32, _x:Float32, _y:Float32):Void; + + @:native("::nvgArcTo") + /** + * Adds an arc segment at the corner defined by the last path point, and two specified points. + */ + public static function arcTo(_ctx:Pointer, _x1:Float32, _y1:Float32, _x2:Float32, _y2:Float32, _radius:Float32):Void; + + @:native("::nvgClosePath") + /** + * Closes current sub-path with a line segment. + */ + public static function closePath(_ctx:Pointer):Void; + + @:native("::nvgPathWinding") + /** + * Sets the current sub-path winding, see NvgWinding and NvgSolidity. + */ + public static function pathWinding(_ctx:Pointer, _dir:Int):Void; + + @:native("::nvgArc") + /** + * Creates new circle arc shaped sub-path. The arc center is at cx,cy, the arc radius is r, + * and the arc is drawn from angle a0 to a1, and swept in direction dir (NVG_CCW, or NVG_CW). + * Angles are specified in radians. + */ + public static function arc(_ctx:Pointer, _cx:Float32, _cy:Float32, _r:Float32, _a0:Float32, _a1:Float32, _dir:Int):Void; + + @:native("::nvgRect") + /** + * Creates new rectangle shaped sub-path. + */ + public static function rect(_ctx:Pointer, _x:Float32, _y:Float32, _w:Float32, _h:Float32):Void; + + @:native("::nvgRoundedRect") + /** + * Creates new rounded rectangle shaped sub-path. + */ + public static function roundedRect(_ctx:Pointer, _x:Float32, _y:Float32, _w:Float32, _h:Float32, _r:Float32):Void; + + @:native("::nvgEllipse") + /** + * Creates new ellipse shaped sub-path. + */ + public static function ellipse(_ctx:Pointer, _cx:Float32, _cy:Float32, _rx:Float32, _ry:Float32):Void; + + @:native("::nvgCircle") + /** + * Creates new circle shaped sub-path. + */ + public static function circle(_ctx:Pointer, _cx:Float32, _cy:Float32, _r:Float32):Void; + + @:native("::nvgFill") + /** + * Fills the current path with current fill style. + */ + public static function fill(_ctx:Pointer):Void; + + @:native("::nvgStroke") + /** + * Fills the current path with current stroke style. + */ + public static function stroke(_ctx:Pointer):Void; + + // + // Text + // + // NanoVG allows you to load .ttf files and use the font to render text. + // + // The appearance of the text can be defined by setting the current text style + // and by specifying the fill color. Common text and font settings such as + // font size, letter spacing and text align are supported. Font blur allows you + // to create simple text effects such as drop shadows. + // + // At render time the font face can be set based on the font handles or name. + // + // Font measure functions return values in local space, the calculations are + // carried in the same resolution as the final rendering. This is done because + // the text glyph positions are snapped to the nearest pixels sharp rendering. + // + // The local space means that values are not rotated or scale as per the current + // transformation. For example if you set font size to 12, which would mean that + // line height is 16, then regardless of the current scaling and rotation, the + // returned line height is always 16. Some measures may vary because of the scaling + // since aforementioned pixel snapping. + // + // While this may sound a little odd, the setup allows you to always render the + // same way regardless of scaling. I.e. following works regardless of scaling: + // + // var txt:String = "Text me up."; + // Nvg.textBounds(vg, x,y, txt.c_str(), NULL, bounds); + // Nvg.beginPath(vg); + // Nvg.roundedRect(vg, bounds[0],bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]); + // Nvg.fill(vg); + // + // Note: currently only solid color fill is supported for text. + + @:native("::nvgCreateFont") + /** + * Creates font by loading it from the disk from specified file name. + * Returns handle to the font. + */ + public static function createFont(_ctx:Pointer, _name:ConstPointer, _filename:ConstPointer):Int; + + @:native("::nvgCreateFontMem") + /** + * Creates image by loading it from the specified memory chunk. + * Returns handle to the font. + */ + public static function createFontMem(_ctx:Pointer, _name:ConstPointer, _data:Pointer, _ndata:Int, _freeData:Int):Int; + + @:native("::nvgFindFont") + /** + * Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found. + */ + public static function findFont(_ctx:Pointer, _name:ConstPointer):Int; + + @:native("::nvgFontSize") + /** + * Sets the font size of current text style. + */ + public static function fontSize(_ctx:Pointer, _size:Float32):Void; + + @:native("::nvgFontBlur") + /** + * Sets the blur of current text style. + */ + public static function fontBlur(_ctx:Pointer, _blur:Float32):Void; + + @:native("::nvgTextLetterSpacing") + /** + * Sets the letter spacing of current text style. + */ + public static function textLetterSpacing(_ctx:Pointer, _spacing:Float32):Void; + + @:native("::nvgTextLineHeight") + /** + * Sets the proportional line height of current text style. + * The line height is specified as multiple of font size. + */ + public static function textLineHeight(_ctx:Pointer, _lineHeight:Float32):Void; + + @:native("::nvgTextAlign") + /** + * Sets the text align of current text style, see NvgAlign for options. + */ + public static function textAlign(_ctx:Pointer, _align:Int):Void; + + @:native("::nvgFontFaceId") + /** + * Sets the font face based on specified id of current text style. + */ + public static function fontFaceId(_ctx:Pointer, _font:Int):Void; + + @:native("::nvgFontFace") + /** + * Sets the font face based on specified name of current text style. + */ + public static function fontFace(_ctx:Pointer, _font:ConstPointer):Void; + + @:native("::nvgText") + /** + * Draws text string at specified location. + * If end is specified only the sub-string up to the end is drawn. + */ + public static function text(_ctx:Pointer, _x:Float32, _y:Float32, _string:ConstPointer, _end:ConstPointer):Float32; + + @:native("::nvgTextBox") + /** + * Draws multi-line text string at specified location wrapped at the specified width. + * If end is specified only the sub-string up to the end is drawn. + * White space is stripped at the beginning of the rows, + * the text is split at word boundaries or when new-line characters are encountered. + * Words longer than the max width are slit at nearest character (i.e. no hyphenation). + */ + public static function textBox(_ctx:Pointer, _x:Float32, _y:Float32, _breakRowWidth:Float32, _string:ConstPointer, _end:ConstPointer):Void; + + @:native("::nvgTextBounds") + /** + * Measures the specified text string. Parameter bounds should be a pointer to float[4], + * if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax] + * Returns the horizontal advance of the measured text (i.e. where the next character should drawn). + * Measured values are returned in local coordinate space. + */ + public static function textBounds(_ctx:Pointer, _x:Float32, _y:Float32, _string:ConstPointer, _end:ConstPointer, _bounds:Pointer):Float32; + + @:native("::nvgTextBoxBounds") + /** + * Measures the specified multi-text string. Parameter bounds should be a pointer to float[4], + * if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax] + * Measured values are returned in local coordinate space. + */ + public static function textBoxBounds(_ctx:Pointer, _x:Float32, _y:Float32, _breakRowWidth:Float32, _string:ConstPointer, _end:ConstPointer, _bounds:Pointer):Void; + + @:native("::nvgTextGlyphPositions") + /** + * Calculates the glyph x positions of the specified text. + * If end is specified only the sub-string will be used. + * Measured values are returned in local coordinate space. + */ + public static function textGlyphPositions(_ctx:Pointer, _x:Float32, _y:Float32, _string:ConstPointer, _end:ConstPointer, _positions:Pointer, _maxPositions:Int):Int; + + @:native("::nvgTextMetrics") + /** + * Returns the vertical metrics based on the current text style. + * Measured values are returned in local coordinate space. + */ + public static function textMetrics(_ctx:Pointer, _ascender:Pointer, _descender:Pointer, _lineh:Pointer):Void; + + @:native("::nvgTextBreakLines") + /** + * Breaks the specified text into lines. If end is specified only the sub-string will be used. + * White space is stripped at the beginning of the rows, + * the text is split at word boundaries or when new-line characters are encountered. + * Words longer than the max width are slit at nearest character (i.e. no hyphenation). + */ + public static function textBreakLines(_ctx:Pointer, _string:ConstPointer, _end:ConstPointer, _breakRowWidth:Float32, _rows:Pointer, _maxRows:Int):Int; }