Initial release

This commit is contained in:
civ
2026-08-16 18:24:52 +07:00
commit 876886a39a
13244 changed files with 2353959 additions and 0 deletions
@@ -0,0 +1,79 @@
if(NOT SMTG_ENABLE_VSTGUI_SUPPORT OR SMTG_LINUX)
return()
endif()
cmake_minimum_required(VERSION 3.25.0)
project(smtg-vst3-dataexchange
VERSION ${vstsdk_VERSION}.0
DESCRIPTION "Steinberg VST 3 Data Exchange example"
)
smtg_add_vst3plugin(data-exchange
source/factory.cpp
source/controller.cpp
source/processor.cpp
source/shared.h
source/version.h
source/waveformview.h
source/waveformview.cpp
source/3rdparty/nanovg/src/nanovg.h
source/3rdparty/nanovg/src/nanovg.c
)
smtg_target_add_plugin_resources(data-exchange
RESOURCES
resource/editor.uidesc
)
target_link_libraries(data-exchange
PRIVATE
vstgui_support
)
target_include_directories(data-exchange PRIVATE source/3rdparty/nanovg/src/)
smtg_target_setup_as_vst3_example(data-exchange)
if(SMTG_MAC)
target_include_directories(data-exchange PRIVATE source/3rdparty/MetalNanoVG/src/)
target_sources(data-exchange PRIVATE
source/waveformview_metal.mm
source/3rdparty/MetalNanoVG/src/nanovg_mtl_shaders.metal
source/3rdparty/MetalNanoVG/src/nanovg_mtl.h
source/3rdparty/MetalNanoVG/src/nanovg_mtl.m
)
set_source_files_properties(
"source/3rdparty/MetalNanoVG/src/nanovg_mtl.m" PROPERTIES
COMPILE_FLAGS "-fobjc-arc"
)
target_link_libraries(data-exchange PRIVATE
"-framework Metal"
"-framework QuartzCore"
"-framework CoreAudio"
)
endif(SMTG_MAC)
if(SMTG_WIN)
target_include_directories(data-exchange PRIVATE source/3rdparty/D3D11NanoVG/)
target_sources(data-exchange PRIVATE
source/waveformview_direct3d.cpp
source/3rdparty/D3D11NanoVG/D3D11PixelShader.h
source/3rdparty/D3D11NanoVG/D3D11PixelShaderAA.h
# source/3rdparty/D3D11NanoVG/D3D11PixelShader.hlsl
# source/3rdparty/D3D11NanoVG/D3D11PixelShaderAA.hlsl
# source/3rdparty/D3D11NanoVG/D3D11PixelShaderNoAA.hlsl
# source/3rdparty/D3D11NanoVG/D3D11VertexShader.hlsl
source/3rdparty/D3D11NanoVG/D3D11VertexShader.h
source/3rdparty/D3D11NanoVG/nanovg_d3d11.h
)
endif(SMTG_WIN)
@@ -0,0 +1,20 @@
# DataExchange
## Introduction
**DataExchange** is simple FX plug-in showing :
* how to exchange data (waveform) between processor (in the realtime thread) and controller using the VST Data Exchange API: [Steinberg::Vst::IDataExchangeHandler](https://steinbergmedia.github.io/vst3_dev_portal/pages/Technical+Documentation/Data+Exchange/Index.html)
* how easy it is to use [VSTGUI](https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/VSTGUI.html)
> See also: [Online Documentation](https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/Plug-in+Examples.html#dataexchange).
## Getting Started
This plug-in is part of the VST 3 SDK package. It is created with the VST 3 SDK root project.
> See the top-level README of the VST 3 SDK: https://github.com/steinbergmedia/vst3sdk.git
## Getting Help
* Read through the SDK documentation on the **[VST 3 Developer Portal](https://steinbergmedia.github.io/vst3_dev_portal/pages/index.html)**
* Ask some real people in the official **[VST 3 Developer Forum](https://forums.steinberg.net/c/developer/103)**
@@ -0,0 +1,320 @@
{
"vstgui-ui-description": {
"version": "1",
"bitmaps": {},
"fonts": {},
"colors": {
"background": "#1d1d1dff",
"control.back": "#64646462",
"control.frame": "#676767ff",
"control.text": "#ffffffff",
"label.text": "#676767ff",
"waveform.left": "#ff0000ff",
"waveform.right": "#00ff00bc"
},
"control-tags": {
"Auto_ReEnable_DataExchange": "10005",
"DisplayFreq": "10002",
"EnableDataExchange": "1",
"FPS": "10004",
"Force_MessageHandling": "10003",
"PeakLeft": "10000",
"PeakRight": "10001"
},
"custom": {
"FocusDrawing": {},
"VST3Editor": {
"Path": "/Volumes/Quasar/mono-dev-pluginset/public.sdk/samples/vst/dataexchange/resource/editor.uidesc"
},
"UIGridController": {
"Grids": "1x 1,5x 5,10x 10,12x 12,15x 15"
},
"UIEditController": {
"EditViewScale": "1",
"EditorSize": "0, 0, 1302, 978",
"SplitViewSize_0_0": "0.572478991596638620009684927936177700758",
"SplitViewSize_0_1": "0.4065126050420168057897285507351625710726",
"SplitViewSize_1_0": "0.4863445378151260434229641305137192830443",
"SplitViewSize_1_1": "0.5084033613445377852713136235252022743225",
"SplitViewSize_2_0": "0.7680491551459293075865275568503420799971",
"SplitViewSize_2_1": "0.2281105990783410253364138498000102117658",
"TabSwitchValue": "2",
"UI Theme": "Dark",
"Version": "1",
"ViewBackground": "3"
},
"UITemplateController": {
"SelectedTemplate": "view"
},
"UIAttributesController": {},
"UIViewCreatorDataSource": {
"SelectedRow": "26"
},
"UITagsDataSource": {
"SelectedRow": "0"
},
"UIColorsDataSource": {
"SelectedRow": "6"
},
"UIFontsDataSource": {
"SelectedRow": "-1"
}
},
"templates": {
"view": {
"attributes": {
"autosize": "left right top bottom ",
"background-color": "background",
"background-color-draw-style": "filled and stroked",
"class": "CViewContainer",
"maxSize": "32767, 32000",
"minSize": "500, 160",
"mouse-enabled": "true",
"opacity": "1",
"origin": "0, 0",
"size": "500, 160",
"transparent": "false",
"wants-focus": "false"
},
"children": {
"CCheckBox": {
"attributes": {
"autosize-to-fit": "false",
"boxfill-color": "control.back",
"boxframe-color": "control.frame",
"checkmark-color": "control.text",
"class": "CCheckBox",
"control-tag": "EnableDataExchange",
"default-value": "0",
"draw-crossbox": "true",
"font": "~ SystemFont",
"font-color": "control.text",
"frame-width": "1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "10, 10",
"round-rect-radius": "0",
"size": "210, 20",
"title": "Enable Realtime Data exchange",
"transparent": "false",
"wants-focus": "true",
"wheel-inc-value": "0.1"
}
},
"CView": {
"attributes": {
"autosize": "left right top bottom ",
"class": "CView",
"custom-view-name": "PeakImageView",
"mouse-enabled": "true",
"opacity": "1",
"origin": "0, 60",
"size": "500, 90",
"transparent": "false",
"wants-focus": "false"
}
},
"CSlider": {
"attributes": {
"bitmap-offset": "0, 0",
"class": "CSlider",
"control-tag": "DisplayFreq",
"default-value": "0.0990991",
"draw-back": "true",
"draw-back-color": "~ BlackCColor",
"draw-frame": "true",
"draw-frame-color": "~ GreyCColor",
"draw-value": "true",
"draw-value-color": "control.text",
"draw-value-from-center": "false",
"draw-value-inverted": "false",
"frame-width": "1",
"handle-offset": "0, 0",
"max-value": "1",
"min-value": "0",
"mode": "use global",
"mouse-enabled": "true",
"opacity": "1",
"orientation": "horizontal",
"origin": "410, 10",
"reverse-orientation": "false",
"size": "70, 20",
"tooltip": "Pixels Per Milliseconds",
"transparent": "false",
"wants-focus": "true",
"wheel-inc-value": "0.1",
"zoom-factor": "1.5"
}
},
"CCheckBox": {
"attributes": {
"autosize-to-fit": "false",
"boxfill-color": "control.back",
"boxframe-color": "control.frame",
"checkmark-color": "control.text",
"class": "CCheckBox",
"control-tag": "Force_MessageHandling",
"default-value": "0",
"draw-crossbox": "true",
"font": "~ SystemFont",
"font-color": "control.text",
"frame-width": "1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "10, 30",
"round-rect-radius": "0",
"size": "210, 20",
"title": "Force Message Handling",
"tooltip": "Deactivate and Activate the plug-in after changing this.",
"transparent": "false",
"wants-focus": "true",
"wheel-inc-value": "0.1"
}
},
"CTextLabel": {
"attributes": {
"back-color": "~ BlackCColor",
"background-offset": "0, 0",
"class": "CTextLabel",
"default-value": "0.5",
"font": "~ NormalFontVerySmall",
"font-antialias": "true",
"font-color": "control.text",
"frame-color": "~ BlackCColor",
"frame-width": "1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "false",
"opacity": "1",
"origin": "400, 30",
"round-rect-radius": "6",
"shadow-color": "~ RedCColor",
"size": "90, 20",
"style-3D-in": "false",
"style-3D-out": "false",
"style-no-draw": "false",
"style-no-frame": "false",
"style-no-text": "false",
"style-round-rect": "false",
"style-shadow-text": "false",
"text-alignment": "center",
"text-inset": "0, 0",
"text-rotation": "0",
"text-shadow-offset": "1, 1",
"title": "Pixels per Millisecond",
"transparent": "true",
"value-precision": "2",
"wants-focus": "false",
"wheel-inc-value": "0.1"
}
},
"CParamDisplay": {
"attributes": {
"autosize": "left top ",
"back-color": "~ BlackCColor",
"background-offset": "0, 0",
"class": "CParamDisplay",
"control-tag": "FPS",
"default-value": "0",
"font": "~ NormalFont",
"font-antialias": "true",
"font-color": "control.text",
"frame-color": "~ BlackCColor",
"frame-width": "1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "270, 30",
"round-rect-radius": "6",
"shadow-color": "waveform.left",
"size": "30, 20",
"style-3D-in": "false",
"style-3D-out": "false",
"style-no-draw": "false",
"style-no-frame": "false",
"style-no-text": "false",
"style-round-rect": "false",
"style-shadow-text": "false",
"text-alignment": "center",
"text-inset": "0, 0",
"text-rotation": "0",
"text-shadow-offset": "1, 1",
"transparent": "false",
"value-precision": "2",
"wants-focus": "false",
"wheel-inc-value": "0.1"
}
},
"CTextLabel": {
"attributes": {
"back-color": "~ BlackCColor",
"background-offset": "0, 0",
"class": "CTextLabel",
"default-value": "0.5",
"font": "~ NormalFont",
"font-antialias": "true",
"font-color": "control.text",
"frame-color": "~ BlackCColor",
"frame-width": "1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "300, 30",
"round-rect-radius": "6",
"shadow-color": "waveform.left",
"size": "40, 20",
"style-3D-in": "false",
"style-3D-out": "false",
"style-no-draw": "false",
"style-no-frame": "false",
"style-no-text": "false",
"style-round-rect": "false",
"style-shadow-text": "false",
"text-alignment": "center",
"text-inset": "0, 0",
"text-rotation": "0",
"text-shadow-offset": "1, 1",
"title": "FPS",
"transparent": "true",
"value-precision": "2",
"wants-focus": "false",
"wheel-inc-value": "0.1"
}
},
"CCheckBox": {
"attributes": {
"autosize-to-fit": "false",
"boxfill-color": "control.back",
"boxframe-color": "control.frame",
"checkmark-color": "control.text",
"class": "CCheckBox",
"control-tag": "Auto_ReEnable_DataExchange",
"default-value": "0",
"draw-crossbox": "true",
"font": "~ SystemFont",
"font-color": "control.text",
"frame-width": "1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "220, 10",
"round-rect-radius": "0",
"size": "120, 20",
"title": "Auto Re-Enable",
"transparent": "false",
"wants-focus": "true",
"wheel-inc-value": "0.1"
}
}
}
}
}
}
}
@@ -0,0 +1,45 @@
#include <windows.h>
#include "../source/version.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Version
/////////////////////////////////////////////////////////////////////////////
VS_VERSION_INFO VERSIONINFO
FILEVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
PRODUCTVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040004e4"
BEGIN
VALUE "FileVersion", FULL_VERSION_STR
VALUE "ProductVersion", FULL_VERSION_STR
VALUE "OriginalFilename", stringOriginalFilename
VALUE "FileDescription", stringFileDescription
VALUE "InternalName", stringFileDescription
VALUE "ProductName", stringFileDescription
VALUE "CompanyName", stringCompanyName
VALUE "LegalCopyright", stringLegalCopyright
VALUE "LegalTrademarks", stringLegalTrademarks
//VALUE "PrivateBuild", " \0"
//VALUE "SpecialBuild", " \0"
//VALUE "Comments", " \0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x400, 1252
END
END
@@ -0,0 +1,814 @@
#if 0
//
// Generated by Microsoft (R) HLSL Shader Compiler 10.1
//
//
// Buffer Definitions:
//
// cbuffer PS_CONSTANTS
// {
//
// float4x4 scissorMat; // Offset: 0 Size: 64
// float4 scissorExt; // Offset: 64 Size: 16
// float4 scissorScale; // Offset: 80 Size: 16
// float4x4 paintMat; // Offset: 96 Size: 64
// float4 extent; // Offset: 160 Size: 16
// float4 radius; // Offset: 176 Size: 16
// float4 feather; // Offset: 192 Size: 16
// float4 innerCol; // Offset: 208 Size: 16
// float4 outerCol; // Offset: 224 Size: 16
// float4 strokeMult; // Offset: 240 Size: 16 [unused]
// int texType; // Offset: 256 Size: 4
// int type; // Offset: 260 Size: 4
//
// }
//
//
// Resource Bindings:
//
// Name Type Format Dim HLSL Bind Count
// ------------------------------ ---------- ------- ----------- -------------- ------
// g_sampler sampler NA NA s0 1
// g_texture texture float4 2d t0 1
// PS_CONSTANTS cbuffer NA NA cb0 1
//
//
//
// Input signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_Position 0 xyzw 0 POS float
// TEXCOORD 0 xy 1 NONE float xy
// TEXCOORD 1 zw 1 NONE float zw
//
//
// Output signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_TARGET 0 xyzw 0 TARGET float xyzw
//
//
// Constant buffer to DX9 shader constant mappings:
//
// Target Reg Buffer Start Reg # of Regs Data Conversion
// ---------- ------- --------- --------- ----------------------
// c0 cb0 0 3 ( FLT, FLT, FLT, FLT)
// c3 cb0 4 5 ( FLT, FLT, FLT, FLT)
// c8 cb0 10 5 ( FLT, FLT, FLT, FLT)
// c13 cb0 16 1 ( INT, INT, FLT, FLT)
//
//
// Sampler/Resource to DX9 shader sampler mappings:
//
// Target Sampler Source Sampler Source Resource
// -------------- --------------- ----------------
// s0 s0 t0
//
//
// Level9 shader bytecode:
//
ps_2_x
def c14, 0.5, 0, -1, -2
dcl t0
dcl_2d s0
mul r0.xy, t0.z, c1
mad r0.xy, c0, t0.w, r0
add r0.xy, r0, c2
abs r0.xy, r0
add r0.xy, r0, -c3
mov r1.xzw, c14
mad_sat r0.xy, r0, -c4, r1.x
mul r0.x, r0.y, r0.x
mul r0.yz, t0.z, c6.xxyw
mad r0.yz, c5.xxyw, t0.w, r0
add r0.yz, r0, c7.xxyw
rcp r2.x, c8.x
rcp r2.y, c8.y
mul r2.xy, r0.yzzw, r2
texld r3, t0, s0
texld r2, r2, s0
mul r4.xyz, r3.w, r3
add r5, r1.zzww, c13.yxxy
mul r5, r5, r5
cmp r3.xyz, -r5.y, r4, r3
cmp r3.yzw, -r5.z, r3.x, r3
mul r3, r0.x, r3
mul r3, r3, c11
cmp r3, -r5.w, -c14.z, r3
abs r0.yz, r0
mul r1.yzw, r2.w, r2.xxyz
cmp r2.xyz, -r5.y, r1.yzww, r2
cmp r2.yzw, -r5.z, r2.x, r2
mul r2, r2, c11
mul r2, r0.x, r2
cmp r2, -r5.x, r2, r3
mov r3.xy, c8
add r1.yz, r3.xxyw, -c9.x
add r0.yz, r0, -r1
max r1.yz, r0, c14.y
max r1.w, r0.y, r0.z
min r0.y, r1.w, c14.y
dp2add r0.z, r1.yzzw, r1.yzzw, c14.y
rsq r0.z, r0.z
rcp r0.z, r0.z
add r0.y, r0.z, r0.y
add r0.y, r0.y, -c9.x
mad r0.y, c10.x, r1.x, r0.y
rcp r0.z, c10.x
mul_sat r0.y, r0.z, r0.y
mov r1, c11
add r1, -r1, c12
mad r1, r0.y, r1, c11
mul r0, r0.x, r1
mul r1.x, c13.y, c13.y
cmp r0, -r1.x, r0, r2
mov oC0, r0
// approximately 53 instruction slots used (2 texture, 51 arithmetic)
ps_4_0
dcl_constantbuffer CB0[17], immediateIndexed
dcl_sampler s0, mode_default
dcl_resource_texture2d (float,float,float,float) t0
dcl_input_ps linear v1.xy
dcl_input_ps linear v1.zw
dcl_output o0.xyzw
dcl_temps 3
mul r0.xy, v1.wwww, cb0[1].xyxx
mad r0.xy, cb0[0].xyxx, v1.zzzz, r0.xyxx
add r0.xy, r0.xyxx, cb0[2].xyxx
add r0.xy, |r0.xyxx|, -cb0[4].xyxx
mad_sat r0.xy, -r0.xyxx, cb0[5].xyxx, l(0.500000, 0.500000, 0.000000, 0.000000)
mul r0.x, r0.y, r0.x
if_z cb0[16].y
mul r0.yz, v1.wwww, cb0[7].xxyx
mad r0.yz, cb0[6].xxyx, v1.zzzz, r0.yyzy
add r0.yz, r0.yyzy, cb0[8].xxyx
add r1.xy, cb0[10].xyxx, -cb0[11].xxxx
add r0.yz, |r0.yyzy|, -r1.xxyx
max r0.w, r0.z, r0.y
min r0.w, r0.w, l(0.000000)
max r0.yz, r0.yyzy, l(0.000000, 0.000000, 0.000000, 0.000000)
dp2 r0.y, r0.yzyy, r0.yzyy
sqrt r0.y, r0.y
add r0.y, r0.y, r0.w
add r0.y, r0.y, -cb0[11].x
mad r0.y, cb0[12].x, l(0.500000), r0.y
div_sat r0.y, r0.y, cb0[12].x
add r1.xyzw, -cb0[13].xyzw, cb0[14].xyzw
mad r1.xyzw, r0.yyyy, r1.xyzw, cb0[13].xyzw
mul o0.xyzw, r0.xxxx, r1.xyzw
else
ieq r0.y, cb0[16].y, l(1)
if_nz r0.y
mul r0.yz, v1.wwww, cb0[7].xxyx
mad r0.yz, cb0[6].xxyx, v1.zzzz, r0.yyzy
add r0.yz, r0.yyzy, cb0[8].xxyx
div r0.yz, r0.yyzy, cb0[10].xxyx
sample r1.xyzw, r0.yzyy, t0.xyzw, s0
ieq r0.yz, cb0[16].xxxx, l(0, 1, 2, 0)
mul r2.xyz, r1.wwww, r1.xyzx
movc r1.xyz, r0.yyyy, r2.xyzx, r1.xyzx
movc r1.yzw, r0.zzzz, r1.xxxx, r1.yyzw
mul r1.xyzw, r1.xyzw, cb0[13].xyzw
mul o0.xyzw, r0.xxxx, r1.xyzw
else
ieq r0.y, cb0[16].y, l(2)
if_nz r0.y
mov o0.xyzw, l(1.000000,1.000000,1.000000,1.000000)
else
sample r1.xyzw, v1.xyxx, t0.xyzw, s0
ieq r0.yz, cb0[16].xxxx, l(0, 1, 2, 0)
mul r2.xyz, r1.wwww, r1.xyzx
movc r1.xyz, r0.yyyy, r2.xyzx, r1.xyzx
movc r1.yzw, r0.zzzz, r1.xxxx, r1.yyzw
mul r0.xyzw, r0.xxxx, r1.xyzw
mul o0.xyzw, r0.xyzw, cb0[13].xyzw
endif
endif
endif
ret
// Approximately 54 instruction slots used
#endif
const BYTE g_D3D11PixelShader_Main[] =
{
68, 88, 66, 67, 14, 64,
81, 101, 247, 99, 217, 101,
174, 153, 127, 7, 152, 44,
133, 191, 1, 0, 0, 0,
116, 14, 0, 0, 6, 0,
0, 0, 56, 0, 0, 0,
24, 4, 0, 0, 168, 10,
0, 0, 36, 11, 0, 0,
208, 13, 0, 0, 64, 14,
0, 0, 65, 111, 110, 57,
216, 3, 0, 0, 216, 3,
0, 0, 0, 2, 255, 255,
128, 3, 0, 0, 88, 0,
0, 0, 4, 0, 40, 0,
0, 0, 88, 0, 0, 0,
88, 0, 1, 0, 36, 0,
0, 0, 88, 0, 0, 0,
0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0,
0, 0, 0, 0, 4, 0,
5, 0, 3, 0, 0, 0,
0, 0, 0, 0, 10, 0,
5, 0, 8, 0, 0, 0,
0, 0, 0, 0, 16, 0,
1, 0, 13, 0, 2, 2,
0, 0, 1, 2, 255, 255,
81, 0, 0, 5, 14, 0,
15, 160, 0, 0, 0, 63,
0, 0, 0, 0, 0, 0,
128, 191, 0, 0, 0, 192,
31, 0, 0, 2, 0, 0,
0, 128, 0, 0, 15, 176,
31, 0, 0, 2, 0, 0,
0, 144, 0, 8, 15, 160,
5, 0, 0, 3, 0, 0,
3, 128, 0, 0, 170, 176,
1, 0, 228, 160, 4, 0,
0, 4, 0, 0, 3, 128,
0, 0, 228, 160, 0, 0,
255, 176, 0, 0, 228, 128,
2, 0, 0, 3, 0, 0,
3, 128, 0, 0, 228, 128,
2, 0, 228, 160, 35, 0,
0, 2, 0, 0, 3, 128,
0, 0, 228, 128, 2, 0,
0, 3, 0, 0, 3, 128,
0, 0, 228, 128, 3, 0,
228, 161, 1, 0, 0, 2,
1, 0, 13, 128, 14, 0,
228, 160, 4, 0, 0, 4,
0, 0, 19, 128, 0, 0,
228, 128, 4, 0, 228, 161,
1, 0, 0, 128, 5, 0,
0, 3, 0, 0, 1, 128,
0, 0, 85, 128, 0, 0,
0, 128, 5, 0, 0, 3,
0, 0, 6, 128, 0, 0,
170, 176, 6, 0, 208, 160,
4, 0, 0, 4, 0, 0,
6, 128, 5, 0, 208, 160,
0, 0, 255, 176, 0, 0,
228, 128, 2, 0, 0, 3,
0, 0, 6, 128, 0, 0,
228, 128, 7, 0, 208, 160,
6, 0, 0, 2, 2, 0,
1, 128, 8, 0, 0, 160,
6, 0, 0, 2, 2, 0,
2, 128, 8, 0, 85, 160,
5, 0, 0, 3, 2, 0,
3, 128, 0, 0, 233, 128,
2, 0, 228, 128, 66, 0,
0, 3, 3, 0, 15, 128,
0, 0, 228, 176, 0, 8,
228, 160, 66, 0, 0, 3,
2, 0, 15, 128, 2, 0,
228, 128, 0, 8, 228, 160,
5, 0, 0, 3, 4, 0,
7, 128, 3, 0, 255, 128,
3, 0, 228, 128, 2, 0,
0, 3, 5, 0, 15, 128,
1, 0, 250, 128, 13, 0,
65, 160, 5, 0, 0, 3,
5, 0, 15, 128, 5, 0,
228, 128, 5, 0, 228, 128,
88, 0, 0, 4, 3, 0,
7, 128, 5, 0, 85, 129,
4, 0, 228, 128, 3, 0,
228, 128, 88, 0, 0, 4,
3, 0, 14, 128, 5, 0,
170, 129, 3, 0, 0, 128,
3, 0, 228, 128, 5, 0,
0, 3, 3, 0, 15, 128,
0, 0, 0, 128, 3, 0,
228, 128, 5, 0, 0, 3,
3, 0, 15, 128, 3, 0,
228, 128, 11, 0, 228, 160,
88, 0, 0, 4, 3, 0,
15, 128, 5, 0, 255, 129,
14, 0, 170, 161, 3, 0,
228, 128, 35, 0, 0, 2,
0, 0, 6, 128, 0, 0,
228, 128, 5, 0, 0, 3,
1, 0, 14, 128, 2, 0,
255, 128, 2, 0, 144, 128,
88, 0, 0, 4, 2, 0,
7, 128, 5, 0, 85, 129,
1, 0, 249, 128, 2, 0,
228, 128, 88, 0, 0, 4,
2, 0, 14, 128, 5, 0,
170, 129, 2, 0, 0, 128,
2, 0, 228, 128, 5, 0,
0, 3, 2, 0, 15, 128,
2, 0, 228, 128, 11, 0,
228, 160, 5, 0, 0, 3,
2, 0, 15, 128, 0, 0,
0, 128, 2, 0, 228, 128,
88, 0, 0, 4, 2, 0,
15, 128, 5, 0, 0, 129,
2, 0, 228, 128, 3, 0,
228, 128, 1, 0, 0, 2,
3, 0, 3, 128, 8, 0,
228, 160, 2, 0, 0, 3,
1, 0, 6, 128, 3, 0,
208, 128, 9, 0, 0, 161,
2, 0, 0, 3, 0, 0,
6, 128, 0, 0, 228, 128,
1, 0, 228, 129, 11, 0,
0, 3, 1, 0, 6, 128,
0, 0, 228, 128, 14, 0,
85, 160, 11, 0, 0, 3,
1, 0, 8, 128, 0, 0,
85, 128, 0, 0, 170, 128,
10, 0, 0, 3, 0, 0,
2, 128, 1, 0, 255, 128,
14, 0, 85, 160, 90, 0,
0, 4, 0, 0, 4, 128,
1, 0, 233, 128, 1, 0,
233, 128, 14, 0, 85, 160,
7, 0, 0, 2, 0, 0,
4, 128, 0, 0, 170, 128,
6, 0, 0, 2, 0, 0,
4, 128, 0, 0, 170, 128,
2, 0, 0, 3, 0, 0,
2, 128, 0, 0, 170, 128,
0, 0, 85, 128, 2, 0,
0, 3, 0, 0, 2, 128,
0, 0, 85, 128, 9, 0,
0, 161, 4, 0, 0, 4,
0, 0, 2, 128, 10, 0,
0, 160, 1, 0, 0, 128,
0, 0, 85, 128, 6, 0,
0, 2, 0, 0, 4, 128,
10, 0, 0, 160, 5, 0,
0, 3, 0, 0, 18, 128,
0, 0, 170, 128, 0, 0,
85, 128, 1, 0, 0, 2,
1, 0, 15, 128, 11, 0,
228, 160, 2, 0, 0, 3,
1, 0, 15, 128, 1, 0,
228, 129, 12, 0, 228, 160,
4, 0, 0, 4, 1, 0,
15, 128, 0, 0, 85, 128,
1, 0, 228, 128, 11, 0,
228, 160, 5, 0, 0, 3,
0, 0, 15, 128, 0, 0,
0, 128, 1, 0, 228, 128,
5, 0, 0, 3, 1, 0,
1, 128, 13, 0, 85, 160,
13, 0, 85, 160, 88, 0,
0, 4, 0, 0, 15, 128,
1, 0, 0, 129, 0, 0,
228, 128, 2, 0, 228, 128,
1, 0, 0, 2, 0, 8,
15, 128, 0, 0, 228, 128,
255, 255, 0, 0, 83, 72,
68, 82, 136, 6, 0, 0,
64, 0, 0, 0, 162, 1,
0, 0, 89, 0, 0, 4,
70, 142, 32, 0, 0, 0,
0, 0, 17, 0, 0, 0,
90, 0, 0, 3, 0, 96,
16, 0, 0, 0, 0, 0,
88, 24, 0, 4, 0, 112,
16, 0, 0, 0, 0, 0,
85, 85, 0, 0, 98, 16,
0, 3, 50, 16, 16, 0,
1, 0, 0, 0, 98, 16,
0, 3, 194, 16, 16, 0,
1, 0, 0, 0, 101, 0,
0, 3, 242, 32, 16, 0,
0, 0, 0, 0, 104, 0,
0, 2, 3, 0, 0, 0,
56, 0, 0, 8, 50, 0,
16, 0, 0, 0, 0, 0,
246, 31, 16, 0, 1, 0,
0, 0, 70, 128, 32, 0,
0, 0, 0, 0, 1, 0,
0, 0, 50, 0, 0, 10,
50, 0, 16, 0, 0, 0,
0, 0, 70, 128, 32, 0,
0, 0, 0, 0, 0, 0,
0, 0, 166, 26, 16, 0,
1, 0, 0, 0, 70, 0,
16, 0, 0, 0, 0, 0,
0, 0, 0, 8, 50, 0,
16, 0, 0, 0, 0, 0,
70, 0, 16, 0, 0, 0,
0, 0, 70, 128, 32, 0,
0, 0, 0, 0, 2, 0,
0, 0, 0, 0, 0, 10,
50, 0, 16, 0, 0, 0,
0, 0, 70, 0, 16, 128,
129, 0, 0, 0, 0, 0,
0, 0, 70, 128, 32, 128,
65, 0, 0, 0, 0, 0,
0, 0, 4, 0, 0, 0,
50, 32, 0, 14, 50, 0,
16, 0, 0, 0, 0, 0,
70, 0, 16, 128, 65, 0,
0, 0, 0, 0, 0, 0,
70, 128, 32, 0, 0, 0,
0, 0, 5, 0, 0, 0,
2, 64, 0, 0, 0, 0,
0, 63, 0, 0, 0, 63,
0, 0, 0, 0, 0, 0,
0, 0, 56, 0, 0, 7,
18, 0, 16, 0, 0, 0,
0, 0, 26, 0, 16, 0,
0, 0, 0, 0, 10, 0,
16, 0, 0, 0, 0, 0,
31, 0, 0, 4, 26, 128,
32, 0, 0, 0, 0, 0,
16, 0, 0, 0, 56, 0,
0, 8, 98, 0, 16, 0,
0, 0, 0, 0, 246, 31,
16, 0, 1, 0, 0, 0,
6, 129, 32, 0, 0, 0,
0, 0, 7, 0, 0, 0,
50, 0, 0, 10, 98, 0,
16, 0, 0, 0, 0, 0,
6, 129, 32, 0, 0, 0,
0, 0, 6, 0, 0, 0,
166, 26, 16, 0, 1, 0,
0, 0, 86, 6, 16, 0,
0, 0, 0, 0, 0, 0,
0, 8, 98, 0, 16, 0,
0, 0, 0, 0, 86, 6,
16, 0, 0, 0, 0, 0,
6, 129, 32, 0, 0, 0,
0, 0, 8, 0, 0, 0,
0, 0, 0, 10, 50, 0,
16, 0, 1, 0, 0, 0,
70, 128, 32, 0, 0, 0,
0, 0, 10, 0, 0, 0,
6, 128, 32, 128, 65, 0,
0, 0, 0, 0, 0, 0,
11, 0, 0, 0, 0, 0,
0, 9, 98, 0, 16, 0,
0, 0, 0, 0, 86, 6,
16, 128, 129, 0, 0, 0,
0, 0, 0, 0, 6, 1,
16, 128, 65, 0, 0, 0,
1, 0, 0, 0, 52, 0,
0, 7, 130, 0, 16, 0,
0, 0, 0, 0, 42, 0,
16, 0, 0, 0, 0, 0,
26, 0, 16, 0, 0, 0,
0, 0, 51, 0, 0, 7,
130, 0, 16, 0, 0, 0,
0, 0, 58, 0, 16, 0,
0, 0, 0, 0, 1, 64,
0, 0, 0, 0, 0, 0,
52, 0, 0, 10, 98, 0,
16, 0, 0, 0, 0, 0,
86, 6, 16, 0, 0, 0,
0, 0, 2, 64, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 15, 0,
0, 7, 34, 0, 16, 0,
0, 0, 0, 0, 150, 5,
16, 0, 0, 0, 0, 0,
150, 5, 16, 0, 0, 0,
0, 0, 75, 0, 0, 5,
34, 0, 16, 0, 0, 0,
0, 0, 26, 0, 16, 0,
0, 0, 0, 0, 0, 0,
0, 7, 34, 0, 16, 0,
0, 0, 0, 0, 26, 0,
16, 0, 0, 0, 0, 0,
58, 0, 16, 0, 0, 0,
0, 0, 0, 0, 0, 9,
34, 0, 16, 0, 0, 0,
0, 0, 26, 0, 16, 0,
0, 0, 0, 0, 10, 128,
32, 128, 65, 0, 0, 0,
0, 0, 0, 0, 11, 0,
0, 0, 50, 0, 0, 10,
34, 0, 16, 0, 0, 0,
0, 0, 10, 128, 32, 0,
0, 0, 0, 0, 12, 0,
0, 0, 1, 64, 0, 0,
0, 0, 0, 63, 26, 0,
16, 0, 0, 0, 0, 0,
14, 32, 0, 8, 34, 0,
16, 0, 0, 0, 0, 0,
26, 0, 16, 0, 0, 0,
0, 0, 10, 128, 32, 0,
0, 0, 0, 0, 12, 0,
0, 0, 0, 0, 0, 10,
242, 0, 16, 0, 1, 0,
0, 0, 70, 142, 32, 128,
65, 0, 0, 0, 0, 0,
0, 0, 13, 0, 0, 0,
70, 142, 32, 0, 0, 0,
0, 0, 14, 0, 0, 0,
50, 0, 0, 10, 242, 0,
16, 0, 1, 0, 0, 0,
86, 5, 16, 0, 0, 0,
0, 0, 70, 14, 16, 0,
1, 0, 0, 0, 70, 142,
32, 0, 0, 0, 0, 0,
13, 0, 0, 0, 56, 0,
0, 7, 242, 32, 16, 0,
0, 0, 0, 0, 6, 0,
16, 0, 0, 0, 0, 0,
70, 14, 16, 0, 1, 0,
0, 0, 18, 0, 0, 1,
32, 0, 0, 8, 34, 0,
16, 0, 0, 0, 0, 0,
26, 128, 32, 0, 0, 0,
0, 0, 16, 0, 0, 0,
1, 64, 0, 0, 1, 0,
0, 0, 31, 0, 4, 3,
26, 0, 16, 0, 0, 0,
0, 0, 56, 0, 0, 8,
98, 0, 16, 0, 0, 0,
0, 0, 246, 31, 16, 0,
1, 0, 0, 0, 6, 129,
32, 0, 0, 0, 0, 0,
7, 0, 0, 0, 50, 0,
0, 10, 98, 0, 16, 0,
0, 0, 0, 0, 6, 129,
32, 0, 0, 0, 0, 0,
6, 0, 0, 0, 166, 26,
16, 0, 1, 0, 0, 0,
86, 6, 16, 0, 0, 0,
0, 0, 0, 0, 0, 8,
98, 0, 16, 0, 0, 0,
0, 0, 86, 6, 16, 0,
0, 0, 0, 0, 6, 129,
32, 0, 0, 0, 0, 0,
8, 0, 0, 0, 14, 0,
0, 8, 98, 0, 16, 0,
0, 0, 0, 0, 86, 6,
16, 0, 0, 0, 0, 0,
6, 129, 32, 0, 0, 0,
0, 0, 10, 0, 0, 0,
69, 0, 0, 9, 242, 0,
16, 0, 1, 0, 0, 0,
150, 5, 16, 0, 0, 0,
0, 0, 70, 126, 16, 0,
0, 0, 0, 0, 0, 96,
16, 0, 0, 0, 0, 0,
32, 0, 0, 11, 98, 0,
16, 0, 0, 0, 0, 0,
6, 128, 32, 0, 0, 0,
0, 0, 16, 0, 0, 0,
2, 64, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0,
2, 0, 0, 0, 0, 0,
0, 0, 56, 0, 0, 7,
114, 0, 16, 0, 2, 0,
0, 0, 246, 15, 16, 0,
1, 0, 0, 0, 70, 2,
16, 0, 1, 0, 0, 0,
55, 0, 0, 9, 114, 0,
16, 0, 1, 0, 0, 0,
86, 5, 16, 0, 0, 0,
0, 0, 70, 2, 16, 0,
2, 0, 0, 0, 70, 2,
16, 0, 1, 0, 0, 0,
55, 0, 0, 9, 226, 0,
16, 0, 1, 0, 0, 0,
166, 10, 16, 0, 0, 0,
0, 0, 6, 0, 16, 0,
1, 0, 0, 0, 86, 14,
16, 0, 1, 0, 0, 0,
56, 0, 0, 8, 242, 0,
16, 0, 1, 0, 0, 0,
70, 14, 16, 0, 1, 0,
0, 0, 70, 142, 32, 0,
0, 0, 0, 0, 13, 0,
0, 0, 56, 0, 0, 7,
242, 32, 16, 0, 0, 0,
0, 0, 6, 0, 16, 0,
0, 0, 0, 0, 70, 14,
16, 0, 1, 0, 0, 0,
18, 0, 0, 1, 32, 0,
0, 8, 34, 0, 16, 0,
0, 0, 0, 0, 26, 128,
32, 0, 0, 0, 0, 0,
16, 0, 0, 0, 1, 64,
0, 0, 2, 0, 0, 0,
31, 0, 4, 3, 26, 0,
16, 0, 0, 0, 0, 0,
54, 0, 0, 8, 242, 32,
16, 0, 0, 0, 0, 0,
2, 64, 0, 0, 0, 0,
128, 63, 0, 0, 128, 63,
0, 0, 128, 63, 0, 0,
128, 63, 18, 0, 0, 1,
69, 0, 0, 9, 242, 0,
16, 0, 1, 0, 0, 0,
70, 16, 16, 0, 1, 0,
0, 0, 70, 126, 16, 0,
0, 0, 0, 0, 0, 96,
16, 0, 0, 0, 0, 0,
32, 0, 0, 11, 98, 0,
16, 0, 0, 0, 0, 0,
6, 128, 32, 0, 0, 0,
0, 0, 16, 0, 0, 0,
2, 64, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0,
2, 0, 0, 0, 0, 0,
0, 0, 56, 0, 0, 7,
114, 0, 16, 0, 2, 0,
0, 0, 246, 15, 16, 0,
1, 0, 0, 0, 70, 2,
16, 0, 1, 0, 0, 0,
55, 0, 0, 9, 114, 0,
16, 0, 1, 0, 0, 0,
86, 5, 16, 0, 0, 0,
0, 0, 70, 2, 16, 0,
2, 0, 0, 0, 70, 2,
16, 0, 1, 0, 0, 0,
55, 0, 0, 9, 226, 0,
16, 0, 1, 0, 0, 0,
166, 10, 16, 0, 0, 0,
0, 0, 6, 0, 16, 0,
1, 0, 0, 0, 86, 14,
16, 0, 1, 0, 0, 0,
56, 0, 0, 7, 242, 0,
16, 0, 0, 0, 0, 0,
6, 0, 16, 0, 0, 0,
0, 0, 70, 14, 16, 0,
1, 0, 0, 0, 56, 0,
0, 8, 242, 32, 16, 0,
0, 0, 0, 0, 70, 14,
16, 0, 0, 0, 0, 0,
70, 142, 32, 0, 0, 0,
0, 0, 13, 0, 0, 0,
21, 0, 0, 1, 21, 0,
0, 1, 21, 0, 0, 1,
62, 0, 0, 1, 83, 84,
65, 84, 116, 0, 0, 0,
54, 0, 0, 0, 3, 0,
0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 33, 0,
0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 5, 0,
0, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0,
0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 82, 68, 69, 70,
164, 2, 0, 0, 1, 0,
0, 0, 160, 0, 0, 0,
3, 0, 0, 0, 28, 0,
0, 0, 0, 4, 255, 255,
0, 1, 0, 0, 121, 2,
0, 0, 124, 0, 0, 0,
3, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0,
1, 0, 0, 0, 134, 0,
0, 0, 2, 0, 0, 0,
5, 0, 0, 0, 4, 0,
0, 0, 255, 255, 255, 255,
0, 0, 0, 0, 1, 0,
0, 0, 13, 0, 0, 0,
144, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0,
0, 0, 103, 95, 115, 97,
109, 112, 108, 101, 114, 0,
103, 95, 116, 101, 120, 116,
117, 114, 101, 0, 80, 83,
95, 67, 79, 78, 83, 84,
65, 78, 84, 83, 0, 171,
171, 171, 144, 0, 0, 0,
12, 0, 0, 0, 184, 0,
0, 0, 16, 1, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 216, 1, 0, 0,
0, 0, 0, 0, 64, 0,
0, 0, 2, 0, 0, 0,
228, 1, 0, 0, 0, 0,
0, 0, 244, 1, 0, 0,
64, 0, 0, 0, 16, 0,
0, 0, 2, 0, 0, 0,
0, 2, 0, 0, 0, 0,
0, 0, 16, 2, 0, 0,
80, 0, 0, 0, 16, 0,
0, 0, 2, 0, 0, 0,
0, 2, 0, 0, 0, 0,
0, 0, 29, 2, 0, 0,
96, 0, 0, 0, 64, 0,
0, 0, 2, 0, 0, 0,
228, 1, 0, 0, 0, 0,
0, 0, 38, 2, 0, 0,
160, 0, 0, 0, 16, 0,
0, 0, 2, 0, 0, 0,
0, 2, 0, 0, 0, 0,
0, 0, 45, 2, 0, 0,
176, 0, 0, 0, 16, 0,
0, 0, 2, 0, 0, 0,
0, 2, 0, 0, 0, 0,
0, 0, 52, 2, 0, 0,
192, 0, 0, 0, 16, 0,
0, 0, 2, 0, 0, 0,
0, 2, 0, 0, 0, 0,
0, 0, 60, 2, 0, 0,
208, 0, 0, 0, 16, 0,
0, 0, 2, 0, 0, 0,
0, 2, 0, 0, 0, 0,
0, 0, 69, 2, 0, 0,
224, 0, 0, 0, 16, 0,
0, 0, 2, 0, 0, 0,
0, 2, 0, 0, 0, 0,
0, 0, 78, 2, 0, 0,
240, 0, 0, 0, 16, 0,
0, 0, 0, 0, 0, 0,
0, 2, 0, 0, 0, 0,
0, 0, 89, 2, 0, 0,
0, 1, 0, 0, 4, 0,
0, 0, 2, 0, 0, 0,
100, 2, 0, 0, 0, 0,
0, 0, 116, 2, 0, 0,
4, 1, 0, 0, 4, 0,
0, 0, 2, 0, 0, 0,
100, 2, 0, 0, 0, 0,
0, 0, 115, 99, 105, 115,
115, 111, 114, 77, 97, 116,
0, 171, 3, 0, 3, 0,
4, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0,
115, 99, 105, 115, 115, 111,
114, 69, 120, 116, 0, 171,
1, 0, 3, 0, 1, 0,
4, 0, 0, 0, 0, 0,
0, 0, 0, 0, 115, 99,
105, 115, 115, 111, 114, 83,
99, 97, 108, 101, 0, 112,
97, 105, 110, 116, 77, 97,
116, 0, 101, 120, 116, 101,
110, 116, 0, 114, 97, 100,
105, 117, 115, 0, 102, 101,
97, 116, 104, 101, 114, 0,
105, 110, 110, 101, 114, 67,
111, 108, 0, 111, 117, 116,
101, 114, 67, 111, 108, 0,
115, 116, 114, 111, 107, 101,
77, 117, 108, 116, 0, 116,
101, 120, 84, 121, 112, 101,
0, 171, 171, 171, 0, 0,
2, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0,
0, 0, 116, 121, 112, 101,
0, 77, 105, 99, 114, 111,
115, 111, 102, 116, 32, 40,
82, 41, 32, 72, 76, 83,
76, 32, 83, 104, 97, 100,
101, 114, 32, 67, 111, 109,
112, 105, 108, 101, 114, 32,
49, 48, 46, 49, 0, 171,
171, 171, 73, 83, 71, 78,
104, 0, 0, 0, 3, 0,
0, 0, 8, 0, 0, 0,
80, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0,
3, 0, 0, 0, 0, 0,
0, 0, 15, 0, 0, 0,
92, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 1, 0,
0, 0, 3, 3, 0, 0,
92, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 1, 0,
0, 0, 12, 12, 0, 0,
83, 86, 95, 80, 111, 115,
105, 116, 105, 111, 110, 0,
84, 69, 88, 67, 79, 79,
82, 68, 0, 171, 171, 171,
79, 83, 71, 78, 44, 0,
0, 0, 1, 0, 0, 0,
8, 0, 0, 0, 32, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 0, 0, 0, 0,
15, 0, 0, 0, 83, 86,
95, 84, 65, 82, 71, 69,
84, 0, 171, 171
};
@@ -0,0 +1,920 @@
#if 0
//
// Generated by Microsoft (R) HLSL Shader Compiler 10.1
//
//
// Buffer Definitions:
//
// cbuffer PS_CONSTANTS
// {
//
// float4x4 scissorMat; // Offset: 0 Size: 64
// float4 scissorExt; // Offset: 64 Size: 16
// float4 scissorScale; // Offset: 80 Size: 16
// float4x4 paintMat; // Offset: 96 Size: 64
// float4 extent; // Offset: 160 Size: 16
// float4 radius; // Offset: 176 Size: 16
// float4 feather; // Offset: 192 Size: 16
// float4 innerCol; // Offset: 208 Size: 16
// float4 outerCol; // Offset: 224 Size: 16
// float4 strokeMult; // Offset: 240 Size: 16
// int texType; // Offset: 256 Size: 4
// int type; // Offset: 260 Size: 4
//
// }
//
//
// Resource Bindings:
//
// Name Type Format Dim HLSL Bind Count
// ------------------------------ ---------- ------- ----------- -------------- ------
// g_sampler sampler NA NA s0 1
// g_texture texture float4 2d t0 1
// PS_CONSTANTS cbuffer NA NA cb0 1
//
//
//
// Input signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_Position 0 xyzw 0 POS float
// TEXCOORD 0 xy 1 NONE float xy
// TEXCOORD 1 zw 1 NONE float zw
//
//
// Output signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_TARGET 0 xyzw 0 TARGET float xyzw
//
//
// Constant buffer to DX9 shader constant mappings:
//
// Target Reg Buffer Start Reg # of Regs Data Conversion
// ---------- ------- --------- --------- ----------------------
// c0 cb0 0 3 ( FLT, FLT, FLT, FLT)
// c3 cb0 4 5 ( FLT, FLT, FLT, FLT)
// c8 cb0 10 6 ( FLT, FLT, FLT, FLT)
// c14 cb0 16 1 ( INT, INT, FLT, FLT)
//
//
// Sampler/Resource to DX9 shader sampler mappings:
//
// Target Sampler Source Sampler Source Resource
// -------------- --------------- ----------------
// s0 s0 t0
//
//
// Level9 shader bytecode:
//
ps_2_x
def c15, 0.5, 0, 0, 0
def c16, 2, -1, 1, -0
dcl t0
dcl_2d s0
mad r0.w, t0.x, c16.x, c16.y
abs r0.x, r0.w
add r0.x, -r0.x, c16.z
mul r0.x, r0.x, c13.x
min r1.w, r0.x, c16.z
min r0.x, t0.y, c16.z
mad r0.y, r1.w, r0.x, -c13.y
mul r0.x, r0.x, r1.w
cmp r1, r0.y, c16.w, c16.y
texkill r1
mul r0.yz, t0.z, c1.xxyw
mad r0.yz, c0.xxyw, t0.w, r0
add r0.yz, r0, c2.xxyw
abs r0.yz, r0
add r0.yz, r0, -c3.xxyw
mov r0.w, c15.x
mad_sat r0.yz, r0, -c4.xxyw, r0.w
mul r0.y, r0.z, r0.y
mul r0.z, c14.y, c14.y
mul r1.xy, t0.z, c6
mad r1.xy, c5, t0.w, r1
add r1.xy, r1, c7
mov r2.xy, c8
add r1.zw, r2.xyxy, -c9.x
abs r2.xy, r1
add r1.zw, -r1, r2.xyxy
max r2.xy, r1.zwzw, -c16.w
dp2add r2.x, r2, r2, -c16.w
rsq r2.x, r2.x
rcp r2.x, r2.x
max r2.y, r1.z, r1.w
min r1.z, r2.y, -c16.w
add r1.z, r2.x, r1.z
add r1.z, r1.z, -c9.x
mad r0.w, c10.x, r0.w, r1.z
rcp r1.z, c10.x
mul_sat r0.w, r0.w, r1.z
mul r0.x, r0.y, r0.x
rcp r2.x, c8.x
rcp r2.y, c8.y
mul r1.xy, r1, r2
mov r2, c11
add r2, -r2, c12
mad r2, r0.w, r2, c11
mul r2, r0.x, r2
mov r3.xz, c16
add r3, -r3.zzxx, c14.yxxy
mul r3, r3, r3
texld r4, t0, s0
texld r1, r1, s0
mul r5.xyz, r1.w, r1
cmp r1.xyz, -r3.y, r5, r1
cmp r1.yzw, -r3.z, r1.x, r1
mul r1, r1, c11
mul r1, r0.x, r1
mul r5.xyz, r4.w, r4
cmp r4.xyz, -r3.y, r5, r4
cmp r4.yzw, -r3.z, r4.x, r4
mul r4, r0.y, r4
mul r4, r4, c11
cmp r4, -r3.w, c16.z, r4
cmp r1, -r3.x, r1, r4
cmp r0, -r0.z, r2, r1
mov oC0, r0
// approximately 65 instruction slots used (2 texture, 63 arithmetic)
ps_4_0
dcl_constantbuffer CB0[17], immediateIndexed
dcl_sampler s0, mode_default
dcl_resource_texture2d (float,float,float,float) t0
dcl_input_ps linear v1.xy
dcl_input_ps linear v1.zw
dcl_output o0.xyzw
dcl_temps 3
mad r0.x, v1.x, l(2.000000), l(-1.000000)
add r0.x, -|r0.x|, l(1.000000)
mul r0.x, r0.x, cb0[15].x
min r0.x, r0.x, l(1.000000)
min r0.y, v1.y, l(1.000000)
mul r0.x, r0.y, r0.x
lt r0.y, r0.x, cb0[15].y
discard_nz r0.y
mul r0.yz, v1.wwww, cb0[1].xxyx
mad r0.yz, cb0[0].xxyx, v1.zzzz, r0.yyzy
add r0.yz, r0.yyzy, cb0[2].xxyx
add r0.yz, |r0.yyzy|, -cb0[4].xxyx
mad_sat r0.yz, -r0.yyzy, cb0[5].xxyx, l(0.000000, 0.500000, 0.500000, 0.000000)
mul r0.y, r0.z, r0.y
if_z cb0[16].y
mul r0.zw, v1.wwww, cb0[7].xxxy
mad r0.zw, cb0[6].xxxy, v1.zzzz, r0.zzzw
add r0.zw, r0.zzzw, cb0[8].xxxy
add r1.xy, cb0[10].xyxx, -cb0[11].xxxx
add r0.zw, |r0.zzzw|, -r1.xxxy
max r1.x, r0.w, r0.z
min r1.x, r1.x, l(0.000000)
max r0.zw, r0.zzzw, l(0.000000, 0.000000, 0.000000, 0.000000)
dp2 r0.z, r0.zwzz, r0.zwzz
sqrt r0.z, r0.z
add r0.z, r0.z, r1.x
add r0.z, r0.z, -cb0[11].x
mad r0.z, cb0[12].x, l(0.500000), r0.z
div_sat r0.z, r0.z, cb0[12].x
add r1.xyzw, -cb0[13].xyzw, cb0[14].xyzw
mad r1.xyzw, r0.zzzz, r1.xyzw, cb0[13].xyzw
mul r0.z, r0.y, r0.x
mul o0.xyzw, r0.zzzz, r1.xyzw
else
ieq r0.z, cb0[16].y, l(1)
if_nz r0.z
mul r0.zw, v1.wwww, cb0[7].xxxy
mad r0.zw, cb0[6].xxxy, v1.zzzz, r0.zzzw
add r0.zw, r0.zzzw, cb0[8].xxxy
div r0.zw, r0.zzzw, cb0[10].xxxy
sample r1.xyzw, r0.zwzz, t0.xyzw, s0
ieq r0.zw, cb0[16].xxxx, l(0, 0, 1, 2)
mul r2.xyz, r1.wwww, r1.xyzx
movc r1.xyz, r0.zzzz, r2.xyzx, r1.xyzx
movc r1.yzw, r0.wwww, r1.xxxx, r1.yyzw
mul r1.xyzw, r1.xyzw, cb0[13].xyzw
mul r0.x, r0.y, r0.x
mul o0.xyzw, r0.xxxx, r1.xyzw
else
ieq r0.x, cb0[16].y, l(2)
if_nz r0.x
mov o0.xyzw, l(1.000000,1.000000,1.000000,1.000000)
else
sample r1.xyzw, v1.xyxx, t0.xyzw, s0
ieq r0.xz, cb0[16].xxxx, l(1, 0, 2, 0)
mul r2.xyz, r1.wwww, r1.xyzx
movc r1.xyz, r0.xxxx, r2.xyzx, r1.xyzx
movc r1.yzw, r0.zzzz, r1.xxxx, r1.yyzw
mul r0.xyzw, r0.yyyy, r1.xyzw
mul o0.xyzw, r0.xyzw, cb0[13].xyzw
endif
endif
endif
ret
// Approximately 64 instruction slots used
#endif
const BYTE g_D3D11PixelShaderAA_Main[] =
{
68, 88, 66, 67, 124, 154,
102, 100, 166, 192, 106, 130,
175, 56, 140, 93, 110, 82,
184, 123, 1, 0, 0, 0,
100, 16, 0, 0, 6, 0,
0, 0, 56, 0, 0, 0,
236, 4, 0, 0, 152, 12,
0, 0, 20, 13, 0, 0,
192, 15, 0, 0, 48, 16,
0, 0, 65, 111, 110, 57,
172, 4, 0, 0, 172, 4,
0, 0, 0, 2, 255, 255,
84, 4, 0, 0, 88, 0,
0, 0, 4, 0, 40, 0,
0, 0, 88, 0, 0, 0,
88, 0, 1, 0, 36, 0,
0, 0, 88, 0, 0, 0,
0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0,
0, 0, 0, 0, 4, 0,
5, 0, 3, 0, 0, 0,
0, 0, 0, 0, 10, 0,
6, 0, 8, 0, 0, 0,
0, 0, 0, 0, 16, 0,
1, 0, 14, 0, 2, 2,
0, 0, 1, 2, 255, 255,
81, 0, 0, 5, 15, 0,
15, 160, 0, 0, 0, 63,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
81, 0, 0, 5, 16, 0,
15, 160, 0, 0, 0, 64,
0, 0, 128, 191, 0, 0,
128, 63, 0, 0, 0, 128,
31, 0, 0, 2, 0, 0,
0, 128, 0, 0, 15, 176,
31, 0, 0, 2, 0, 0,
0, 144, 0, 8, 15, 160,
4, 0, 0, 4, 0, 0,
8, 128, 0, 0, 0, 176,
16, 0, 0, 160, 16, 0,
85, 160, 35, 0, 0, 2,
0, 0, 1, 128, 0, 0,
255, 128, 2, 0, 0, 3,
0, 0, 1, 128, 0, 0,
0, 129, 16, 0, 170, 160,
5, 0, 0, 3, 0, 0,
1, 128, 0, 0, 0, 128,
13, 0, 0, 160, 10, 0,
0, 3, 1, 0, 8, 128,
0, 0, 0, 128, 16, 0,
170, 160, 10, 0, 0, 3,
0, 0, 1, 128, 0, 0,
85, 176, 16, 0, 170, 160,
4, 0, 0, 4, 0, 0,
2, 128, 1, 0, 255, 128,
0, 0, 0, 128, 13, 0,
85, 161, 5, 0, 0, 3,
0, 0, 1, 128, 0, 0,
0, 128, 1, 0, 255, 128,
88, 0, 0, 4, 1, 0,
15, 128, 0, 0, 85, 128,
16, 0, 255, 160, 16, 0,
85, 160, 65, 0, 0, 1,
1, 0, 15, 128, 5, 0,
0, 3, 0, 0, 6, 128,
0, 0, 170, 176, 1, 0,
208, 160, 4, 0, 0, 4,
0, 0, 6, 128, 0, 0,
208, 160, 0, 0, 255, 176,
0, 0, 228, 128, 2, 0,
0, 3, 0, 0, 6, 128,
0, 0, 228, 128, 2, 0,
208, 160, 35, 0, 0, 2,
0, 0, 6, 128, 0, 0,
228, 128, 2, 0, 0, 3,
0, 0, 6, 128, 0, 0,
228, 128, 3, 0, 208, 161,
1, 0, 0, 2, 0, 0,
8, 128, 15, 0, 0, 160,
4, 0, 0, 4, 0, 0,
22, 128, 0, 0, 228, 128,
4, 0, 208, 161, 0, 0,
255, 128, 5, 0, 0, 3,
0, 0, 2, 128, 0, 0,
170, 128, 0, 0, 85, 128,
5, 0, 0, 3, 0, 0,
4, 128, 14, 0, 85, 160,
14, 0, 85, 160, 5, 0,
0, 3, 1, 0, 3, 128,
0, 0, 170, 176, 6, 0,
228, 160, 4, 0, 0, 4,
1, 0, 3, 128, 5, 0,
228, 160, 0, 0, 255, 176,
1, 0, 228, 128, 2, 0,
0, 3, 1, 0, 3, 128,
1, 0, 228, 128, 7, 0,
228, 160, 1, 0, 0, 2,
2, 0, 3, 128, 8, 0,
228, 160, 2, 0, 0, 3,
1, 0, 12, 128, 2, 0,
68, 128, 9, 0, 0, 161,
35, 0, 0, 2, 2, 0,
3, 128, 1, 0, 228, 128,
2, 0, 0, 3, 1, 0,
12, 128, 1, 0, 228, 129,
2, 0, 68, 128, 11, 0,
0, 3, 2, 0, 3, 128,
1, 0, 238, 128, 16, 0,
255, 161, 90, 0, 0, 4,
2, 0, 1, 128, 2, 0,
228, 128, 2, 0, 228, 128,
16, 0, 255, 161, 7, 0,
0, 2, 2, 0, 1, 128,
2, 0, 0, 128, 6, 0,
0, 2, 2, 0, 1, 128,
2, 0, 0, 128, 11, 0,
0, 3, 2, 0, 2, 128,
1, 0, 170, 128, 1, 0,
255, 128, 10, 0, 0, 3,
1, 0, 4, 128, 2, 0,
85, 128, 16, 0, 255, 161,
2, 0, 0, 3, 1, 0,
4, 128, 2, 0, 0, 128,
1, 0, 170, 128, 2, 0,
0, 3, 1, 0, 4, 128,
1, 0, 170, 128, 9, 0,
0, 161, 4, 0, 0, 4,
0, 0, 8, 128, 10, 0,
0, 160, 0, 0, 255, 128,
1, 0, 170, 128, 6, 0,
0, 2, 1, 0, 4, 128,
10, 0, 0, 160, 5, 0,
0, 3, 0, 0, 24, 128,
0, 0, 255, 128, 1, 0,
170, 128, 5, 0, 0, 3,
0, 0, 1, 128, 0, 0,
85, 128, 0, 0, 0, 128,
6, 0, 0, 2, 2, 0,
1, 128, 8, 0, 0, 160,
6, 0, 0, 2, 2, 0,
2, 128, 8, 0, 85, 160,
5, 0, 0, 3, 1, 0,
3, 128, 1, 0, 228, 128,
2, 0, 228, 128, 1, 0,
0, 2, 2, 0, 15, 128,
11, 0, 228, 160, 2, 0,
0, 3, 2, 0, 15, 128,
2, 0, 228, 129, 12, 0,
228, 160, 4, 0, 0, 4,
2, 0, 15, 128, 0, 0,
255, 128, 2, 0, 228, 128,
11, 0, 228, 160, 5, 0,
0, 3, 2, 0, 15, 128,
0, 0, 0, 128, 2, 0,
228, 128, 1, 0, 0, 2,
3, 0, 5, 128, 16, 0,
228, 160, 2, 0, 0, 3,
3, 0, 15, 128, 3, 0,
10, 129, 14, 0, 65, 160,
5, 0, 0, 3, 3, 0,
15, 128, 3, 0, 228, 128,
3, 0, 228, 128, 66, 0,
0, 3, 4, 0, 15, 128,
0, 0, 228, 176, 0, 8,
228, 160, 66, 0, 0, 3,
1, 0, 15, 128, 1, 0,
228, 128, 0, 8, 228, 160,
5, 0, 0, 3, 5, 0,
7, 128, 1, 0, 255, 128,
1, 0, 228, 128, 88, 0,
0, 4, 1, 0, 7, 128,
3, 0, 85, 129, 5, 0,
228, 128, 1, 0, 228, 128,
88, 0, 0, 4, 1, 0,
14, 128, 3, 0, 170, 129,
1, 0, 0, 128, 1, 0,
228, 128, 5, 0, 0, 3,
1, 0, 15, 128, 1, 0,
228, 128, 11, 0, 228, 160,
5, 0, 0, 3, 1, 0,
15, 128, 0, 0, 0, 128,
1, 0, 228, 128, 5, 0,
0, 3, 5, 0, 7, 128,
4, 0, 255, 128, 4, 0,
228, 128, 88, 0, 0, 4,
4, 0, 7, 128, 3, 0,
85, 129, 5, 0, 228, 128,
4, 0, 228, 128, 88, 0,
0, 4, 4, 0, 14, 128,
3, 0, 170, 129, 4, 0,
0, 128, 4, 0, 228, 128,
5, 0, 0, 3, 4, 0,
15, 128, 0, 0, 85, 128,
4, 0, 228, 128, 5, 0,
0, 3, 4, 0, 15, 128,
4, 0, 228, 128, 11, 0,
228, 160, 88, 0, 0, 4,
4, 0, 15, 128, 3, 0,
255, 129, 16, 0, 170, 160,
4, 0, 228, 128, 88, 0,
0, 4, 1, 0, 15, 128,
3, 0, 0, 129, 1, 0,
228, 128, 4, 0, 228, 128,
88, 0, 0, 4, 0, 0,
15, 128, 0, 0, 170, 129,
2, 0, 228, 128, 1, 0,
228, 128, 1, 0, 0, 2,
0, 8, 15, 128, 0, 0,
228, 128, 255, 255, 0, 0,
83, 72, 68, 82, 164, 7,
0, 0, 64, 0, 0, 0,
233, 1, 0, 0, 89, 0,
0, 4, 70, 142, 32, 0,
0, 0, 0, 0, 17, 0,
0, 0, 90, 0, 0, 3,
0, 96, 16, 0, 0, 0,
0, 0, 88, 24, 0, 4,
0, 112, 16, 0, 0, 0,
0, 0, 85, 85, 0, 0,
98, 16, 0, 3, 50, 16,
16, 0, 1, 0, 0, 0,
98, 16, 0, 3, 194, 16,
16, 0, 1, 0, 0, 0,
101, 0, 0, 3, 242, 32,
16, 0, 0, 0, 0, 0,
104, 0, 0, 2, 3, 0,
0, 0, 50, 0, 0, 9,
18, 0, 16, 0, 0, 0,
0, 0, 10, 16, 16, 0,
1, 0, 0, 0, 1, 64,
0, 0, 0, 0, 0, 64,
1, 64, 0, 0, 0, 0,
128, 191, 0, 0, 0, 8,
18, 0, 16, 0, 0, 0,
0, 0, 10, 0, 16, 128,
193, 0, 0, 0, 0, 0,
0, 0, 1, 64, 0, 0,
0, 0, 128, 63, 56, 0,
0, 8, 18, 0, 16, 0,
0, 0, 0, 0, 10, 0,
16, 0, 0, 0, 0, 0,
10, 128, 32, 0, 0, 0,
0, 0, 15, 0, 0, 0,
51, 0, 0, 7, 18, 0,
16, 0, 0, 0, 0, 0,
10, 0, 16, 0, 0, 0,
0, 0, 1, 64, 0, 0,
0, 0, 128, 63, 51, 0,
0, 7, 34, 0, 16, 0,
0, 0, 0, 0, 26, 16,
16, 0, 1, 0, 0, 0,
1, 64, 0, 0, 0, 0,
128, 63, 56, 0, 0, 7,
18, 0, 16, 0, 0, 0,
0, 0, 26, 0, 16, 0,
0, 0, 0, 0, 10, 0,
16, 0, 0, 0, 0, 0,
49, 0, 0, 8, 34, 0,
16, 0, 0, 0, 0, 0,
10, 0, 16, 0, 0, 0,
0, 0, 26, 128, 32, 0,
0, 0, 0, 0, 15, 0,
0, 0, 13, 0, 4, 3,
26, 0, 16, 0, 0, 0,
0, 0, 56, 0, 0, 8,
98, 0, 16, 0, 0, 0,
0, 0, 246, 31, 16, 0,
1, 0, 0, 0, 6, 129,
32, 0, 0, 0, 0, 0,
1, 0, 0, 0, 50, 0,
0, 10, 98, 0, 16, 0,
0, 0, 0, 0, 6, 129,
32, 0, 0, 0, 0, 0,
0, 0, 0, 0, 166, 26,
16, 0, 1, 0, 0, 0,
86, 6, 16, 0, 0, 0,
0, 0, 0, 0, 0, 8,
98, 0, 16, 0, 0, 0,
0, 0, 86, 6, 16, 0,
0, 0, 0, 0, 6, 129,
32, 0, 0, 0, 0, 0,
2, 0, 0, 0, 0, 0,
0, 10, 98, 0, 16, 0,
0, 0, 0, 0, 86, 6,
16, 128, 129, 0, 0, 0,
0, 0, 0, 0, 6, 129,
32, 128, 65, 0, 0, 0,
0, 0, 0, 0, 4, 0,
0, 0, 50, 32, 0, 14,
98, 0, 16, 0, 0, 0,
0, 0, 86, 6, 16, 128,
65, 0, 0, 0, 0, 0,
0, 0, 6, 129, 32, 0,
0, 0, 0, 0, 5, 0,
0, 0, 2, 64, 0, 0,
0, 0, 0, 0, 0, 0,
0, 63, 0, 0, 0, 63,
0, 0, 0, 0, 56, 0,
0, 7, 34, 0, 16, 0,
0, 0, 0, 0, 42, 0,
16, 0, 0, 0, 0, 0,
26, 0, 16, 0, 0, 0,
0, 0, 31, 0, 0, 4,
26, 128, 32, 0, 0, 0,
0, 0, 16, 0, 0, 0,
56, 0, 0, 8, 194, 0,
16, 0, 0, 0, 0, 0,
246, 31, 16, 0, 1, 0,
0, 0, 6, 132, 32, 0,
0, 0, 0, 0, 7, 0,
0, 0, 50, 0, 0, 10,
194, 0, 16, 0, 0, 0,
0, 0, 6, 132, 32, 0,
0, 0, 0, 0, 6, 0,
0, 0, 166, 26, 16, 0,
1, 0, 0, 0, 166, 14,
16, 0, 0, 0, 0, 0,
0, 0, 0, 8, 194, 0,
16, 0, 0, 0, 0, 0,
166, 14, 16, 0, 0, 0,
0, 0, 6, 132, 32, 0,
0, 0, 0, 0, 8, 0,
0, 0, 0, 0, 0, 10,
50, 0, 16, 0, 1, 0,
0, 0, 70, 128, 32, 0,
0, 0, 0, 0, 10, 0,
0, 0, 6, 128, 32, 128,
65, 0, 0, 0, 0, 0,
0, 0, 11, 0, 0, 0,
0, 0, 0, 9, 194, 0,
16, 0, 0, 0, 0, 0,
166, 14, 16, 128, 129, 0,
0, 0, 0, 0, 0, 0,
6, 4, 16, 128, 65, 0,
0, 0, 1, 0, 0, 0,
52, 0, 0, 7, 18, 0,
16, 0, 1, 0, 0, 0,
58, 0, 16, 0, 0, 0,
0, 0, 42, 0, 16, 0,
0, 0, 0, 0, 51, 0,
0, 7, 18, 0, 16, 0,
1, 0, 0, 0, 10, 0,
16, 0, 1, 0, 0, 0,
1, 64, 0, 0, 0, 0,
0, 0, 52, 0, 0, 10,
194, 0, 16, 0, 0, 0,
0, 0, 166, 14, 16, 0,
0, 0, 0, 0, 2, 64,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
15, 0, 0, 7, 66, 0,
16, 0, 0, 0, 0, 0,
230, 10, 16, 0, 0, 0,
0, 0, 230, 10, 16, 0,
0, 0, 0, 0, 75, 0,
0, 5, 66, 0, 16, 0,
0, 0, 0, 0, 42, 0,
16, 0, 0, 0, 0, 0,
0, 0, 0, 7, 66, 0,
16, 0, 0, 0, 0, 0,
42, 0, 16, 0, 0, 0,
0, 0, 10, 0, 16, 0,
1, 0, 0, 0, 0, 0,
0, 9, 66, 0, 16, 0,
0, 0, 0, 0, 42, 0,
16, 0, 0, 0, 0, 0,
10, 128, 32, 128, 65, 0,
0, 0, 0, 0, 0, 0,
11, 0, 0, 0, 50, 0,
0, 10, 66, 0, 16, 0,
0, 0, 0, 0, 10, 128,
32, 0, 0, 0, 0, 0,
12, 0, 0, 0, 1, 64,
0, 0, 0, 0, 0, 63,
42, 0, 16, 0, 0, 0,
0, 0, 14, 32, 0, 8,
66, 0, 16, 0, 0, 0,
0, 0, 42, 0, 16, 0,
0, 0, 0, 0, 10, 128,
32, 0, 0, 0, 0, 0,
12, 0, 0, 0, 0, 0,
0, 10, 242, 0, 16, 0,
1, 0, 0, 0, 70, 142,
32, 128, 65, 0, 0, 0,
0, 0, 0, 0, 13, 0,
0, 0, 70, 142, 32, 0,
0, 0, 0, 0, 14, 0,
0, 0, 50, 0, 0, 10,
242, 0, 16, 0, 1, 0,
0, 0, 166, 10, 16, 0,
0, 0, 0, 0, 70, 14,
16, 0, 1, 0, 0, 0,
70, 142, 32, 0, 0, 0,
0, 0, 13, 0, 0, 0,
56, 0, 0, 7, 66, 0,
16, 0, 0, 0, 0, 0,
26, 0, 16, 0, 0, 0,
0, 0, 10, 0, 16, 0,
0, 0, 0, 0, 56, 0,
0, 7, 242, 32, 16, 0,
0, 0, 0, 0, 166, 10,
16, 0, 0, 0, 0, 0,
70, 14, 16, 0, 1, 0,
0, 0, 18, 0, 0, 1,
32, 0, 0, 8, 66, 0,
16, 0, 0, 0, 0, 0,
26, 128, 32, 0, 0, 0,
0, 0, 16, 0, 0, 0,
1, 64, 0, 0, 1, 0,
0, 0, 31, 0, 4, 3,
42, 0, 16, 0, 0, 0,
0, 0, 56, 0, 0, 8,
194, 0, 16, 0, 0, 0,
0, 0, 246, 31, 16, 0,
1, 0, 0, 0, 6, 132,
32, 0, 0, 0, 0, 0,
7, 0, 0, 0, 50, 0,
0, 10, 194, 0, 16, 0,
0, 0, 0, 0, 6, 132,
32, 0, 0, 0, 0, 0,
6, 0, 0, 0, 166, 26,
16, 0, 1, 0, 0, 0,
166, 14, 16, 0, 0, 0,
0, 0, 0, 0, 0, 8,
194, 0, 16, 0, 0, 0,
0, 0, 166, 14, 16, 0,
0, 0, 0, 0, 6, 132,
32, 0, 0, 0, 0, 0,
8, 0, 0, 0, 14, 0,
0, 8, 194, 0, 16, 0,
0, 0, 0, 0, 166, 14,
16, 0, 0, 0, 0, 0,
6, 132, 32, 0, 0, 0,
0, 0, 10, 0, 0, 0,
69, 0, 0, 9, 242, 0,
16, 0, 1, 0, 0, 0,
230, 10, 16, 0, 0, 0,
0, 0, 70, 126, 16, 0,
0, 0, 0, 0, 0, 96,
16, 0, 0, 0, 0, 0,
32, 0, 0, 11, 194, 0,
16, 0, 0, 0, 0, 0,
6, 128, 32, 0, 0, 0,
0, 0, 16, 0, 0, 0,
2, 64, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 2, 0,
0, 0, 56, 0, 0, 7,
114, 0, 16, 0, 2, 0,
0, 0, 246, 15, 16, 0,
1, 0, 0, 0, 70, 2,
16, 0, 1, 0, 0, 0,
55, 0, 0, 9, 114, 0,
16, 0, 1, 0, 0, 0,
166, 10, 16, 0, 0, 0,
0, 0, 70, 2, 16, 0,
2, 0, 0, 0, 70, 2,
16, 0, 1, 0, 0, 0,
55, 0, 0, 9, 226, 0,
16, 0, 1, 0, 0, 0,
246, 15, 16, 0, 0, 0,
0, 0, 6, 0, 16, 0,
1, 0, 0, 0, 86, 14,
16, 0, 1, 0, 0, 0,
56, 0, 0, 8, 242, 0,
16, 0, 1, 0, 0, 0,
70, 14, 16, 0, 1, 0,
0, 0, 70, 142, 32, 0,
0, 0, 0, 0, 13, 0,
0, 0, 56, 0, 0, 7,
18, 0, 16, 0, 0, 0,
0, 0, 26, 0, 16, 0,
0, 0, 0, 0, 10, 0,
16, 0, 0, 0, 0, 0,
56, 0, 0, 7, 242, 32,
16, 0, 0, 0, 0, 0,
6, 0, 16, 0, 0, 0,
0, 0, 70, 14, 16, 0,
1, 0, 0, 0, 18, 0,
0, 1, 32, 0, 0, 8,
18, 0, 16, 0, 0, 0,
0, 0, 26, 128, 32, 0,
0, 0, 0, 0, 16, 0,
0, 0, 1, 64, 0, 0,
2, 0, 0, 0, 31, 0,
4, 3, 10, 0, 16, 0,
0, 0, 0, 0, 54, 0,
0, 8, 242, 32, 16, 0,
0, 0, 0, 0, 2, 64,
0, 0, 0, 0, 128, 63,
0, 0, 128, 63, 0, 0,
128, 63, 0, 0, 128, 63,
18, 0, 0, 1, 69, 0,
0, 9, 242, 0, 16, 0,
1, 0, 0, 0, 70, 16,
16, 0, 1, 0, 0, 0,
70, 126, 16, 0, 0, 0,
0, 0, 0, 96, 16, 0,
0, 0, 0, 0, 32, 0,
0, 11, 82, 0, 16, 0,
0, 0, 0, 0, 6, 128,
32, 0, 0, 0, 0, 0,
16, 0, 0, 0, 2, 64,
0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 2, 0,
0, 0, 0, 0, 0, 0,
56, 0, 0, 7, 114, 0,
16, 0, 2, 0, 0, 0,
246, 15, 16, 0, 1, 0,
0, 0, 70, 2, 16, 0,
1, 0, 0, 0, 55, 0,
0, 9, 114, 0, 16, 0,
1, 0, 0, 0, 6, 0,
16, 0, 0, 0, 0, 0,
70, 2, 16, 0, 2, 0,
0, 0, 70, 2, 16, 0,
1, 0, 0, 0, 55, 0,
0, 9, 226, 0, 16, 0,
1, 0, 0, 0, 166, 10,
16, 0, 0, 0, 0, 0,
6, 0, 16, 0, 1, 0,
0, 0, 86, 14, 16, 0,
1, 0, 0, 0, 56, 0,
0, 7, 242, 0, 16, 0,
0, 0, 0, 0, 86, 5,
16, 0, 0, 0, 0, 0,
70, 14, 16, 0, 1, 0,
0, 0, 56, 0, 0, 8,
242, 32, 16, 0, 0, 0,
0, 0, 70, 14, 16, 0,
0, 0, 0, 0, 70, 142,
32, 0, 0, 0, 0, 0,
13, 0, 0, 0, 21, 0,
0, 1, 21, 0, 0, 1,
21, 0, 0, 1, 62, 0,
0, 1, 83, 84, 65, 84,
116, 0, 0, 0, 64, 0,
0, 0, 3, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 42, 0, 0, 0,
4, 0, 0, 0, 0, 0,
0, 0, 5, 0, 0, 0,
2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0,
4, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
82, 68, 69, 70, 164, 2,
0, 0, 1, 0, 0, 0,
160, 0, 0, 0, 3, 0,
0, 0, 28, 0, 0, 0,
0, 4, 255, 255, 0, 1,
0, 0, 121, 2, 0, 0,
124, 0, 0, 0, 3, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0,
0, 0, 134, 0, 0, 0,
2, 0, 0, 0, 5, 0,
0, 0, 4, 0, 0, 0,
255, 255, 255, 255, 0, 0,
0, 0, 1, 0, 0, 0,
13, 0, 0, 0, 144, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0,
103, 95, 115, 97, 109, 112,
108, 101, 114, 0, 103, 95,
116, 101, 120, 116, 117, 114,
101, 0, 80, 83, 95, 67,
79, 78, 83, 84, 65, 78,
84, 83, 0, 171, 171, 171,
144, 0, 0, 0, 12, 0,
0, 0, 184, 0, 0, 0,
16, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
216, 1, 0, 0, 0, 0,
0, 0, 64, 0, 0, 0,
2, 0, 0, 0, 228, 1,
0, 0, 0, 0, 0, 0,
244, 1, 0, 0, 64, 0,
0, 0, 16, 0, 0, 0,
2, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0,
16, 2, 0, 0, 80, 0,
0, 0, 16, 0, 0, 0,
2, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0,
29, 2, 0, 0, 96, 0,
0, 0, 64, 0, 0, 0,
2, 0, 0, 0, 228, 1,
0, 0, 0, 0, 0, 0,
38, 2, 0, 0, 160, 0,
0, 0, 16, 0, 0, 0,
2, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0,
45, 2, 0, 0, 176, 0,
0, 0, 16, 0, 0, 0,
2, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0,
52, 2, 0, 0, 192, 0,
0, 0, 16, 0, 0, 0,
2, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0,
60, 2, 0, 0, 208, 0,
0, 0, 16, 0, 0, 0,
2, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0,
69, 2, 0, 0, 224, 0,
0, 0, 16, 0, 0, 0,
2, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0,
78, 2, 0, 0, 240, 0,
0, 0, 16, 0, 0, 0,
2, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0,
89, 2, 0, 0, 0, 1,
0, 0, 4, 0, 0, 0,
2, 0, 0, 0, 100, 2,
0, 0, 0, 0, 0, 0,
116, 2, 0, 0, 4, 1,
0, 0, 4, 0, 0, 0,
2, 0, 0, 0, 100, 2,
0, 0, 0, 0, 0, 0,
115, 99, 105, 115, 115, 111,
114, 77, 97, 116, 0, 171,
3, 0, 3, 0, 4, 0,
4, 0, 0, 0, 0, 0,
0, 0, 0, 0, 115, 99,
105, 115, 115, 111, 114, 69,
120, 116, 0, 171, 1, 0,
3, 0, 1, 0, 4, 0,
0, 0, 0, 0, 0, 0,
0, 0, 115, 99, 105, 115,
115, 111, 114, 83, 99, 97,
108, 101, 0, 112, 97, 105,
110, 116, 77, 97, 116, 0,
101, 120, 116, 101, 110, 116,
0, 114, 97, 100, 105, 117,
115, 0, 102, 101, 97, 116,
104, 101, 114, 0, 105, 110,
110, 101, 114, 67, 111, 108,
0, 111, 117, 116, 101, 114,
67, 111, 108, 0, 115, 116,
114, 111, 107, 101, 77, 117,
108, 116, 0, 116, 101, 120,
84, 121, 112, 101, 0, 171,
171, 171, 0, 0, 2, 0,
1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0,
116, 121, 112, 101, 0, 77,
105, 99, 114, 111, 115, 111,
102, 116, 32, 40, 82, 41,
32, 72, 76, 83, 76, 32,
83, 104, 97, 100, 101, 114,
32, 67, 111, 109, 112, 105,
108, 101, 114, 32, 49, 48,
46, 49, 0, 171, 171, 171,
73, 83, 71, 78, 104, 0,
0, 0, 3, 0, 0, 0,
8, 0, 0, 0, 80, 0,
0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 3, 0,
0, 0, 0, 0, 0, 0,
15, 0, 0, 0, 92, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 1, 0, 0, 0,
3, 3, 0, 0, 92, 0,
0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 1, 0, 0, 0,
12, 12, 0, 0, 83, 86,
95, 80, 111, 115, 105, 116,
105, 111, 110, 0, 84, 69,
88, 67, 79, 79, 82, 68,
0, 171, 171, 171, 79, 83,
71, 78, 44, 0, 0, 0,
1, 0, 0, 0, 8, 0,
0, 0, 32, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0,
0, 0, 0, 0, 15, 0,
0, 0, 83, 86, 95, 84,
65, 82, 71, 69, 84, 0,
171, 171
};
@@ -0,0 +1,290 @@
#if 0
//
// Generated by Microsoft (R) HLSL Shader Compiler 10.1
//
//
// Buffer Definitions:
//
// cbuffer VS_CONSTANTS
// {
//
// float4x4 dummy; // Offset: 0 Size: 64 [unused]
// float2 viewSize; // Offset: 64 Size: 8
//
// }
//
//
// Resource Bindings:
//
// Name Type Format Dim HLSL Bind Count
// ------------------------------ ---------- ------- ----------- -------------- ------
// VS_CONSTANTS cbuffer NA NA cb0 1
//
//
//
// Input signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// POSITION 0 xy 0 NONE float xy
// TEXCOORD 0 xy 1 NONE float xy
//
//
// Output signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_Position 0 xyzw 0 POS float xyzw
// TEXCOORD 0 xy 1 NONE float xy
// TEXCOORD 1 zw 1 NONE float zw
//
//
// Constant buffer to DX9 shader constant mappings:
//
// Target Reg Buffer Start Reg # of Regs Data Conversion
// ---------- ------- --------- --------- ----------------------
// c1 cb0 4 1 ( FLT, FLT, FLT, FLT)
//
//
// Runtime generated constant mappings:
//
// Target Reg Constant Description
// ---------- --------------------------------------------------
// c0 Vertex Shader position offset
//
//
// Level9 shader bytecode:
//
vs_2_x
def c2, -1, 1, 0, 0
dcl_texcoord v0
dcl_texcoord1 v1
rcp r0.x, c1.x
add r0.yz, v0.xxyw, v0.xxyw
mad r0.x, r0.y, r0.x, c0.x
rcp r0.w, c1.y
mad r0.y, r0.z, -r0.w, c0.y
add oPos.xy, r0, c2
mov oPos.zw, c2.xyzy
mov oT0.xy, v1
mov oT0.zw, v0.xyyx
// approximately 9 instruction slots used
vs_4_0
dcl_constantbuffer CB0[5], immediateIndexed
dcl_input v0.xy
dcl_input v1.xy
dcl_output_siv o0.xyzw, position
dcl_output o1.xy
dcl_output o1.zw
dcl_temps 1
add r0.xy, v0.xyxx, v0.xyxx
div r0.xy, r0.xyxx, cb0[4].xyxx
add o0.x, r0.x, l(-1.000000)
add o0.y, -r0.y, l(1.000000)
mov o0.zw, l(0,0,0,1.000000)
mov o1.xy, v1.xyxx
mov o1.zw, v0.xxxy
ret
// Approximately 8 instruction slots used
#endif
const BYTE g_D3D11VertexShader_Main[] =
{
68, 88, 66, 67, 115, 51,
12, 52, 39, 12, 186, 201,
117, 248, 244, 176, 24, 80,
85, 142, 1, 0, 0, 0,
148, 4, 0, 0, 6, 0,
0, 0, 56, 0, 0, 0,
48, 1, 0, 0, 92, 2,
0, 0, 216, 2, 0, 0,
208, 3, 0, 0, 36, 4,
0, 0, 65, 111, 110, 57,
240, 0, 0, 0, 240, 0,
0, 0, 0, 2, 254, 255,
188, 0, 0, 0, 52, 0,
0, 0, 1, 0, 36, 0,
0, 0, 48, 0, 0, 0,
48, 0, 0, 0, 36, 0,
1, 0, 48, 0, 0, 0,
4, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 254, 255,
81, 0, 0, 5, 2, 0,
15, 160, 0, 0, 128, 191,
0, 0, 128, 63, 0, 0,
0, 0, 0, 0, 0, 0,
31, 0, 0, 2, 5, 0,
0, 128, 0, 0, 15, 144,
31, 0, 0, 2, 5, 0,
1, 128, 1, 0, 15, 144,
6, 0, 0, 2, 0, 0,
1, 128, 1, 0, 0, 160,
2, 0, 0, 3, 0, 0,
6, 128, 0, 0, 208, 144,
0, 0, 208, 144, 4, 0,
0, 4, 0, 0, 1, 128,
0, 0, 85, 128, 0, 0,
0, 128, 0, 0, 0, 160,
6, 0, 0, 2, 0, 0,
8, 128, 1, 0, 85, 160,
4, 0, 0, 4, 0, 0,
2, 128, 0, 0, 170, 128,
0, 0, 255, 129, 0, 0,
85, 160, 2, 0, 0, 3,
0, 0, 3, 192, 0, 0,
228, 128, 2, 0, 228, 160,
1, 0, 0, 2, 0, 0,
12, 192, 2, 0, 100, 160,
1, 0, 0, 2, 0, 0,
3, 224, 1, 0, 228, 144,
1, 0, 0, 2, 0, 0,
12, 224, 0, 0, 20, 144,
255, 255, 0, 0, 83, 72,
68, 82, 36, 1, 0, 0,
64, 0, 1, 0, 73, 0,
0, 0, 89, 0, 0, 4,
70, 142, 32, 0, 0, 0,
0, 0, 5, 0, 0, 0,
95, 0, 0, 3, 50, 16,
16, 0, 0, 0, 0, 0,
95, 0, 0, 3, 50, 16,
16, 0, 1, 0, 0, 0,
103, 0, 0, 4, 242, 32,
16, 0, 0, 0, 0, 0,
1, 0, 0, 0, 101, 0,
0, 3, 50, 32, 16, 0,
1, 0, 0, 0, 101, 0,
0, 3, 194, 32, 16, 0,
1, 0, 0, 0, 104, 0,
0, 2, 1, 0, 0, 0,
0, 0, 0, 7, 50, 0,
16, 0, 0, 0, 0, 0,
70, 16, 16, 0, 0, 0,
0, 0, 70, 16, 16, 0,
0, 0, 0, 0, 14, 0,
0, 8, 50, 0, 16, 0,
0, 0, 0, 0, 70, 0,
16, 0, 0, 0, 0, 0,
70, 128, 32, 0, 0, 0,
0, 0, 4, 0, 0, 0,
0, 0, 0, 7, 18, 32,
16, 0, 0, 0, 0, 0,
10, 0, 16, 0, 0, 0,
0, 0, 1, 64, 0, 0,
0, 0, 128, 191, 0, 0,
0, 8, 34, 32, 16, 0,
0, 0, 0, 0, 26, 0,
16, 128, 65, 0, 0, 0,
0, 0, 0, 0, 1, 64,
0, 0, 0, 0, 128, 63,
54, 0, 0, 8, 194, 32,
16, 0, 0, 0, 0, 0,
2, 64, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
128, 63, 54, 0, 0, 5,
50, 32, 16, 0, 1, 0,
0, 0, 70, 16, 16, 0,
1, 0, 0, 0, 54, 0,
0, 5, 194, 32, 16, 0,
1, 0, 0, 0, 6, 20,
16, 0, 0, 0, 0, 0,
62, 0, 0, 1, 83, 84,
65, 84, 116, 0, 0, 0,
8, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0,
5, 0, 0, 0, 4, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 82, 68, 69, 70,
240, 0, 0, 0, 1, 0,
0, 0, 76, 0, 0, 0,
1, 0, 0, 0, 28, 0,
0, 0, 0, 4, 254, 255,
0, 1, 0, 0, 200, 0,
0, 0, 60, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 86, 83,
95, 67, 79, 78, 83, 84,
65, 78, 84, 83, 0, 171,
171, 171, 60, 0, 0, 0,
2, 0, 0, 0, 100, 0,
0, 0, 80, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 148, 0, 0, 0,
0, 0, 0, 0, 64, 0,
0, 0, 0, 0, 0, 0,
156, 0, 0, 0, 0, 0,
0, 0, 172, 0, 0, 0,
64, 0, 0, 0, 8, 0,
0, 0, 2, 0, 0, 0,
184, 0, 0, 0, 0, 0,
0, 0, 100, 117, 109, 109,
121, 0, 171, 171, 3, 0,
3, 0, 4, 0, 4, 0,
0, 0, 0, 0, 0, 0,
0, 0, 118, 105, 101, 119,
83, 105, 122, 101, 0, 171,
171, 171, 1, 0, 3, 0,
1, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0,
77, 105, 99, 114, 111, 115,
111, 102, 116, 32, 40, 82,
41, 32, 72, 76, 83, 76,
32, 83, 104, 97, 100, 101,
114, 32, 67, 111, 109, 112,
105, 108, 101, 114, 32, 49,
48, 46, 49, 0, 73, 83,
71, 78, 76, 0, 0, 0,
2, 0, 0, 0, 8, 0,
0, 0, 56, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0,
0, 0, 0, 0, 3, 3,
0, 0, 65, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0,
1, 0, 0, 0, 3, 3,
0, 0, 80, 79, 83, 73,
84, 73, 79, 78, 0, 84,
69, 88, 67, 79, 79, 82,
68, 0, 171, 171, 79, 83,
71, 78, 104, 0, 0, 0,
3, 0, 0, 0, 8, 0,
0, 0, 80, 0, 0, 0,
0, 0, 0, 0, 1, 0,
0, 0, 3, 0, 0, 0,
0, 0, 0, 0, 15, 0,
0, 0, 92, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0,
1, 0, 0, 0, 3, 12,
0, 0, 92, 0, 0, 0,
1, 0, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0,
1, 0, 0, 0, 12, 3,
0, 0, 83, 86, 95, 80,
111, 115, 105, 116, 105, 111,
110, 0, 84, 69, 88, 67,
79, 79, 82, 68, 0, 171,
171, 171
};
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Ollix
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,74 @@
MetalNanoVG
===========
MetalNanoVG is the native [Metal](https://developer.apple.com/metal/) port of [NanoVG](https://github.com/memononen/nanovg) that tries to get the most out of Apple's Graphics APIs.
### Donation
If you found this project useful, please consider donating to show your support ❤️
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3366Q3AVUJLTQ)
Precautions
===========
* Works only on [macOS 10.11+](https://support.apple.com/en-us/HT205073), tvOS 9.0+ and [iOS 8.0+](https://developer.apple.com/library/content/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/DeviceCompatibilityMatrix/DeviceCompatibilityMatrix.html#//apple_ref/doc/uid/TP40013599-CH17-SW1).
* Simulator support is available since iOS 13 and requires Xcode 11+ running on macOS 10.15+.
* Not all Apple hardwares are supported even if meets the OS requirement.
* [ARC](https://en.wikipedia.org/wiki/Automatic_Reference_Counting) is required.
Advantages
==========
* Shared buffers between CPU and GPU.
* Various Metal states are cached whenever possible.
* Low overheads compared to OpenGL.
* Pre-compiled shaders. (no need to compile shaders at runtime)
* Seamless integration with powerful Metal features such as [Metal Performance Shaders](https://developer.apple.com/documentation/metalperformanceshaders).
Installation
============
1. Download both `NanoVG` and `MetalNanoVG` source codes.
2. Add both `NanoVG` and `MetalNanoVG`'s `src` directories to the header search
path.
3. Add `NanoVG`'s `src/nanovg.c` and `MetalNanoVG`'s `src/nanovg_mtl.m` to
the `Compile Sources` section in Xcode.
4. Link the `Metal` and `QuartzCore` frameworks.
5. For best performance, disable *GPU Frame Capture* and *Metal API Validation* as described [here](https://developer.apple.com/library/content/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/Dev-Technique/Dev-Technique.html#//apple_ref/doc/uid/TP40014221-CH8-SW3).
Done.
Usage
=====
1. Include the headers.
```C
#include "nanovg.h"
#include "nanovg_mtl.h"
```
2. Pass the `CAMetalLayer` object when creating the NanoVG context.
```C
NVGcontext* ctx = nvgCreateMTL(metalLayer, NVG_ANTIALIAS | NVG_STENCIL_STROKES);
```
Benchmark
=========
The following table depicts a simple CPU usage benchmark of running the
NanoVG demo app on iOS devices with full Retina resolution. Both Metal and
OpenGL ES2 implementations get constant 60 FPS.
| | iPhone 6s+ | iPad Pro 12.7" (2015) |
| ---------- | ----------- | --------------------- |
| Resolution | 1080 x 1920 | 2732 * 2048 |
| Metal | 20% | 20% |
| OpenGL ES2 | 35% | 33% |
Example
=======
MetalNanoVG was originally created to improve the performance of the iOS app [Fog of World](https://fogofworld.com).
![Screenshot of Fog of World](http://media.fogofworld.com.s3.amazonaws.com/github/fogofworld_screenshot.jpg)
@@ -0,0 +1,122 @@
// Copyright (c) 2017 Ollix
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// ---
// Author: olliwang@ollix.com (Olli Wang)
#ifndef NANOVG_MTL_H_
#define NANOVG_MTL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "nanovg.h"
// Create flags
enum NVGcreateFlags {
// Flag indicating if geometry based anti-aliasing is used (may not be
// needed when using MSAA).
NVG_ANTIALIAS = 1 << 0,
// Flag indicating if strokes should be drawn using stencil buffer.
// The rendering will be a little slower, but path overlaps
// (i.e. self-intersecting or sharp turns) will be drawn just once.
NVG_STENCIL_STROKES = 1 << 1,
// Flag indicating if double buffering scheme is used.
NVG_DOUBLE_BUFFER = 1 << 12,
// Flag indicating if triple buffering scheme is used.
NVG_TRIPLE_BUFFER = 1 << 13,
// Flag indicating that additional debug checks are done.
NVG_DEBUG = 1 << 2,
};
// These are additional flags on top of NVGimageFlags.
enum NVGimageFlagsMetal {
NVG_IMAGE_NODELETE = 1 << 16, // Do not delete Metal texture handle.
};
// The possible OS targets.
enum MNVGTarget {
MNVG_IOS,
MNVG_MACOS,
MNVG_SIMULATOR,
MNVG_TVOS,
MNVG_UNKNOWN,
};
struct MNVGframebuffer {
NVGcontext* ctx;
int image;
};
typedef struct MNVGframebuffer MNVGframebuffer;
// Creates a new NanoVG context. The `metalLayer` parameter should be a
// `CAMetalLayer` object, and the `flags` should be combination of
// `NVGcreateFlags` above.
NVGcontext* nvgCreateMTL(void* metalLayer, int flags);
// Deletes the specified NanoVG context.
void nvgDeleteMTL(NVGcontext* ctx);
//
// Framebuffer
//
// Binds the specified framebuffer as the current render pass.
void mnvgBindFramebuffer(MNVGframebuffer* framebuffer);
// Creates a new framebuffer.
MNVGframebuffer* mnvgCreateFramebuffer(NVGcontext* ctx, int width,
int height, int imageFlags);
// Deletes the specified framebuffer.
void mnvgDeleteFramebuffer(MNVGframebuffer* framebuffer);
//
// Metal bridging functions
//
// Clear context on next frame, must be called before nvgEndFrame
void mnvgClearWithColor(NVGcontext* ctx, NVGcolor color);
// Returns a pointer to the corresponded `id<MTLCommandQueue>` object.
void* mnvgCommandQueue(NVGcontext* ctx);
// Creates an image id from a `id<MTLTexture>` object pointer.
int mnvgCreateImageFromHandle(NVGcontext* ctx, void* textureId, int imageFlags);
// Returns a pointer to the corresponded `id<MTLDevice>` object.
void* mnvgDevice(NVGcontext* ctx);
// Returns a pointer to the `id<MTLTexture>` object of the specified image.
void* mnvgImageHandle(NVGcontext* ctx, int image);
// Copies the pixels from the specified image into the specified `data`.
void mnvgReadPixels(NVGcontext* ctx, int image, int x, int y, int width,
int height, void* data);
// Returns the current OS target.
enum MNVGTarget mnvgTarget();
#ifdef __cplusplus
}
#endif
#endif // NANOVG_MTL_H_
@@ -0,0 +1,169 @@
// Copyright (c) 2017 Ollix
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// ---
// Author: olliwang@ollix.com (Olli Wang)
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
typedef struct {
float2 pos [[attribute(0)]];
float2 tcoord [[attribute(1)]];
} Vertex;
typedef struct {
float4 pos [[position]];
float2 fpos;
float2 ftcoord;
} RasterizerData;
typedef struct {
float3x3 scissorMat;
float3x3 paintMat;
float4 innerCol;
float4 outerCol;
float2 scissorExt;
float2 scissorScale;
float2 extent;
float radius;
float feather;
float strokeMult;
float strokeThr;
int texType;
int type;
} Uniforms;
float scissorMask(constant Uniforms& uniforms, float2 p);
float sdroundrect(constant Uniforms& uniforms, float2 pt);
float strokeMask(constant Uniforms& uniforms, float2 ftcoord);
float scissorMask(constant Uniforms& uniforms, float2 p) {
float2 sc = (abs((uniforms.scissorMat * float3(p, 1.0f)).xy)
- uniforms.scissorExt) \
* uniforms.scissorScale;
sc = saturate(float2(0.5f) - sc);
return sc.x * sc.y;
}
float sdroundrect(constant Uniforms& uniforms, float2 pt) {
float2 ext2 = uniforms.extent - float2(uniforms.radius);
float2 d = abs(pt) - ext2;
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - uniforms.radius;
}
float strokeMask(constant Uniforms& uniforms, float2 ftcoord) {
return min(1.0, (1.0 - abs(ftcoord.x * 2.0 - 1.0)) * uniforms.strokeMult) \
* min(1.0, ftcoord.y);
}
// Vertex Function
vertex RasterizerData vertexShader(Vertex vert [[stage_in]],
constant float2& viewSize [[buffer(1)]]) {
RasterizerData out;
out.ftcoord = vert.tcoord;
out.fpos = vert.pos;
out.pos = float4(2.0 * vert.pos.x / viewSize.x - 1.0,
1.0 - 2.0 * vert.pos.y / viewSize.y,
0, 1);
return out;
}
// Fragment function (No AA)
fragment float4 fragmentShader(RasterizerData in [[stage_in]],
constant Uniforms& uniforms [[buffer(0)]],
texture2d<float> texture [[texture(0)]],
sampler sampler [[sampler(0)]]) {
float scissor = scissorMask(uniforms, in.fpos);
if (scissor == 0)
return float4(0);
if (uniforms.type == 0) { // MNVG_SHADER_FILLGRAD
float2 pt = (uniforms.paintMat * float3(in.fpos, 1.0)).xy;
float d = saturate((uniforms.feather * 0.5 + sdroundrect(uniforms, pt))
/ uniforms.feather);
float4 color = mix(uniforms.innerCol, uniforms.outerCol, d);
return color * scissor;
} else if (uniforms.type == 1) { // MNVG_SHADER_FILLIMG
float2 pt = (uniforms.paintMat * float3(in.fpos, 1.0)).xy / uniforms.extent;
float4 color = texture.sample(sampler, pt);
if (uniforms.texType == 1)
color = float4(color.xyz * color.w, color.w);
else if (uniforms.texType == 2)
color = float4(color.x);
color *= scissor;
return color * uniforms.innerCol;
} else { // MNVG_SHADER_IMG
float4 color = texture.sample(sampler, in.ftcoord);
if (uniforms.texType == 1)
color = float4(color.xyz * color.w, color.w);
else if (uniforms.texType == 2)
color = float4(color.x);
color *= scissor;
return color * uniforms.innerCol;
}
}
// Fragment function (AA)
fragment float4 fragmentShaderAA(RasterizerData in [[stage_in]],
constant Uniforms& uniforms [[buffer(0)]],
texture2d<float> texture [[texture(0)]],
sampler sampler [[sampler(0)]]) {
float scissor = scissorMask(uniforms, in.fpos);
if (scissor == 0)
return float4(0);
if (uniforms.type == 2) { // MNVG_SHADER_IMG
float4 color = texture.sample(sampler, in.ftcoord);
if (uniforms.texType == 1)
color = float4(color.xyz * color.w, color.w);
else if (uniforms.texType == 2)
color = float4(color.x);
color *= scissor;
return color * uniforms.innerCol;
}
float strokeAlpha = strokeMask(uniforms, in.ftcoord);
if (strokeAlpha < uniforms.strokeThr) {
return float4(0);
}
if (uniforms.type == 0) { // MNVG_SHADER_FILLGRAD
float2 pt = (uniforms.paintMat * float3(in.fpos, 1.0)).xy;
float d = saturate((uniforms.feather * 0.5 + sdroundrect(uniforms, pt))
/ uniforms.feather);
float4 color = mix(uniforms.innerCol, uniforms.outerCol, d);
color *= scissor;
color *= strokeAlpha;
return color;
} else { // MNVG_SHADER_FILLIMG
float2 pt = (uniforms.paintMat * float3(in.fpos, 1.0)).xy / uniforms.extent;
float4 color = texture.sample(sampler, pt);
if (uniforms.texType == 1)
color = float4(color.xyz * color.w, color.w);
else if (uniforms.texType == 2)
color = float4(color.x);
color *= scissor;
color *= strokeAlpha;
return color * uniforms.innerCol;
}
}
@@ -0,0 +1,99 @@
#!/bin/bash
#
# Copyright (c) 2017 Ollix
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# ---
# Author: olliwang@ollix.com (Olli Wang)
#
# This script compiles the metal source file "nanovg_mtl_shaders.metal"
# into metallib binary data as defined in "nanovg_mtl_metallib_*.h" headers.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR/../src
result=true
PREFIX="mnvg_bitcode"
mkdir $PREFIX
execute_cmd() {
SDK=$1
TARGET=$2
SUFFIX=""
CMD="xcrun -sdk $SDK metal -c nanovg_mtl_shaders.metal"
AIR_FILE_NAME="$PREFIX/$TARGET$SUFFIX.air"
HEADER_NAME="$PREFIX/$TARGET$SUFFIX.h"
VARIABLE_NAME="$PREFIX/$TARGET$SUFFIX"
if [ $SDK = "iphoneos" ]; then
CMD="$CMD -mios-version-min=8.0"
elif [ $SDK = "macosx" ]; then
CMD="$CMD -mmacosx-version-min=10.11"
fi
CMD="$CMD -o $AIR_FILE_NAME"
eval $CMD
if [ $? -ne 0 ]; then
return 1
fi
xcrun -sdk $SDK metallib $AIR_FILE_NAME -o $VARIABLE_NAME \
> /dev/null 2>&1
xxd -i $VARIABLE_NAME > $HEADER_NAME
rm $AIR_FILE_NAME $VARIABLE_NAME
return 0
}
for SDK in "iphoneos" "iphonesimulator" "macosx" "appletvos"; do
if [ $SDK = "appletvos" ]; then
echo "* Compiling for tvOS..."
TARGET="tvos"
execute_cmd $SDK $TARGET
if [ $? -ne 0 ]; then
result=false
break
fi
else
if [ $SDK = "iphoneos" ]; then
echo "* Compiling for iOS..."
TARGET="ios"
elif [ $SDK = "iphonesimulator" ]; then
echo "* Compiling for Simulator..."
TARGET="simulator"
elif [ $SDK = "macosx" ]; then
echo "* Compiling for macOS..."
TARGET="macos"
fi
execute_cmd $SDK $TARGET
if [ $? -ne 0 ]; then
result=false
break
fi
fi
done
if $result; then
echo "Done"
fi
@@ -0,0 +1,18 @@
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.
@@ -0,0 +1,126 @@
*This project is not actively maintained.*
NanoVG
==========
NanoVG is small antialiased vector graphics rendering library for OpenGL. It has lean API modeled after HTML5 canvas API. It is aimed to be a practical and fun toolset for building scalable user interfaces and visualizations.
## Screenshot
![screenshot of some text rendered witht the sample program](/example/screenshot-01.png?raw=true)
Usage
=====
The NanoVG API is modeled loosely on HTML5 canvas API. If you know canvas, you're up to speed with NanoVG in no time.
## Creating drawing context
The drawing context is created using platform specific constructor function. If you're using the OpenGL 2.0 back-end the context is created as follows:
```C
#define NANOVG_GL2_IMPLEMENTATION // Use GL2 implementation.
#include "nanovg_gl.h"
...
struct NVGcontext* vg = nvgCreateGL2(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
```
The first parameter defines flags for creating the renderer.
- `NVG_ANTIALIAS` means that the renderer adjusts the geometry to include anti-aliasing. If you're using MSAA, you can omit this flags.
- `NVG_STENCIL_STROKES` means that the render uses better quality rendering for (overlapping) strokes. The quality is mostly visible on wider strokes. If you want speed, you can omit this flag.
Currently there is an OpenGL back-end for NanoVG: [nanovg_gl.h](/src/nanovg_gl.h) for OpenGL 2.0, OpenGL ES 2.0, OpenGL 3.2 core profile and OpenGL ES 3. The implementation can be chosen using a define as in above example. See the header file and examples for further info.
*NOTE:* The render target you're rendering to must have stencil buffer.
## Drawing shapes with NanoVG
Drawing a simple shape using NanoVG consists of four steps: 1) begin a new shape, 2) define the path to draw, 3) set fill or stroke, 4) and finally fill or stroke the path.
```C
nvgBeginPath(vg);
nvgRect(vg, 100,100, 120,30);
nvgFillColor(vg, nvgRGBA(255,192,0,255));
nvgFill(vg);
```
Calling `nvgBeginPath()` will clear any existing paths and start drawing from blank slate. There are number of number of functions to define the path to draw, such as rectangle, rounded rectangle and ellipse, or you can use the common moveTo, lineTo, bezierTo and arcTo API to compose the paths step by step.
## Understanding Composite Paths
Because of the way the rendering backend is build in NanoVG, drawing a composite path, that is path consisting from multiple paths defining holes and fills, is a bit more involved. NanoVG uses even-odd filling rule and by default the paths are wound in counter clockwise order. Keep that in mind when drawing using the low level draw API. In order to wind one of the predefined shapes as a hole, you should call `nvgPathWinding(vg, NVG_HOLE)`, or `nvgPathWinding(vg, NVG_CW)` _after_ defining the path.
``` C
nvgBeginPath(vg);
nvgRect(vg, 100,100, 120,30);
nvgCircle(vg, 120,120, 5);
nvgPathWinding(vg, NVG_HOLE); // Mark circle as a hole.
nvgFillColor(vg, nvgRGBA(255,192,0,255));
nvgFill(vg);
```
## Rendering is wrong, what to do?
- make sure you have created NanoVG context using one of the `nvgCreatexxx()` calls
- make sure you have initialised OpenGL with *stencil buffer*
- make sure you have cleared stencil buffer
- make sure all rendering calls happen between `nvgBeginFrame()` and `nvgEndFrame()`
- to enable more checks for OpenGL errors, add `NVG_DEBUG` flag to `nvgCreatexxx()`
- if the problem still persists, please report an issue!
## OpenGL state touched by the backend
The OpenGL back-end touches following states:
When textures are uploaded or updated, the following pixel store is set to defaults: `GL_UNPACK_ALIGNMENT`, `GL_UNPACK_ROW_LENGTH`, `GL_UNPACK_SKIP_PIXELS`, `GL_UNPACK_SKIP_ROWS`. Texture binding is also affected. Texture updates can happen when the user loads images, or when new font glyphs are added. Glyphs are added as needed between calls to `nvgBeginFrame()` and `nvgEndFrame()`.
The data for the whole frame is buffered and flushed in `nvgEndFrame()`. The following code illustrates the OpenGL state touched by the rendering code:
```C
glUseProgram(prog);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilMask(0xffffffff);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
glActiveTexture(GL_TEXTURE0);
glBindBuffer(GL_UNIFORM_BUFFER, buf);
glBindVertexArray(arr);
glBindBuffer(GL_ARRAY_BUFFER, buf);
glBindTexture(GL_TEXTURE_2D, tex);
glUniformBlockBinding(... , GLNVG_FRAG_BINDING);
```
## API Reference
See the header file [nanovg.h](/src/nanovg.h) for API reference.
## Ports
- [DX11 port](https://github.com/cmaughan/nanovg) by [Chris Maughan](https://github.com/cmaughan)
- [Metal port](https://github.com/ollix/MetalNanoVG) by [Olli Wang](https://github.com/olliwang)
- [bgfx port](https://github.com/bkaradzic/bgfx/tree/master/examples/20-nanovg) by [Branimir Karadžić](https://github.com/bkaradzic)
## Projects using NanoVG
- [Processing API simulation by vinjn](https://github.com/vinjn/island/blob/master/examples/01-processing/sketch2d.h)
- [NanoVG for .NET, C# P/Invoke binding](https://github.com/sbarisic/nanovg_dotnet)
## License
The library is licensed under [zlib license](LICENSE.txt)
Fonts used in examples:
- Roboto licensed under [Apache license](http://www.apache.org/licenses/LICENSE-2.0)
- Entypo licensed under CC BY-SA 4.0.
- Noto Emoji licensed under [SIL Open Font License, Version 1.1](http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL)
## Discussions
[NanoVG mailing list](https://groups.google.com/forum/#!forum/nanovg)
## Links
Uses [stb_truetype](http://nothings.org) (or, optionally, [freetype](http://freetype.org)) for font rendering.
Uses [stb_image](http://nothings.org) for image loading.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,697 @@
//
// 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
#ifdef __cplusplus
extern "C" {
#endif
#define NVG_PI 3.14159265358979323846264338327f
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union
#endif
typedef struct NVGcontext NVGcontext;
struct NVGcolor {
union {
float rgba[4];
struct {
float r,g,b,a;
};
};
};
typedef struct NVGcolor NVGcolor;
struct NVGpaint {
float xform[6];
float extent[2];
float radius;
float feather;
NVGcolor innerColor;
NVGcolor outerColor;
int image;
};
typedef struct NVGpaint NVGpaint;
enum NVGwinding {
NVG_CCW = 1, // Winding for solid shapes
NVG_CW = 2, // Winding for holes
};
enum NVGsolidity {
NVG_SOLID = 1, // CCW
NVG_HOLE = 2, // CW
};
enum NVGlineCap {
NVG_BUTT,
NVG_ROUND,
NVG_SQUARE,
NVG_BEVEL,
NVG_MITER,
};
enum NVGalign {
// Horizontal align
NVG_ALIGN_LEFT = 1<<0, // Default, align text horizontally to left.
NVG_ALIGN_CENTER = 1<<1, // Align text horizontally to center.
NVG_ALIGN_RIGHT = 1<<2, // Align text horizontally to right.
// Vertical align
NVG_ALIGN_TOP = 1<<3, // Align text vertically to top.
NVG_ALIGN_MIDDLE = 1<<4, // Align text vertically to middle.
NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom.
NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline.
};
enum NVGblendFactor {
NVG_ZERO = 1<<0,
NVG_ONE = 1<<1,
NVG_SRC_COLOR = 1<<2,
NVG_ONE_MINUS_SRC_COLOR = 1<<3,
NVG_DST_COLOR = 1<<4,
NVG_ONE_MINUS_DST_COLOR = 1<<5,
NVG_SRC_ALPHA = 1<<6,
NVG_ONE_MINUS_SRC_ALPHA = 1<<7,
NVG_DST_ALPHA = 1<<8,
NVG_ONE_MINUS_DST_ALPHA = 1<<9,
NVG_SRC_ALPHA_SATURATE = 1<<10,
};
enum NVGcompositeOperation {
NVG_SOURCE_OVER,
NVG_SOURCE_IN,
NVG_SOURCE_OUT,
NVG_ATOP,
NVG_DESTINATION_OVER,
NVG_DESTINATION_IN,
NVG_DESTINATION_OUT,
NVG_DESTINATION_ATOP,
NVG_LIGHTER,
NVG_COPY,
NVG_XOR,
};
struct NVGcompositeOperationState {
int srcRGB;
int dstRGB;
int srcAlpha;
int dstAlpha;
};
typedef struct NVGcompositeOperationState NVGcompositeOperationState;
struct NVGglyphPosition {
const char* str; // Position of the glyph in the input string.
float x; // The x-coordinate of the logical glyph position.
float minx, maxx; // The bounds of the glyph shape.
};
typedef struct NVGglyphPosition NVGglyphPosition;
struct NVGtextRow {
const char* start; // Pointer to the input text where the row starts.
const char* end; // Pointer to the input text where the row ends (one past the last character).
const char* next; // Pointer to the beginning of the next row.
float width; // Logical width of the row.
float minx, maxx; // Actual bounds of the row. Logical with and bounds can differ because of kerning and some parts over extending.
};
typedef struct NVGtextRow NVGtextRow;
enum NVGimageFlags {
NVG_IMAGE_GENERATE_MIPMAPS = 1<<0, // Generate mipmaps during creation of the image.
NVG_IMAGE_REPEATX = 1<<1, // Repeat image in X direction.
NVG_IMAGE_REPEATY = 1<<2, // Repeat image in Y direction.
NVG_IMAGE_FLIPY = 1<<3, // Flips (inverses) image in Y direction when rendered.
NVG_IMAGE_PREMULTIPLIED = 1<<4, // Image data has premultiplied alpha.
NVG_IMAGE_NEAREST = 1<<5, // Image interpolation is Nearest instead Linear
};
// 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
// devicePixelRatio to: frameBufferWidth / windowWidth.
void nvgBeginFrame(NVGcontext* ctx, float windowWidth, float windowHeight, float devicePixelRatio);
// Cancels drawing the current frame.
void nvgCancelFrame(NVGcontext* ctx);
// Ends drawing flushing remaining render state.
void nvgEndFrame(NVGcontext* ctx);
//
// Composite operation
//
// The composite operations in NanoVG are modeled after HTML Canvas API, and
// the blend func is based on OpenGL (see corresponding manuals for more info).
// The colors in the blending state have premultiplied alpha.
// Sets the composite operation. The op parameter should be one of NVGcompositeOperation.
void nvgGlobalCompositeOperation(NVGcontext* ctx, int op);
// Sets the composite operation with custom pixel arithmetic. The parameters should be one of NVGblendFactor.
void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor);
// Sets the composite operation with custom pixel arithmetic for RGB and alpha components separately. The parameters should be one of NVGblendFactor.
void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha);
//
// Color utils
//
// Colors in NanoVG are stored as unsigned ints in ABGR format.
// Returns a color value from red, green, blue values. Alpha will be set to 255 (1.0f).
NVGcolor nvgRGB(unsigned char r, unsigned char g, unsigned char b);
// Returns a color value from red, green, blue values. Alpha will be set to 1.0f.
NVGcolor nvgRGBf(float r, float g, float b);
// Returns a color value from red, green, blue and alpha values.
NVGcolor nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
// Returns a color value from red, green, blue and alpha values.
NVGcolor nvgRGBAf(float r, float g, float b, float a);
// Linearly interpolates from color c0 to c1, and returns resulting color value.
NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u);
// Sets transparency of a color value.
NVGcolor nvgTransRGBA(NVGcolor c0, unsigned char a);
// Sets transparency of a color value.
NVGcolor nvgTransRGBAf(NVGcolor c0, float a);
// Returns color value specified by hue, saturation and lightness.
// HSL values are all in range [0..1], alpha will be set to 255.
NVGcolor nvgHSL(float h, float s, float l);
// Returns color value specified by hue, saturation and lightness and alpha.
// HSL values are all in range [0..1], alpha in range [0..255]
NVGcolor nvgHSLA(float h, float s, float l, unsigned char a);
//
// 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.
// Pushes and saves the current render state into a state stack.
// A matching nvgRestore() must be used to restore the state.
void nvgSave(NVGcontext* ctx);
// Pops and restores current render state.
void nvgRestore(NVGcontext* ctx);
// Resets current render state to default values. Does not affect the render state stack.
void nvgReset(NVGcontext* ctx);
//
// 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().
// Sets whether to draw antialias for nvgStroke() and nvgFill(). It's enabled by default.
void nvgShapeAntiAlias(NVGcontext* ctx, int enabled);
// Sets current stroke style to a solid color.
void nvgStrokeColor(NVGcontext* ctx, NVGcolor color);
// Sets current stroke style to a paint, which can be a one of the gradients or a pattern.
void nvgStrokePaint(NVGcontext* ctx, NVGpaint paint);
// Sets current fill style to a solid color.
void nvgFillColor(NVGcontext* ctx, NVGcolor color);
// Sets current fill style to a paint, which can be a one of the gradients or a pattern.
void nvgFillPaint(NVGcontext* ctx, NVGpaint paint);
// Sets the miter limit of the stroke style.
// Miter limit controls when a sharp corner is beveled.
void nvgMiterLimit(NVGcontext* ctx, float limit);
// Sets the stroke width of the stroke style.
void nvgStrokeWidth(NVGcontext* ctx, float size);
// Sets how the end of the line (cap) is drawn,
// Can be one of: NVG_BUTT (default), NVG_ROUND, NVG_SQUARE.
void nvgLineCap(NVGcontext* ctx, int cap);
// Sets how sharp path corners are drawn.
// Can be one of NVG_MITER (default), NVG_ROUND, NVG_BEVEL.
void nvgLineJoin(NVGcontext* ctx, int join);
// Sets the transparency applied to all rendered shapes.
// Already transparent paths will get proportionally more transparent as well.
void nvgGlobalAlpha(NVGcontext* ctx, float alpha);
//
// 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().
// Resets current transform to a identity matrix.
void nvgResetTransform(NVGcontext* ctx);
// Premultiplies current coordinate system by specified matrix.
// The parameters are interpreted as matrix as follows:
// [a c e]
// [b d f]
// [0 0 1]
void nvgTransform(NVGcontext* ctx, float a, float b, float c, float d, float e, float f);
// Translates current coordinate system.
void nvgTranslate(NVGcontext* ctx, float x, float y);
// Rotates current coordinate system. Angle is specified in radians.
void nvgRotate(NVGcontext* ctx, float angle);
// Skews the current coordinate system along X axis. Angle is specified in radians.
void nvgSkewX(NVGcontext* ctx, float angle);
// Skews the current coordinate system along Y axis. Angle is specified in radians.
void nvgSkewY(NVGcontext* ctx, float angle);
// Scales the current coordinate system.
void nvgScale(NVGcontext* ctx, float x, float y);
// 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.
void nvgCurrentTransform(NVGcontext* ctx, float* xform);
// The following functions can be used to make calculations on 2x3 transformation matrices.
// A 2x3 matrix is represented as float[6].
// Sets the transform to identity matrix.
void nvgTransformIdentity(float* dst);
// Sets the transform to translation matrix matrix.
void nvgTransformTranslate(float* dst, float tx, float ty);
// Sets the transform to scale matrix.
void nvgTransformScale(float* dst, float sx, float sy);
// Sets the transform to rotate matrix. Angle is specified in radians.
void nvgTransformRotate(float* dst, float a);
// Sets the transform to skew-x matrix. Angle is specified in radians.
void nvgTransformSkewX(float* dst, float a);
// Sets the transform to skew-y matrix. Angle is specified in radians.
void nvgTransformSkewY(float* dst, float a);
// Sets the transform to the result of multiplication of two transforms, of A = A*B.
void nvgTransformMultiply(float* dst, const float* src);
// Sets the transform to the result of multiplication of two transforms, of A = B*A.
void nvgTransformPremultiply(float* dst, const float* src);
// Sets the destination to inverse of specified transform.
// Returns 1 if the inverse could be calculated, else 0.
int nvgTransformInverse(float* dst, const float* src);
// Transform a point by given transform.
void nvgTransformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy);
// Converts degrees to radians and vice versa.
float nvgDegToRad(float deg);
float nvgRadToDeg(float rad);
//
// 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.
// Creates image by loading it from the disk from specified file name.
// Returns handle to the image.
int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags);
// Creates image by loading it from the specified chunk of memory.
// Returns handle to the image.
int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata);
// Creates image from specified image data.
// Returns handle to the image.
int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data);
// Updates image data specified by image handle.
void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data);
// Returns the dimensions of a created image.
void nvgImageSize(NVGcontext* ctx, int image, int* w, int* h);
// Deletes created image.
void nvgDeleteImage(NVGcontext* ctx, int image);
//
// 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.
// 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().
NVGpaint nvgLinearGradient(NVGcontext* ctx, float sx, float sy, float ex, float ey,
NVGcolor icol, NVGcolor ocol);
// 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().
NVGpaint nvgBoxGradient(NVGcontext* ctx, float x, float y, float w, float h,
float r, float f, NVGcolor icol, NVGcolor ocol);
// 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().
NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float outr,
NVGcolor icol, NVGcolor ocol);
// Creates and returns an image pattern. 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().
NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey,
float angle, int image, float alpha);
//
// 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.
// Sets the current scissor rectangle.
// The scissor rectangle is transformed by the current transform.
void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h);
// 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.
void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h);
// Reset and disables scissoring.
void nvgResetScissor(NVGcontext* ctx);
//
// 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.
// Clears the current path and sub-paths.
void nvgBeginPath(NVGcontext* ctx);
// Starts new sub-path with specified point as first point.
void nvgMoveTo(NVGcontext* ctx, float x, float y);
// Adds line segment from the last point in the path to the specified point.
void nvgLineTo(NVGcontext* ctx, float x, float y);
// Adds cubic bezier segment from last point in the path via two control points to the specified point.
void nvgBezierTo(NVGcontext* ctx, float c1x, float c1y, float c2x, float c2y, float x, float y);
// Adds quadratic bezier segment from last point in the path via a control point to the specified point.
void nvgQuadTo(NVGcontext* ctx, float cx, float cy, float x, float y);
// Adds an arc segment at the corner defined by the last path point, and two specified points.
void nvgArcTo(NVGcontext* ctx, float x1, float y1, float x2, float y2, float radius);
// Closes current sub-path with a line segment.
void nvgClosePath(NVGcontext* ctx);
// Sets the current sub-path winding, see NVGwinding and NVGsolidity.
void nvgPathWinding(NVGcontext* ctx, int dir);
// 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.
void nvgArc(NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir);
// Creates new rectangle shaped sub-path.
void nvgRect(NVGcontext* ctx, float x, float y, float w, float h);
// Creates new rounded rectangle shaped sub-path.
void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r);
// Creates new rounded rectangle shaped sub-path with varying radii for each corner.
void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft);
// Creates new ellipse shaped sub-path.
void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry);
// Creates new circle shaped sub-path.
void nvgCircle(NVGcontext* ctx, float cx, float cy, float r);
// Fills the current path with current fill style.
void nvgFill(NVGcontext* ctx);
// Fills the current path with current stroke style.
void nvgStroke(NVGcontext* ctx);
//
// 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:
//
// const char* txt = "Text me up.";
// nvgTextBounds(vg, x,y, txt, NULL, bounds);
// nvgBeginPath(vg);
// nvgRoundedRect(vg, bounds[0],bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]);
// nvgFill(vg);
//
// Note: currently only solid color fill is supported for text.
// Creates font by loading it from the disk from specified file name.
// Returns handle to the font.
int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename);
// fontIndex specifies which font face to load from a .ttf/.ttc file.
int nvgCreateFontAtIndex(NVGcontext* ctx, const char* name, const char* filename, const int fontIndex);
// Creates font by loading it from the specified memory chunk.
// Returns handle to the font.
int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData);
// fontIndex specifies which font face to load from a .ttf/.ttc file.
int nvgCreateFontMemAtIndex(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData, const int fontIndex);
// Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found.
int nvgFindFont(NVGcontext* ctx, const char* name);
// Adds a fallback font by handle.
int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont);
// Adds a fallback font by name.
int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont);
// Resets fallback fonts by handle.
void nvgResetFallbackFontsId(NVGcontext* ctx, int baseFont);
// Resets fallback fonts by name.
void nvgResetFallbackFonts(NVGcontext* ctx, const char* baseFont);
// Sets the font size of current text style.
void nvgFontSize(NVGcontext* ctx, float size);
// Sets the blur of current text style.
void nvgFontBlur(NVGcontext* ctx, float blur);
// Sets the letter spacing of current text style.
void nvgTextLetterSpacing(NVGcontext* ctx, float spacing);
// Sets the proportional line height of current text style. The line height is specified as multiple of font size.
void nvgTextLineHeight(NVGcontext* ctx, float lineHeight);
// Sets the text align of current text style, see NVGalign for options.
void nvgTextAlign(NVGcontext* ctx, int align);
// Sets the font face based on specified id of current text style.
void nvgFontFaceId(NVGcontext* ctx, int font);
// Sets the font face based on specified name of current text style.
void nvgFontFace(NVGcontext* ctx, const char* font);
// Draws text string at specified location. If end is specified only the sub-string up to the end is drawn.
float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end);
// 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).
void nvgTextBox(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end);
// 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.
float nvgTextBounds(NVGcontext* ctx, float x, float y, const char* string, const char* end, float* bounds);
// 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.
void nvgTextBoxBounds(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds);
// 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.
int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string, const char* end, NVGglyphPosition* positions, int maxPositions);
// Returns the vertical metrics based on the current text style.
// Measured values are returned in local coordinate space.
void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* lineh);
// 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).
int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, float breakRowWidth, NVGtextRow* rows, int maxRows);
//
// Internal Render API
//
enum NVGtexture {
NVG_TEXTURE_ALPHA = 0x01,
NVG_TEXTURE_RGBA = 0x02,
};
struct NVGscissor {
float xform[6];
float extent[2];
};
typedef struct NVGscissor NVGscissor;
struct NVGvertex {
float x,y,u,v;
};
typedef struct NVGvertex NVGvertex;
struct NVGpath {
int first;
int count;
unsigned char closed;
int nbevel;
NVGvertex* fill;
int nfill;
NVGvertex* stroke;
int nstroke;
int winding;
int convex;
};
typedef struct NVGpath NVGpath;
struct NVGparams {
void* userPtr;
int edgeAntiAlias;
int (*renderCreate)(void* uptr);
int (*renderCreateTexture)(void* uptr, int type, int w, int h, int imageFlags, 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 (*renderViewport)(void* uptr, float width, float height, float devicePixelRatio);
void (*renderCancel)(void* uptr);
void (*renderFlush)(void* uptr);
void (*renderFill)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths);
void (*renderStroke)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths);
void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, const NVGvertex* verts, int nverts, float fringe);
void (*renderDelete)(void* uptr);
};
typedef struct NVGparams NVGparams;
// Constructor and destructor, called by the render back-end.
NVGcontext* nvgCreateInternal(NVGparams* params);
void nvgDeleteInternal(NVGcontext* ctx);
NVGparams* nvgInternalParams(NVGcontext* ctx);
// Debug function to dump cached path data.
void nvgDebugDumpPathCache(NVGcontext* ctx);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#define NVG_NOTUSED(v) for (;;) { (void)(1 ? (void)0 : ( (void)(v) ) ); break; }
#ifdef __cplusplus
}
#endif
#endif // NANOVG_H
@@ -0,0 +1,154 @@
//
// 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 NANOVG_GL_UTILS_H
#define NANOVG_GL_UTILS_H
struct NVGLUframebuffer {
NVGcontext* ctx;
GLuint fbo;
GLuint rbo;
GLuint texture;
int image;
};
typedef struct NVGLUframebuffer NVGLUframebuffer;
// Helper function to create GL frame buffer to render to.
void nvgluBindFramebuffer(NVGLUframebuffer* fb);
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags);
void nvgluDeleteFramebuffer(NVGLUframebuffer* fb);
#endif // NANOVG_GL_UTILS_H
#ifdef NANOVG_GL_IMPLEMENTATION
#if defined(NANOVG_GL3) || defined(NANOVG_GLES2) || defined(NANOVG_GLES3)
// FBO is core in OpenGL 3>.
# define NANOVG_FBO_VALID 1
#elif defined(NANOVG_GL2)
// On OS X including glext defines FBO on GL2 too.
# ifdef __APPLE__
# include <OpenGL/glext.h>
# define NANOVG_FBO_VALID 1
# endif
#endif
static GLint defaultFBO = -1;
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags)
{
#ifdef NANOVG_FBO_VALID
GLint defaultFBO;
GLint defaultRBO;
NVGLUframebuffer* fb = NULL;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
glGetIntegerv(GL_RENDERBUFFER_BINDING, &defaultRBO);
fb = (NVGLUframebuffer*)malloc(sizeof(NVGLUframebuffer));
if (fb == NULL) goto error;
memset(fb, 0, sizeof(NVGLUframebuffer));
fb->image = nvgCreateImageRGBA(ctx, w, h, imageFlags | NVG_IMAGE_FLIPY | NVG_IMAGE_PREMULTIPLIED, NULL);
#if defined NANOVG_GL2
fb->texture = nvglImageHandleGL2(ctx, fb->image);
#elif defined NANOVG_GL3
fb->texture = nvglImageHandleGL3(ctx, fb->image);
#elif defined NANOVG_GLES2
fb->texture = nvglImageHandleGLES2(ctx, fb->image);
#elif defined NANOVG_GLES3
fb->texture = nvglImageHandleGLES3(ctx, fb->image);
#endif
fb->ctx = ctx;
// frame buffer object
glGenFramebuffers(1, &fb->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fb->fbo);
// render buffer object
glGenRenderbuffers(1, &fb->rbo);
glBindRenderbuffer(GL_RENDERBUFFER, fb->rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, w, h);
// combine all
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
#ifdef GL_DEPTH24_STENCIL8
// If GL_STENCIL_INDEX8 is not supported, try GL_DEPTH24_STENCIL8 as a fallback.
// Some graphics cards require a depth buffer along with a stencil.
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
#endif // GL_DEPTH24_STENCIL8
goto error;
}
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO);
return fb;
error:
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO);
nvgluDeleteFramebuffer(fb);
return NULL;
#else
NVG_NOTUSED(ctx);
NVG_NOTUSED(w);
NVG_NOTUSED(h);
NVG_NOTUSED(imageFlags);
return NULL;
#endif
}
void nvgluBindFramebuffer(NVGLUframebuffer* fb)
{
#ifdef NANOVG_FBO_VALID
if (defaultFBO == -1) glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
glBindFramebuffer(GL_FRAMEBUFFER, fb != NULL ? fb->fbo : defaultFBO);
#else
NVG_NOTUSED(fb);
#endif
}
void nvgluDeleteFramebuffer(NVGLUframebuffer* fb)
{
#ifdef NANOVG_FBO_VALID
if (fb == NULL) return;
if (fb->fbo != 0)
glDeleteFramebuffers(1, &fb->fbo);
if (fb->rbo != 0)
glDeleteRenderbuffers(1, &fb->rbo);
if (fb->image >= 0)
nvgDeleteImage(fb->ctx, fb->image);
fb->ctx = NULL;
fb->fbo = 0;
fb->rbo = 0;
fb->texture = 0;
fb->image = -1;
free(fb);
#else
NVG_NOTUSED(fb);
#endif
}
#endif // NANOVG_GL_IMPLEMENTATION
@@ -0,0 +1,374 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
// Flags : clang-format SMTGSequencer
// Category : Examples
// Filename : public.sdk/samples/vst/dataexchange/controller.cpp
// Created by : Steinberg, 06/2023
// Description : VST Data Exchange API Example
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#include "shared.h"
#include "vstgui/lib/cexternalview.h"
#include "vstgui/lib/cvstguitimer.h"
#include "vstgui/lib/iviewlistener.h"
#include "vstgui/plugin-bindings/vst3editor.h"
#include "waveformview.h"
#include "public.sdk/source/vst/utility/dataexchange.h"
#include "public.sdk/source/vst/utility/ringbuffer.h"
#include "public.sdk/source/vst/utility/rttransfer.h"
#include "public.sdk/source/vst/vsteditcontroller.h"
#include "pluginterfaces/base/funknownimpl.h"
#include <deque>
#include <mutex>
#include <queue>
#include <string_view>
#include <thread>
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
using namespace VSTGUI;
//------------------------------------------------------------------------
struct DataExchangeController : EditController,
IDataExchangeReceiver,
VST3EditorDelegate,
ViewListenerAdapter
{
//---Interface---------
OBJ_METHODS (DataExchangeController, EditController)
DEFINE_INTERFACES
DEF_INTERFACE (IDataExchangeReceiver)
END_DEFINE_INTERFACES (EditController)
REFCOUNT_METHODS (EditController)
using Mutex = std::mutex;
using LockGuard = std::lock_guard<Mutex>;
using AudioBufferDataQueue = OneReaderOneWriter::RingBuffer<AudioBufferData>;
DataExchangeReceiverHandler dataExchange {this};
uint32 numOpenEditors {0};
std::vector<CView*> peakImageViews;
AudioBufferData currentAudioBufferData {};
uint32 currentAudioBufferCounter {0u};
std::atomic<float> pixelsPerMillisecond {1.f};
std::unique_ptr<WaveformViewManager> viewManager;
SharedPointer<CVSTGUITimer> fpsCheckTimer;
bool autoReEnableDataExchange {true};
enum
{
UITagStart = 10000,
UITagPeakLeft = 0,
UITagPeakRight,
UITagDisplayFreq,
UITagForceMessageHandling,
UITagFPSDisplay,
UITagAutoReenableDataExchange
};
std::vector<IPtr<Parameter>> uiOnlyParameters;
WaveformViewManager& getViewManager ()
{
if (!viewManager)
{
viewManager =
std::make_unique<WaveformViewManager> (SystemTime (getComponentHandler ()));
}
return *viewManager.get ();
}
tresult PLUGIN_API initialize (FUnknown* context) override
{
auto res = EditController::initialize (context);
if (res == kResultTrue)
{
parameters.addParameter (STR ("Enable Data Exchange"), STR ("On/Off"), 1, 0.,
Vst::ParameterInfo::kIsHidden, ParamIDEnableDataExchange, 0,
STR ("DataExchange"));
// UI only parameters
auto param = owned (new Parameter (STR ("PeakLeft"), UITagPeakLeft + UITagStart));
param->setPrecision (2);
uiOnlyParameters.push_back (param);
param = owned (new Parameter (STR ("PeakRight"), UITagPeakRight + UITagStart));
param->setPrecision (2);
uiOnlyParameters.push_back (param);
param = owned (new RangeParameter (STR ("Display Freq"), UITagDisplayFreq + UITagStart,
nullptr, 0.01, 10, 1.));
param->setPrecision (2);
param->setNormalized (param->toNormalized (pixelsPerMillisecond));
uiOnlyParameters.push_back (param);
auto strListParam = owned (new StringListParameter (
STR ("Force Message Handling"), UITagForceMessageHandling + UITagStart));
strListParam->appendString (STR ("Off"));
strListParam->appendString (STR ("On"));
uiOnlyParameters.push_back (strListParam);
param = owned (new RangeParameter (STR ("FPS"), UITagFPSDisplay + UITagStart, nullptr,
0, 10000, 0.));
param->setPrecision (0);
uiOnlyParameters.push_back (param);
strListParam = owned (new StringListParameter (
STR ("Auto Reenable Data Exchange"), UITagAutoReenableDataExchange + UITagStart));
strListParam->appendString (STR ("Off"));
strListParam->appendString (STR ("On"));
strListParam->setNormalized (autoReEnableDataExchange ? 1. : 0.);
uiOnlyParameters.push_back (strListParam);
}
return res;
}
tresult PLUGIN_API terminate () override
{
viewManager.reset ();
return EditController::terminate ();
}
tresult PLUGIN_API notify (IMessage* message) override
{
if (dataExchange.onMessage (message))
return kResultTrue;
return EditController::notify (message);
}
void PLUGIN_API queueOpened (DataExchangeUserContextID userContextID, uint32 blockSize,
TBool& dispatchOnBackgroundThread) override
{
dispatchOnBackgroundThread = userContextID == SampleBufferQueueID;
}
void PLUGIN_API queueClosed (DataExchangeUserContextID userContextID) override {}
void PLUGIN_API onDataExchangeBlocksReceived (DataExchangeUserContextID userContextID,
uint32 numBlocks, DataExchangeBlock* block,
TBool onBackgroundThread) override
{
if (userContextID == SampleBufferQueueID)
{
// assert (onBackgroundThread == true);
for (auto idx = 0u; idx < numBlocks; ++idx)
{
const auto& data = getSampleBufferExchangeData (block[idx]);
// n * pixel per millisecond
auto numSamplesPerPixel =
static_cast<uint32> (std::ceil (data.sampleRate / 1000 * pixelsPerMillisecond));
if (currentAudioBufferData.peak.size () < data.numChannels)
{
currentAudioBufferData.systemTime = data.systemTime;
currentAudioBufferData.sampleRate = data.sampleRate;
currentAudioBufferData.peak.resize (data.numChannels);
std::fill (currentAudioBufferData.peak.begin (),
currentAudioBufferData.peak.end (), PeakValue ());
}
uint32 sampleCounter = 0;
while (sampleCounter < data.numSamples)
{
auto numSamples =
std::min<uint32> (numSamplesPerPixel - currentAudioBufferCounter,
data.numSamples - sampleCounter);
for (auto channel = 0u; channel < data.numChannels; ++channel)
{
for (auto sampleIdx = 0u; sampleIdx < numSamples; ++sampleIdx)
{
auto sample = data.sampleData[sampleDataOffsetForChannel (
channel, data.numSamples) +
sampleCounter + sampleIdx];
if (currentAudioBufferData.peak[channel].min > sample)
currentAudioBufferData.peak[channel].min = sample;
if (currentAudioBufferData.peak[channel].max < sample)
currentAudioBufferData.peak[channel].max = sample;
}
}
sampleCounter += numSamples;
currentAudioBufferCounter += numSamples;
if (currentAudioBufferCounter >= numSamplesPerPixel)
{
getViewManager ().pushAudioBufferData (std::move (currentAudioBufferData));
currentAudioBufferData.systemTime = data.systemTime;
currentAudioBufferData.sampleRate = data.sampleRate;
currentAudioBufferData.peak.resize (data.numChannels);
std::fill (currentAudioBufferData.peak.begin (),
currentAudioBufferData.peak.end (), PeakValue ());
currentAudioBufferCounter = 0;
}
}
}
getViewManager ().renderIfNeeded ();
}
}
Parameter* getParameterObject (ParamID tag) override
{
if (tag >= UITagStart)
{
tag -= UITagStart;
if (tag <= uiOnlyParameters.size ())
return uiOnlyParameters[tag];
return nullptr;
}
return EditController::getParameterObject (tag);
}
tresult beginEdit (ParamID tag) override
{
if (tag >= UITagStart)
return kResultTrue;
return EditController::beginEdit (tag);
}
tresult performEdit (ParamID tag, ParamValue valueNormalized) override
{
if (tag >= UITagStart)
{
tag -= UITagStart;
if (tag == UITagDisplayFreq)
{
auto value = uiOnlyParameters[UITagDisplayFreq]->toPlain (valueNormalized);
pixelsPerMillisecond = static_cast<float> (value);
}
else if (tag == UITagForceMessageHandling)
{
if (auto msg = owned (allocateMessage ()))
{
msg->setMessageID (MessageIDForceMessageHandling);
if (auto attributes = msg->getAttributes ())
{
attributes->setInt (MessageKeyValue, valueNormalized > 0.5 ? 1 : 0);
sendMessage (msg);
}
}
}
else if (tag == UITagAutoReenableDataExchange)
{
autoReEnableDataExchange = valueNormalized > 0.5;
if (autoReEnableDataExchange)
enableDataExchange (true);
}
return kResultTrue;
}
return EditController::performEdit (tag, valueNormalized);
}
tresult endEdit (ParamID tag) override
{
if (tag >= UITagStart)
return kResultTrue;
return EditController::endEdit (tag);
}
void enableDataExchange (bool state)
{
beginEdit (ParamIDEnableDataExchange);
if (auto param = getParameterObject (ParamIDEnableDataExchange))
param->setNormalized (state ? 1. : 0);
performEdit (ParamIDEnableDataExchange, state ? 1. : 0.);
endEdit (ParamIDEnableDataExchange);
}
tresult PLUGIN_API setParamNormalized (ParamID tag, ParamValue value) override
{
auto result = EditController::setParamNormalized (tag, value);
if (numOpenEditors > 0 && tag == ParamIDEnableDataExchange)
{
if (autoReEnableDataExchange && value < 0.5)
enableDataExchange (true);
}
return result;
}
IPlugView* PLUGIN_API createView (const char* _name) override
{
std::string_view name (_name);
if (name == ViewType::kEditor)
{
auto* view = new VST3Editor (this, "view", "editor.uidesc");
return view;
}
return nullptr;
}
void editorAttached (EditorView* /*editor*/) override
{
if (++numOpenEditors == 1)
{
// start streaming realtime audio when an editor is open
enableDataExchange (true);
fpsCheckTimer = VSTGUI::owned (NEW CVSTGUITimer (
[this] (auto) {
auto fps = getViewManager ().getFramesPerSeconds ();
if (auto param = getParameterObject (UITagFPSDisplay + UITagStart))
{
param->setNormalized (param->toNormalized (fps));
}
},
1000));
}
}
void editorRemoved (EditorView* /*editor*/) override
{
if (--numOpenEditors == 0)
{
// stop streaming realtime audio when all editors are closed
enableDataExchange (false);
fpsCheckTimer = nullptr;
}
}
void viewWillDelete (CView* view) override
{
auto it = std::find (peakImageViews.begin (), peakImageViews.end (), view);
if (it != peakImageViews.end ())
{
view->unregisterViewListener (this);
peakImageViews.erase (it);
}
}
CView* createCustomView (UTF8StringPtr name, const UIAttributes& attributes,
const IUIDescription* description, VST3Editor* editor) override
{
if (std::string_view (name) == "PeakImageView")
{
CColor leftChannelColor = {255, 0, 0, 255};
CColor rightChannelColor = {0, 255, 0, 128};
description->getColor ("waveform.left", leftChannelColor);
description->getColor ("waveform.right", rightChannelColor);
if (auto view = getViewManager ().createNewView (leftChannelColor, rightChannelColor))
{
peakImageViews.push_back (view);
view->registerViewListener (this);
return view;
}
}
return nullptr;
}
};
//------------------------------------------------------------------------
FUnknown* createDataExchangeController (void*)
{
return static_cast<IEditController*> (new DataExchangeController);
}
//------------------------------------------------------------------------
} // Vst
} // Steinberg
@@ -0,0 +1,51 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
// Flags : clang-format SMTGSequencer
// Category : Examples
// Filename : public.sdk/samples/vst/dataexchange/factory.cpp
// Created by : Steinberg, 06/2023
// Description : VST Data Exchange API Example
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#include "shared.h"
#include "version.h" // for versioning
#include "pluginterfaces/vst/ivstaudioprocessor.h"
#include "pluginterfaces/vst/ivsteditcontroller.h"
//------------------------------------------------------------------------
#include "public.sdk/source/main/pluginfactory_constexpr.h"
#define stringPluginName "DataExchange"
BEGIN_FACTORY_DEF (stringCompanyName, stringCompanyWeb, stringCompanyEmail, 2)
DEF_CLASS (Steinberg::Vst::DataExchangeProcessorUID, //
Steinberg::PClassInfo::kManyInstances, //
kVstAudioEffectClass, //
stringPluginName, //
Steinberg::Vst::kDistributable, //
"Fx", //
FULL_VERSION_STR, //
kVstVersionString, //
Steinberg::Vst::createDataExchangeProcessor, //
nullptr)
DEF_CLASS (Steinberg::Vst::DataExchangeControllerUID, //
Steinberg::PClassInfo::kManyInstances, //
kVstComponentControllerClass, //
stringPluginName "Controller", //
0, //
"", //
FULL_VERSION_STR, //
kVstVersionString, //
Steinberg::Vst::createDataExchangeController, //
nullptr)
END_FACTORY
@@ -0,0 +1,386 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
// Flags : clang-format SMTGSequencer
// Category : Examples
// Filename : public.sdk/samples/vst/dataexchange/processor.cpp
// Created by : Steinberg, 06/2023
// Description : VST Data Exchange API Example
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#include "shared.h"
#include "public.sdk/source/vst/utility/dataexchange.h"
#include "public.sdk/source/vst/vstaudioeffect.h"
#include "pluginterfaces/base/funknownimpl.h"
#include "pluginterfaces/vst/ivstparameterchanges.h"
#include "pluginterfaces/vst/ivstprocesscontext.h"
#include <algorithm>
#include <cassert>
#include <string_view>
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
static constexpr DataExchangeBlock InvalidDataExchangeBlock = {nullptr, 0,
InvalidDataExchangeBlockID};
//------------------------------------------------------------------------
template <typename ExchangeDataT, uint32 blockAlignment = 0>
struct ExchangeDataProcessor : DataExchangeHandler
{
using Base = ExchangeDataProcessor<ExchangeDataT, blockAlignment>;
private:
DataExchangeBlock currentBlock {InvalidDataExchangeBlock};
protected:
int32 displayLatency {0};
virtual DataExchangeUserContextID getUserContextID () const = 0;
virtual uint32 getQueueBlockSize (SampleRate sampleRate) const = 0;
virtual uint32 getNumQueueBlocks () const = 0;
virtual void onNewLockedBlock () = 0;
virtual void onOpen (SampleRate sr) = 0;
public:
ExchangeDataProcessor (IAudioProcessor* processor)
: DataExchangeHandler (processor, [this] (auto& config, const auto& setup) {
onOpen (setup.sampleRate);
config.blockSize = getQueueBlockSize (setup.sampleRate);
config.numBlocks = getNumQueueBlocks ();
config.alignment = blockAlignment;
config.userContextID = getUserContextID ();
return true;
})
{
}
void setDisplayLatency (int32 latency) { displayLatency = latency; }
protected:
bool lockBlock ()
{
if (!isEnabled ())
return false;
return getCurrentData () != nullptr;
}
void freeBlock (bool send = true)
{
if (!isEnabled ())
return;
if (send)
sendCurrentBlock ();
else
discardCurrentBlock ();
currentBlock.blockID = InvalidDataExchangeBlockID;
}
ExchangeDataT* getCurrentData ()
{
auto block = getCurrentOrNewBlock ();
if (block.blockID == InvalidDataExchangeBlockID)
return nullptr;
if (currentBlock != block)
{
currentBlock = block;
onNewLockedBlock ();
}
return reinterpret_cast<ExchangeDataT*> (currentBlock.data);
}
};
//------------------------------------------------------------------------
struct AudioBlockExchangeProcessor : ExchangeDataProcessor<SampleBufferExchangeData>
{
private:
uint32 numFilled {0};
uint32 numSamplesToSend {0};
float* left {nullptr};
float* right {nullptr};
public:
using Base::Base;
uint32 calcNumSamplesToSend (SampleRate sampleRate) const
{
return static_cast<uint32> (sampleRate / 120); // 120 Hz
}
DataExchangeUserContextID getUserContextID () const override { return SampleBufferQueueID; }
void onOpen (SampleRate sampleRate) override
{
numSamplesToSend = calcNumSamplesToSend (sampleRate);
}
uint32 getQueueBlockSize (SampleRate sampleRate) const override
{
return calculateExampleDataSizeForSamples (calcNumSamplesToSend (sampleRate), 2);
}
uint32 getNumQueueBlocks () const override { return 32; }
void onNewLockedBlock () override
{
auto data = getCurrentData ();
assert (data);
*data = {}; // initialize with default
data->numSamples = numSamplesToSend;
left = &data->sampleData[0];
right = &data->sampleData[sampleDataOffsetForChannel (1, numSamplesToSend)];
numFilled = 0;
}
bool onProcess (const ProcessData& processData)
{
if (!isEnabled ())
return true;
auto data = getCurrentData ();
if (!data)
return true;
float* outputLeft = processData.outputs[0].channelBuffers32[0];
float* outputRight = processData.outputs[0].channelBuffers32[1];
auto numSamples = static_cast<uint32> (processData.numSamples);
while (numSamples > 0)
{
auto numSamplesFreeInBlock = numSamplesToSend - numFilled;
auto numSamplesToCopy = std::min<uint32> (numSamplesFreeInBlock, numSamples);
memcpy (left, outputLeft, numSamplesToCopy * sizeof (float));
memcpy (right, outputRight, numSamplesToCopy * sizeof (float));
numFilled += numSamplesToCopy;
numSamples -= numSamplesToCopy;
left += numSamplesToCopy;
right += numSamplesToCopy;
outputLeft += numSamplesToCopy;
outputRight += numSamplesToCopy;
if (numFilled == numSamplesToSend)
{
data->numChannels = 2;
data->sampleRate = processData.processContext->sampleRate;
data->systemTime = processData.processContext->systemTime;
freeBlock ();
if (!lockBlock ())
return false;
data = getCurrentData ();
if (data == nullptr)
return false;
}
}
return true;
}
};
//------------------------------------------------------------------------
struct DataExchangeProcessor : AudioEffect, IAudioPresentationLatency
{
OBJ_METHODS (DataExchangeProcessor, AudioEffect)
DEFINE_INTERFACES
DEF_INTERFACE (IAudioPresentationLatency)
END_DEFINE_INTERFACES (AudioEffect)
REFCOUNT_METHODS (AudioEffect)
//--- ---------------------------------------------------------------------
AudioBlockExchangeProcessor audioBlockProcessor {this};
bool enableDataExchange {false};
bool firstProcessCall {true};
static bool forceUseMessageHandling;
//--- ---------------------------------------------------------------------
DataExchangeProcessor ()
{
setControllerClass (DataExchangeControllerUID);
processContextRequirements.needSystemTime ();
}
//--- ---------------------------------------------------------------------
tresult PLUGIN_API initialize (FUnknown* context) override
{
auto res = AudioEffect::initialize (context);
if (res == kResultTrue)
{
addAudioInput (STR16 ("AudioInput"), Vst::SpeakerArr::kStereo);
addAudioOutput (STR16 ("AudioOutput"), Vst::SpeakerArr::kStereo);
}
return res;
}
//--- ---------------------------------------------------------------------
tresult PLUGIN_API terminate () override { return AudioEffect::terminate (); }
//--- ---------------------------------------------------------------------
tresult PLUGIN_API connect (IConnectionPoint* other) override
{
auto res = AudioEffect::connect (other);
audioBlockProcessor.onConnect (other, getHostContext ());
return res;
}
//--- ---------------------------------------------------------------------
tresult PLUGIN_API disconnect (IConnectionPoint* other) override
{
audioBlockProcessor.onDisconnect (other);
return AudioEffect::disconnect (other);
}
//--- ---------------------------------------------------------------------
tresult PLUGIN_API notify (IMessage* message) override
{
if (std::string_view (MessageIDForceMessageHandling) == message->getMessageID ())
{
if (auto attributes = message->getAttributes ())
{
int64 value;
if (attributes->getInt (MessageKeyValue, value) == kResultTrue)
{
forceUseMessageHandling = value;
}
}
}
return AudioEffect::notify (message);
}
//--- ---------------------------------------------------------------------
tresult PLUGIN_API setBusArrangements (Vst::SpeakerArrangement* inputs, int32 numIns,
Vst::SpeakerArrangement* outputs, int32 numOuts) override
{
if (numIns == numOuts && numIns == 1 && inputs[0] == outputs[0] &&
inputs[0] == SpeakerArr::kStereo)
{
return AudioEffect::setBusArrangements (inputs, numIns, outputs, numOuts);
}
return kResultFalse;
}
//--- ---------------------------------------------------------------------
tresult PLUGIN_API setAudioPresentationLatencySamples (BusDirection dir, int32 busIndex,
uint32 latencyInSamples) override
{
if (dir == BusDirections::kOutput && busIndex == 0)
{
audioBlockProcessor.setDisplayLatency (latencyInSamples);
}
return kResultTrue;
}
//--- ---------------------------------------------------------------------
tresult PLUGIN_API setActive (TBool state) override
{
if (state)
{
audioBlockProcessor.onActivate (processSetup, forceUseMessageHandling);
firstProcessCall = true;
}
else
{
audioBlockProcessor.onDeactivate ();
}
return AudioEffect::setActive (state);
}
//--- ---------------------------------------------------------------------
void processParameterChange (IParamValueQueue* queue)
{
int32 pointCount = queue->getPointCount ();
ParamID paramID = queue->getParameterId ();
if (pointCount <= 0)
return;
ParamValue value;
int32 sampleOffset;
if (queue->getPoint (pointCount - 1, sampleOffset, value) != kResultTrue)
return;
switch (paramID)
{
case ParamIDEnableDataExchange:
{
enableDataExchange = value > 0.5;
if (audioBlockProcessor.isEnabled () != enableDataExchange)
audioBlockProcessor.enable (enableDataExchange);
break;
}
}
}
//--- ---------------------------------------------------------------------
void processInputParameterChanges (IParameterChanges* changes)
{
int32 numParamsChanged = changes->getParameterCount ();
for (int32 index = 0; index < numParamsChanged; index++)
{
if (auto paramQueue = changes->getParameterData (index))
processParameterChange (paramQueue);
}
}
//--- ---------------------------------------------------------------------
void stopDataExchange (ProcessData* data)
{
audioBlockProcessor.enable (false);
if (data)
{
if (auto paramChanges = data->outputParameterChanges)
{
int32 index;
if (auto queue = paramChanges->addParameterData (ParamIDEnableDataExchange, index))
{
queue->addPoint (0, 0., index);
}
}
}
}
//--- ---------------------------------------------------------------------
tresult PLUGIN_API process (ProcessData& data) override
{
if (data.inputParameterChanges)
processInputParameterChanges (data.inputParameterChanges);
if (firstProcessCall)
{
firstProcessCall = false;
audioBlockProcessor.enable (enableDataExchange);
}
if (data.numSamples)
{
for (int32 channel = 0; channel < data.inputs[0].numChannels; channel++)
{
float* inputChannel = data.inputs[0].channelBuffers32[channel];
float* outputChannel = data.outputs[0].channelBuffers32[channel];
if (inputChannel == outputChannel)
continue;
for (auto sample = 0; sample < data.numSamples; ++sample)
{
auto inputSample = inputChannel[sample];
outputChannel[sample] = inputSample;
}
data.outputs[0].silenceFlags = data.inputs[0].silenceFlags;
}
if (enableDataExchange)
{
auto res = !audioBlockProcessor.onProcess (data);
// check overflow and stop if necessary
if (res)
stopDataExchange (&data);
}
}
return kResultTrue;
}
};
bool DataExchangeProcessor::forceUseMessageHandling = false;
//------------------------------------------------------------------------
FUnknown* createDataExchangeProcessor (void*)
{
return static_cast<IAudioProcessor*> (new DataExchangeProcessor);
}
//------------------------------------------------------------------------
} // Vst
} // Steinberg
@@ -0,0 +1,77 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
// Flags : clang-format SMTGSequencer
// Category : Examples
// Filename : public.sdk/samples/vst/dataexchange/shared.h
// Created by : Steinberg, 06/2023
// Description : VST Data Exchange API Example
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#pragma once
#include "pluginterfaces/base/funknown.h"
#include "pluginterfaces/vst/ivstdataexchange.h"
#include "pluginterfaces/vst/vsttypes.h"
#include <cassert>
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
static DECLARE_UID (DataExchangeProcessorUID, 0x2AF3DF1C, 0x93D243B3, 0xBA13E61C, 0xDCFDAC5D);
static DECLARE_UID (DataExchangeControllerUID, 0xB49E781B, 0xED8F486F, 0x85D4306E, 0x2C6207A0);
//------------------------------------------------------------------------
FUnknown* createDataExchangeProcessor (void*);
FUnknown* createDataExchangeController (void*);
//------------------------------------------------------------------------
static SMTG_CONSTEXPR ParamID ParamIDEnableDataExchange = 1;
//------------------------------------------------------------------------
static SMTG_CONSTEXPR auto MessageIDForceMessageHandling = "ForceMessageHandling";
static SMTG_CONSTEXPR auto MessageKeyValue = "Value";
//------------------------------------------------------------------------
static SMTG_CONSTEXPR DataExchangeUserContextID SampleBufferQueueID = 2;
//------------------------------------------------------------------------
struct SampleBufferExchangeData
{
int64 systemTime;
SampleRate sampleRate;
uint32 numChannels;
uint32 numSamples;
float sampleData[1]; // variable size
};
//------------------------------------------------------------------------
inline SampleBufferExchangeData& getSampleBufferExchangeData (const DataExchangeBlock& block)
{
return *reinterpret_cast<SampleBufferExchangeData*> (block.data);
}
//------------------------------------------------------------------------
inline uint32 calculateExampleDataSizeForSamples (uint32 numSamples, uint32 numChannels)
{
return sizeof (SampleBufferExchangeData) + ((sizeof (float) * numSamples) * numChannels);
}
//------------------------------------------------------------------------
inline uint32 sampleDataOffsetForChannel (uint32 channel, uint32 numSamplesInBuffer)
{
return numSamplesInBuffer * channel;
}
//------------------------------------------------------------------------
} // Vst
} // Steinberg
@@ -0,0 +1,34 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/dataexchange/source/version.h
// Created by : Steinberg, 06/2023
// Description : Versioning and copyright info for the data-exchange example plug-in
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#pragma once
#include "pluginterfaces/base/fplatform.h"
// Plain project version file generated by cmake
#include "projectversion.h"
#define stringOriginalFilename "DataExchange.vst3"
#if SMTG_PLATFORM_64
#define stringFileDescription "DataExchange VST3-SDK (64Bit)"
#else
#define stringFileDescription "DataExchange VST3-SDK"
#endif
#define stringCompanyWeb "http://www.steinberg.net"
#define stringCompanyEmail "mailto:info@steinberg.de"
#define stringCompanyName "Steinberg Media Technologies"
#define stringLegalCopyright "© 2025 Steinberg Media Technologies"
#define stringLegalTrademarks "VST is a trademark of Steinberg Media Technologies GmbH"
@@ -0,0 +1,231 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
// Flags : clang-format SMTGSequencer
// Category : Examples
// Filename : public.sdk/samples/vst/dataexchange/waveformview.cpp
// Created by : Steinberg, 06/2023
// Description : VST Data Exchange API Example
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#include "waveformview.h"
#include "vstgui/lib/cframe.h"
#include "vstgui/lib/iviewlistener.h"
#include "nanovg.h"
#include <deque>
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
using namespace VSTGUI;
//------------------------------------------------------------------------
struct ViewAndContext
{
CExternalView* view {nullptr};
NVGcontext* context {nullptr};
CColor leftColor {kRedCColor};
CColor rightColor {kGreenCColor};
WaveformViewManager::DrawCallbackToken callbackToken {};
};
//------------------------------------------------------------------------
struct WaveformViewManager::Impl : ViewListenerAdapter
{
AudioBufferDataQueue& _audioBufferDataQueue;
std::deque<AudioBufferData> _audioPeakValues {1000};
std::deque<AudioBufferData> _audioPeakFutureValues;
std::vector<ViewAndContext> views;
using Mutex = std::recursive_mutex;
using LockGuard = std::lock_guard<Mutex>;
Mutex peakValueMutex;
int64 _lastRenderTimer {-1};
FramesPerSeconds fps;
Impl (AudioBufferDataQueue& dataQueue) : _audioBufferDataQueue (dataQueue) {}
void viewWillDelete (CView* view) override
{
auto it = std::find_if (views.begin (), views.end (),
[&] (const auto& el) { return el.view == view; });
if (it == views.end ())
return;
view->unregisterViewListener (this);
releaseNanoVGContext (it->context);
views.erase (it);
}
void viewAttached (CView* view) override
{
auto it = std::find_if (views.begin (), views.end (),
[&] (const auto& el) { return el.view == view; });
if (it == views.end ())
return;
it->callbackToken = RenderThreadManager::instance ().registerDrawCallback (
[this, context = *it] () { render (context); });
}
void viewRemoved (CView* view) override
{
auto it = std::find_if (views.begin (), views.end (),
[&] (const auto& el) { return el.view == view; });
if (it == views.end ())
return;
RenderThreadManager::instance ().unregisterDrawCallback (it->callbackToken);
}
void addView (ViewAndContext&& ctx)
{
ctx.view->registerViewListener (this);
views.emplace_back (std::move (ctx));
}
void render (const ViewAndContext& view)
{
if (!preRender (view.view, view.context))
return;
LockGuard g (peakValueMutex);
auto devicePixelRatio = static_cast<float> (view.view->getFrame ()->getScaleFactor ());
auto size = view.view->getViewSize ().getSize ();
nvgBeginFrame (view.context, static_cast<float> (size.x), static_cast<float> (size.y),
devicePixelRatio);
float xAdd = static_cast<float> (size.x / _audioPeakValues.size ());
nvgStrokeWidth (view.context, xAdd);
// left channel
float x = 0.f;
float y = 0.f;
nvgStrokeColor (view.context, nvgRGBA (view.leftColor.red, view.leftColor.green,
view.leftColor.blue, view.leftColor.alpha));
nvgBeginPath (view.context);
for (auto value : _audioPeakValues)
{
if (value.peak.empty ())
continue;
y = static_cast<float> (size.y) * ((value.peak[0].min + 1.f) / 2.f);
nvgMoveTo (view.context, x, y);
y = static_cast<float> (size.y) * ((value.peak[0].max + 1.f) / 2.f);
nvgLineTo (view.context, x, y);
x += xAdd;
}
nvgStroke (view.context);
// right channel
x = 0.f;
nvgStrokeColor (view.context, nvgRGBA (view.rightColor.red, view.rightColor.green,
view.rightColor.blue, view.rightColor.alpha));
nvgBeginPath (view.context);
for (auto value : _audioPeakValues)
{
if (value.peak.size () < 2)
continue;
y = static_cast<float> (size.y) * ((value.peak[1].min + 1.f) / 2.f);
nvgMoveTo (view.context, x, y);
y = static_cast<float> (size.y) * ((value.peak[1].max + 1.f) / 2.f);
nvgLineTo (view.context, x, y);
x += xAdd;
}
nvgStroke (view.context);
nvgEndFrame (view.context);
postRender (view.view, view.context);
fps.increaseDrawCount ();
}
};
//------------------------------------------------------------------------
WaveformViewManager::WaveformViewManager (SystemTime&& systemTime)
: systemTime (std::move (systemTime))
{
impl = std::make_unique<Impl> (audioBufferDataQueue);
}
//------------------------------------------------------------------------
WaveformViewManager::WaveformViewManager (const SystemTime& systemTime) : systemTime (systemTime)
{
impl = std::make_unique<Impl> (audioBufferDataQueue);
}
//------------------------------------------------------------------------
WaveformViewManager::~WaveformViewManager () noexcept
{
}
//------------------------------------------------------------------------
auto WaveformViewManager::createNewView (CColor leftChannel, CColor rightChannel) -> CExternalView*
{
auto p = createNanoVGViewAndContext ();
if (p.first && p.second)
impl->addView ({p.first, p.second, leftChannel, rightChannel});
return p.first;
}
//------------------------------------------------------------------------
double WaveformViewManager::getFramesPerSeconds () const
{
return impl->fps.get ();
}
//------------------------------------------------------------------------
void WaveformViewManager::renderIfNeeded ()
{
if (!impl->peakValueMutex.try_lock ())
return;
auto currentTime = systemTime.get ();
bool atLeastOneValueChanged {false};
while (!impl->_audioPeakFutureValues.empty () &&
impl->_audioPeakFutureValues.front ().systemTime <= currentTime)
{
// if the queued buffer has reached the currentTime we push it into the buffer we draw
impl->_audioPeakValues.pop_front ();
impl->_audioPeakValues.push_back (std::move (impl->_audioPeakFutureValues.front ()));
impl->_audioPeakFutureValues.pop_front ();
atLeastOneValueChanged = true;
}
AudioBufferData bufferData;
while (impl->_audioBufferDataQueue.pop (bufferData))
{
if (bufferData.systemTime > currentTime)
{
// if the systemTime of the buffer is in the future of the current time
// we queue the buffer
impl->_audioPeakFutureValues.push_back (std::move (bufferData));
}
else
{
// otherwise we push the buffer into the queue that is drawn
impl->_audioPeakValues.pop_front ();
impl->_audioPeakValues.push_back (std::move (bufferData));
atLeastOneValueChanged = true;
}
}
impl->peakValueMutex.unlock ();
}
//------------------------------------------------------------------------
} // Vst
} // Steinberg
@@ -0,0 +1,232 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
// Flags : clang-format SMTGSequencer
// Category : Examples
// Filename : public.sdk/samples/vst/dataexchange/waveformview.h
// Created by : Steinberg, 06/2023
// Description : VST Data Exchange API Example
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#pragma once
#include "shared.h"
#include "vstgui/lib/ccolor.h"
#include "vstgui/lib/cexternalview.h"
#include "public.sdk/source/vst/utility/ringbuffer.h"
#include "public.sdk/source/vst/utility/systemtime.h"
#include <atomic>
#include <chrono>
#include <mutex>
#include <thread>
struct NVGcontext;
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
struct PeakValue
{
float min {0.f};
float max {0.f};
};
//------------------------------------------------------------------------
struct AudioBufferData
{
int64 systemTime;
SampleRate sampleRate;
std::vector<PeakValue> peak;
};
//------------------------------------------------------------------------
class WaveformViewManager
{
public:
using DrawCallback = std::function<void ()>;
using DrawCallbackToken = uint64;
struct IRenderThread
{
using ThreadFunc = std::function<void ()>;
virtual void start (ThreadFunc&& f) = 0;
virtual void stop () = 0;
virtual ~IRenderThread () noexcept = default;
};
WaveformViewManager (SystemTime&& systemTime);
WaveformViewManager (const SystemTime& systemTime);
~WaveformViewManager () noexcept;
VSTGUI::CExternalView* createNewView (VSTGUI::CColor leftChannel, VSTGUI::CColor rightChannel);
bool pushAudioBufferData (AudioBufferData&& data)
{
return audioBufferDataQueue.push (std::move (data));
}
void renderIfNeeded ();
double getFramesPerSeconds () const;
//------------------------------------------------------------------------
private:
using AudioBufferDataQueue = OneReaderOneWriter::RingBuffer<AudioBufferData>;
AudioBufferDataQueue audioBufferDataQueue {50u};
SystemTime systemTime;
struct Impl;
std::unique_ptr<Impl> impl;
struct GenericRenderThread : IRenderThread
{
GenericRenderThread () = default;
void start (ThreadFunc&& f) override
{
running = true;
thread = std::thread ([this, func = std::move (f)] () {
using namespace std::chrono;
using Clock = high_resolution_clock;
constexpr microseconds syncInterval (16667);
while (running)
{
auto startTime = Clock::now ();
func ();
auto stopTime = Clock::now ();
auto duration = duration_cast<microseconds> (stopTime - startTime);
if (duration < syncInterval)
std::this_thread::sleep_for (syncInterval - duration);
}
});
}
void stop () override
{
if (!thread.joinable ())
return;
running = false;
thread.join ();
}
private:
std::thread thread;
std::atomic<bool> running {false};
};
//------------------------------------------------------------------------
struct RenderThreadManager
{
static RenderThreadManager& instance ()
{
static RenderThreadManager m;
return m;
}
DrawCallbackToken registerDrawCallback (DrawCallback&& callback)
{
auto token = ++tokenIndex;
callbackMutex.lock ();
callbacks.emplace_back (token, std::move (callback));
auto callbacksSize = callbacks.size ();
callbackMutex.unlock ();
if (callbacksSize == 1)
startThread ();
return token;
}
void unregisterDrawCallback (DrawCallbackToken token)
{
callbackMutex.lock ();
auto it = std::find_if (callbacks.begin (), callbacks.end (),
[&] (const auto& el) { return el.first == token; });
if (it != callbacks.end ())
callbacks.erase (it);
auto noCallbacks = callbacks.empty ();
callbackMutex.unlock ();
if (noCallbacks)
stopThread ();
}
private:
RenderThreadManager () : thread (createRenderThread ()) {}
void startThread ()
{
using namespace std::chrono;
using Clock = high_resolution_clock;
thread.start ([this] () { renderAll (); });
}
void stopThread () { thread.stop (); }
void renderAll ()
{
LockGuard g (callbackMutex);
for (auto& dc : callbacks)
{
dc.second ();
}
}
using Mutex = std::recursive_mutex;
using LockGuard = std::lock_guard<Mutex>;
std::vector<std::pair<DrawCallbackToken, DrawCallback>> callbacks;
Mutex callbackMutex;
std::atomic<DrawCallbackToken> tokenIndex {0};
IRenderThread& thread;
};
//------------------------------------------------------------------------
static std::pair<VSTGUI::CExternalView*, NVGcontext*> createNanoVGViewAndContext ();
static void releaseNanoVGContext (NVGcontext* context);
static bool preRender (VSTGUI::CExternalView* view, NVGcontext* context);
static bool postRender (VSTGUI::CExternalView* view, NVGcontext* context);
static IRenderThread& createRenderThread ();
};
//------------------------------------------------------------------------
struct FramesPerSeconds
{
using Clock = std::chrono::steady_clock;
void reset ()
{
frameCounter = 0;
startTime = Clock::now ();
}
void increaseDrawCount () { ++frameCounter; }
double get () const
{
auto duration =
std::chrono::duration_cast<std::chrono::milliseconds> (Clock::now () - startTime)
.count ();
auto fps = (frameCounter * 1000.) / static_cast<double> (duration);
startTime = Clock::now ();
frameCounter = 0;
return fps;
}
private:
mutable std::atomic<uint32> frameCounter {0};
mutable std::chrono::time_point<Clock> startTime {Clock::now ()};
};
//------------------------------------------------------------------------
} // Vst
} // Steinberg
@@ -0,0 +1,382 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
// Flags : clang-format SMTGSequencer
// Category : Examples
// Filename : public.sdk/samples/vst/dataexchange/waveformview_direct3d.cpp
// Created by : Steinberg, 06/2023
// Description : VST Data Exchange API Example
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#include "waveformview.h"
#include "vstgui/contrib/externalview_hwnd.h"
#include "vstgui/lib/platform/win32/comptr.h"
#include "vstgui/lib/platform/win32/win32factory.h"
#include <d3d11.h>
#include <dxgi1_3.h>
#include <mutex>
#include "nanovg.h"
#define NANOVG_D3D11_IMPLEMENTATION
#include "nanovg_d3d11.h"
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
using namespace VSTGUI;
//------------------------------------------------------------------------
struct D3D11View : ExternalView::ExternalHWNDBase
{
ExternalView::HWNDWindow childWindow;
COM::Ptr<ID3D11Device> device;
COM::Ptr<ID3D11DeviceContext> context;
COM::Ptr<IDXGISwapChain> swapchain;
COM::Ptr<ID3D11RenderTargetView> render_view;
COM::Ptr<ID3D11DepthStencilView> stencil_view;
COM::Ptr<ID3D11Texture2D> stencil;
COM::Ptr<ID3D11Texture2D> buffer;
HANDLE nextFrameHandle {nullptr};
bool firstFrameRendered {false};
using Mutex = std::recursive_mutex;
using LockGuard = std::lock_guard<Mutex>;
Mutex mutex;
D3D11_VIEWPORT viewport {};
D3D11View (HINSTANCE inst) : ExternalHWNDBase (inst), childWindow (inst)
{
childWindow.create (nullptr, {0, 0, 20, 20}, container.getHWND (), 0,
WS_CHILD | WS_VISIBLE);
child = childWindow.getHWND ();
}
~D3D11View () noexcept { child = nullptr; }
bool attach (void* parent, PlatformViewType parentViewType) override
{
LockGuard g (mutex);
if (!Base::attach (parent, parentViewType))
return false;
RECT r;
GetClientRect (child, &r);
return onResize ({r.right - r.left, r.bottom - r.top});
}
bool remove () override
{
LockGuard g (mutex);
unbind ();
releaseResources ();
return Base::remove ();
}
void setViewSize (IntRect frame, IntRect visible) override
{
Base::setViewSize (frame, visible);
LockGuard g (mutex);
onResize (frame.size);
}
void releaseResources ()
{
if (nextFrameHandle)
CloseHandle (nextFrameHandle);
swapchain.reset ();
context.reset ();
device.reset ();
}
bool createResources ()
{
RECT r;
GetClientRect (child, &r);
DXGI_SWAP_CHAIN_DESC desc = {};
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.BufferDesc.Width = r.right - r.left;
desc.BufferDesc.Height = r.bottom - r.top;
desc.BufferDesc.RefreshRate.Denominator = 1;
desc.BufferDesc.RefreshRate.Numerator = 60;
desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 2;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
desc.OutputWindow = child;
desc.Windowed = TRUE;
desc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
UINT dev_flag = 0;
#if 0 // !defined(NDEBUG)
dev_flag = D3D11_CREATE_DEVICE_DEBUG;
#endif
const D3D_FEATURE_LEVEL req_levels[] = {
D3D_FEATURE_LEVEL_11_0,
};
auto hr = D3D11CreateDeviceAndSwapChain (nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr,
dev_flag, req_levels, std::size (req_levels),
D3D11_SDK_VERSION, &desc, swapchain.adoptPtr (),
device.adoptPtr (), nullptr, context.adoptPtr ());
COM::Ptr<IDXGISwapChain2> sc2;
if (swapchain->QueryInterface<IDXGISwapChain2> (sc2.adoptPtr ()) == S_OK)
{
nextFrameHandle = sc2->GetFrameLatencyWaitableObject ();
}
return SUCCEEDED (hr);
}
bool onResize (ExternalView::IntSize size)
{
unbind ();
auto hr = swapchain->ResizeBuffers (
2, static_cast<UINT> (size.width), static_cast<UINT> (size.height),
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT);
if (!SUCCEEDED (hr))
return false;
hr = swapchain->GetBuffer (0, __uuidof (ID3D11Texture2D),
reinterpret_cast<void**> (buffer.adoptPtr ()));
if (!SUCCEEDED (hr))
return false;
render_view = createRenderTargetView (buffer.get ());
stencil =
createStencilBuffer (static_cast<UINT> (size.width), static_cast<UINT> (size.height));
stencil_view = createStencilView (stencil.get ());
bind ();
viewport.Width = static_cast<FLOAT> (size.width);
viewport.Height = static_cast<FLOAT> (size.height);
viewport.MinDepth = 0;
viewport.MaxDepth = 1;
return true;
}
auto createRenderTargetView (ID3D11Texture2D* texture) const -> COM::Ptr<ID3D11RenderTargetView>
{
COM::Ptr<ID3D11RenderTargetView> render_view;
D3D11_RENDER_TARGET_VIEW_DESC view_desc;
D3D11_TEXTURE2D_DESC tex_desc;
HRESULT hr;
texture->GetDesc (&tex_desc);
view_desc.Format = tex_desc.Format;
view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
view_desc.Texture2D.MipSlice = 0;
hr = device->CreateRenderTargetView (texture, &view_desc, render_view.adoptPtr ());
if (!SUCCEEDED (hr))
return {};
return render_view;
}
auto createStencilBuffer (UINT w, UINT h) -> COM::Ptr<ID3D11Texture2D>
{
COM::Ptr<ID3D11Texture2D> stencil;
D3D11_TEXTURE2D_DESC stencil_desc;
HRESULT hr;
stencil_desc.ArraySize = 1;
stencil_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
stencil_desc.CPUAccessFlags = 0;
stencil_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
stencil_desc.Height = h;
stencil_desc.Width = w;
stencil_desc.MipLevels = 1;
stencil_desc.MiscFlags = 0;
stencil_desc.SampleDesc.Count = 1;
stencil_desc.SampleDesc.Quality = 0;
stencil_desc.Usage = D3D11_USAGE_DEFAULT;
hr = device->CreateTexture2D (&stencil_desc, nullptr, stencil.adoptPtr ());
if (!SUCCEEDED (hr))
return {};
return stencil;
}
auto createStencilView (ID3D11Texture2D* texture) -> COM::Ptr<ID3D11DepthStencilView>
{
COM::Ptr<ID3D11DepthStencilView> stencil_view;
D3D11_DEPTH_STENCIL_VIEW_DESC stencil_vdesc;
D3D11_TEXTURE2D_DESC tex_desc;
HRESULT hr;
texture->GetDesc (&tex_desc);
stencil_vdesc.Format = tex_desc.Format;
stencil_vdesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
stencil_vdesc.Flags = 0;
stencil_vdesc.Texture2D.MipSlice = 0;
hr = device->CreateDepthStencilView (texture, &stencil_vdesc, stencil_view.adoptPtr ());
if (!SUCCEEDED (hr))
return {};
return stencil_view;
}
void unbind ()
{
ID3D11RenderTargetView* targets[1] = {nullptr};
context->OMSetRenderTargets (1, targets, nullptr);
render_view.reset ();
stencil_view.reset ();
stencil.reset ();
buffer.reset ();
}
void bind ()
{
ID3D11RenderTargetView* targets[1] = {render_view.get ()};
context->OMSetRenderTargets (1, targets, stencil_view.get ());
}
bool clearBuffer (CColor c)
{
const FLOAT color[] = {1.0f / 255 * c.red, 1.0f / 255 * c.green, 1.0f / 255 * c.blue,
1.0f / 255 * c.alpha};
auto rview = render_view.get ();
auto sview = stencil_view.get ();
if (!rview || !sview)
return false;
context->ClearRenderTargetView (rview, color);
context->ClearDepthStencilView (sview, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.0f, 0);
context->OMSetRenderTargets (1, &rview, sview);
context->RSSetViewports (1, &viewport);
return true;
}
void waitForNextFrame ()
{
if (firstFrameRendered && nextFrameHandle)
{
auto hr = WaitForSingleObject (nextFrameHandle, INFINITE);
if (hr != WAIT_OBJECT_0)
{
printf ("%d", hr);
}
}
}
bool presentAndSwapBuffer ()
{
auto hr = swapchain->Present (0, 0);
firstFrameRendered = true;
return SUCCEEDED (hr);
}
void lock () { mutex.lock (); }
void unlock () { mutex.unlock (); }
};
//------------------------------------------------------------------------
struct D3D11RenderThread : WaveformViewManager::IRenderThread
{
D3D11RenderThread () = default;
static D3D11RenderThread& instance ()
{
static D3D11RenderThread thread;
return thread;
}
void start (ThreadFunc&& f) override
{
running = true;
thread = std::thread ([this, func = std::move (f)] () {
while (running)
{
func ();
std::this_thread::sleep_for (std::chrono::milliseconds (1));
}
});
}
void stop () override
{
if (!thread.joinable ())
return;
running = false;
thread.join ();
}
private:
std::thread thread;
std::atomic<bool> running {false};
};
//------------------------------------------------------------------------
std::pair<CExternalView*, NVGcontext*> WaveformViewManager::createNanoVGViewAndContext ()
{
auto instance = getPlatformFactory ().asWin32Factory ()->getInstance ();
auto d3d11View = std::make_shared<D3D11View> (instance);
if (!d3d11View->createResources ())
return {};
auto externalView = new CExternalView ({}, d3d11View);
auto context = nvgCreateD3D11 (d3d11View->device.get (), NVG_ANTIALIAS);
return {externalView, context};
}
//------------------------------------------------------------------------
void WaveformViewManager::releaseNanoVGContext (NVGcontext* context)
{
nvgDeleteD3D11 (context);
}
//------------------------------------------------------------------------
bool WaveformViewManager::preRender (VSTGUI::CExternalView* view, NVGcontext* context)
{
auto d3d11View = static_cast<D3D11View*> (view->getExternalView ());
assert (d3d11View);
d3d11View->waitForNextFrame ();
d3d11View->lock ();
if (!d3d11View->clearBuffer (kBlackCColor))
{
d3d11View->unlock ();
return false;
}
return true;
}
//------------------------------------------------------------------------
bool WaveformViewManager::postRender (VSTGUI::CExternalView* view, NVGcontext* context)
{
auto d3d11View = static_cast<D3D11View*> (view->getExternalView ());
assert (d3d11View);
d3d11View->presentAndSwapBuffer ();
d3d11View->unlock ();
return true;
}
//------------------------------------------------------------------------
auto WaveformViewManager::createRenderThread () -> IRenderThread&
{
return D3D11RenderThread::instance ();
}
//------------------------------------------------------------------------
} // Vst
} // Steinberg
@@ -0,0 +1,147 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
// Flags : clang-format SMTGSequencer
// Category : Examples
// Filename : public.sdk/samples/vst/dataexchange/waveformview_metal.mm
// Created by : Steinberg, 06/2023
// Description : VST Data Exchange API Example
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#import "shared.h"
#import "nanovg.h"
#import "nanovg_mtl.h"
#import "vstgui/contrib/externalview_metal.h"
#import "waveformview.h"
#import <CoreAudio/CoreAudio.h>
#import <mutex>
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
using namespace VSTGUI;
//------------------------------------------------------------------------
struct MetalLayerView : ExternalView::ExternalNSViewBase<NSView>
{
CAMetalLayer* metalLayer {nullptr};
MetalLayerView () : Base ([NSView new])
{
metalLayer = [CAMetalLayer new];
view.layer = metalLayer;
metalLayer.geometryFlipped = YES;
metalLayer.opaque = NO;
metalLayer.contentsGravity = kCAGravityBottomLeft;
metalLayer.device = MTLCreateSystemDefaultDevice ();
}
void setContentScaleFactor (double scaleFactor) override
{
metalLayer.contentsScale = scaleFactor;
auto size = view.bounds.size;
size.width *= scaleFactor;
size.height *= scaleFactor;
metalLayer.drawableSize = size;
}
void setViewSize (IntRect frame, IntRect visible) override
{
Base::setViewSize (frame, visible);
auto size = view.bounds.size;
size.width *= metalLayer.contentsScale;
size.height *= metalLayer.contentsScale;
metalLayer.drawableSize = size;
}
};
//------------------------------------------------------------------------
std::pair<VSTGUI::CExternalView*, NVGcontext*> WaveformViewManager::createNanoVGViewAndContext ()
{
auto metalView = std::make_shared<MetalLayerView> ();
auto externalView = new CExternalView ({}, metalView);
auto context = nvgCreateMTL (metalView->metalLayer, NVG_ANTIALIAS);
mnvgClearWithColor (context, nvgRGBA (0, 0, 0, 255));
return {externalView, context};
}
//------------------------------------------------------------------------
void WaveformViewManager::releaseNanoVGContext (NVGcontext* context)
{
nvgDeleteMTL (context);
}
//------------------------------------------------------------------------
bool WaveformViewManager::preRender (VSTGUI::CExternalView* view, NVGcontext* context)
{
mnvgClearWithColor (context, nvgRGBA (0, 0, 0, 255));
return true;
}
//------------------------------------------------------------------------
bool WaveformViewManager::postRender (VSTGUI::CExternalView* view, NVGcontext* context)
{
return true;
}
//------------------------------------------------------------------------
struct DisplayLinkRenderThread : WaveformViewManager::IRenderThread
{
static DisplayLinkRenderThread& instance ()
{
static DisplayLinkRenderThread thread;
return thread;
}
void start (ThreadFunc&& f) final
{
assert (_displayLink == nullptr);
func = std::move (f);
auto result = CVDisplayLinkCreateWithActiveCGDisplays (&_displayLink);
assert (result == kCVReturnSuccess);
result = CVDisplayLinkSetOutputCallback (_displayLink, displayLinkRender, this);
assert (result == kCVReturnSuccess);
result = CVDisplayLinkSetCurrentCGDisplay (_displayLink, CGMainDisplayID ());
assert (result == kCVReturnSuccess);
CVDisplayLinkStart (_displayLink);
}
void stop () final
{
assert (_displayLink != nullptr);
CVDisplayLinkStop (_displayLink);
CVDisplayLinkRelease (_displayLink);
_displayLink = nullptr;
}
private:
CVDisplayLinkRef _displayLink {nullptr};
ThreadFunc func;
static CVReturn displayLinkRender (CVDisplayLinkRef displayLink, const CVTimeStamp* now,
const CVTimeStamp* outputTime, CVOptionFlags flagsIn,
CVOptionFlags* flagsOut, void* displayLinkContext)
{
auto This = reinterpret_cast<DisplayLinkRenderThread*> (displayLinkContext);
This->func ();
return kCVReturnSuccess;
}
};
//------------------------------------------------------------------------
auto WaveformViewManager::createRenderThread () -> IRenderThread&
{
return DisplayLinkRenderThread::instance ();
}
//------------------------------------------------------------------------
} // Vst
} // Steinberg